blob: 6c308affbe8f07968a3e3e8eb6de1028ed07c230 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * OS/2 port by Paul Slootman
5 * VMS merge by Zoltan Arpadffy
6 *
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 * See README.txt for an overview of the Vim source code.
10 */
11
12/*
13 * os_unix.c -- code for all flavors of Unix (BSD, SYSV, SVR4, POSIX, ...)
14 * Also for OS/2, using the excellent EMX package!!!
15 * Also for BeOS and Atari MiNT.
16 *
17 * A lot of this file was originally written by Juergen Weigert and later
18 * changed beyond recognition.
19 */
20
Bram Moolenaar071d4272004-06-13 20:20:40 +000021#include "vim.h"
22
Bram Moolenaar325b7a22004-07-05 15:58:32 +000023#ifdef FEAT_MZSCHEME
24# include "if_mzsch.h"
25#endif
26
Bram 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 Moolenaar643b6142018-09-12 20:29:09 +020046#ifdef __BEOS__
Bram Moolenaar311d9822007-02-27 15:48:28 +000047# undef select
Bram Moolenaar643b6142018-09-12 20:29:09 +020048# define select beos_select
Bram Moolenaar071d4272004-06-13 20:20:40 +000049#endif
50
Bram Moolenaara2442432007-04-26 14:26:37 +000051#ifdef __CYGWIN__
Bram Moolenaar4f974752019-02-17 17:44:42 +010052# ifndef MSWIN
Bram Moolenaar0d1498e2008-06-29 12:00:49 +000053# include <cygwin/version.h>
Bram Moolenaar0f873732019-12-05 20:28:46 +010054# include <sys/cygwin.h> // for cygwin_conv_to_posix_path() and/or
55 // for cygwin_conv_path()
Bram Moolenaar693e40c2013-02-26 14:56:42 +010056# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
57# define WIN32_LEAN_AND_MEAN
58# include <windows.h>
59# include "winclip.pro"
60# endif
Bram Moolenaara2442432007-04-26 14:26:37 +000061# endif
62#endif
63
Bram Moolenaar071d4272004-06-13 20:20:40 +000064#ifdef FEAT_MOUSE_GPM
65# include <gpm.h>
Bram Moolenaar0f873732019-12-05 20:28:46 +010066// <linux/keyboard.h> contains defines conflicting with "keymap.h",
67// I just copied relevant defines here. A cleaner solution would be to put gpm
68// code into separate file and include there linux/keyboard.h
69// #include <linux/keyboard.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000070# define KG_SHIFT 0
71# define KG_CTRL 2
72# define KG_ALT 3
73# define KG_ALTGR 1
74# define KG_SHIFTL 4
75# define KG_SHIFTR 5
76# define KG_CTRLL 6
77# define KG_CTRLR 7
78# define KG_CAPSSHIFT 8
79
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010080static void gpm_close(void);
81static int gpm_open(void);
82static int mch_gpm_process(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000083#endif
84
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000085#ifdef FEAT_SYSMOUSE
86# include <sys/consio.h>
87# include <sys/fbio.h>
88
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010089static int sysmouse_open(void);
90static void sysmouse_close(void);
Bram Moolenaard99df422016-01-29 23:20:40 +010091static RETSIGTYPE sig_sysmouse SIGPROTOARG;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000092#endif
93
Bram Moolenaar071d4272004-06-13 20:20:40 +000094/*
95 * end of autoconf section. To be extended...
96 */
97
Bram Moolenaar0f873732019-12-05 20:28:46 +010098// Are the following #ifdefs still required? And why? Is that for X11?
Bram Moolenaar071d4272004-06-13 20:20:40 +000099
100#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
101# ifdef SIGWINCH
102# undef SIGWINCH
103# endif
104# ifdef TIOCGWINSZ
105# undef TIOCGWINSZ
106# endif
107#endif
108
Bram Moolenaar0f873732019-12-05 20:28:46 +0100109#if defined(SIGWINDOW) && !defined(SIGWINCH) // hpux 9.01 has it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110# define SIGWINCH SIGWINDOW
111#endif
112
113#ifdef FEAT_X11
114# include <X11/Xlib.h>
115# include <X11/Xutil.h>
116# include <X11/Xatom.h>
117# ifdef FEAT_XCLIPBOARD
118# include <X11/Intrinsic.h>
119# include <X11/Shell.h>
120# include <X11/StringDefs.h>
121static Widget xterm_Shell = (Widget)0;
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100122static void clip_update(void);
123static void xterm_update(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000124# endif
125
126# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
127Window x11_window = 0;
128# endif
129Display *x11_display = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000130#endif
131
Bram Moolenaar5c3128e2020-05-11 20:54:42 +0200132static int ignore_sigtstp = FALSE;
133
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134#ifdef FEAT_TITLE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100135static int get_x11_title(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000136
137static char_u *oldtitle = NULL;
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200138static volatile sig_atomic_t oldtitle_outdated = FALSE;
Bram Moolenaardac13472019-09-16 21:06:21 +0200139static int unix_did_set_title = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000140static char_u *oldicon = NULL;
141static int did_set_icon = FALSE;
142#endif
143
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100144static void may_core_dump(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145
Bram Moolenaar205b8862011-09-07 15:04:31 +0200146#ifdef HAVE_UNION_WAIT
147typedef union wait waitstatus;
148#else
149typedef int waitstatus;
150#endif
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200151static int WaitForChar(long msec, int *interrupted, int ignore_input);
152static int WaitForCharOrMouse(long msec, int *interrupted, int ignore_input);
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100153#if defined(__BEOS__) || defined(VMS)
Bram Moolenaarcda77642016-06-04 13:32:35 +0200154int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000155#else
Bram Moolenaarcda77642016-06-04 13:32:35 +0200156static int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157#endif
158
159#ifdef FEAT_XCLIPBOARD
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100160static int do_xterm_trace(void);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100161# define XT_TRACE_DELAY 50 // delay for xterm tracing
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162#endif
163
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100164static void handle_resize(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165
166#if defined(SIGWINCH)
Bram Moolenaard99df422016-01-29 23:20:40 +0100167static RETSIGTYPE sig_winch SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168#endif
169#if defined(SIGINT)
Bram Moolenaard99df422016-01-29 23:20:40 +0100170static RETSIGTYPE catch_sigint SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171#endif
172#if defined(SIGPWR)
Bram Moolenaard99df422016-01-29 23:20:40 +0100173static RETSIGTYPE catch_sigpwr SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174#endif
175#if defined(SIGALRM) && defined(FEAT_X11) \
176 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
177# define SET_SIG_ALARM
Bram Moolenaard99df422016-01-29 23:20:40 +0100178static RETSIGTYPE sig_alarm SIGPROTOARG;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100179// volatile because it is used in signal handler sig_alarm().
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200180static volatile sig_atomic_t sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000181#endif
Bram Moolenaard99df422016-01-29 23:20:40 +0100182static RETSIGTYPE deathtrap SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100184static void catch_int_signal(void);
185static void set_signals(void);
186static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)());
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +0200187#ifdef HAVE_SIGPROCMASK
188# define SIGSET_DECL(set) sigset_t set;
189# define BLOCK_SIGNALS(set) block_signals(set)
190# define UNBLOCK_SIGNALS(set) unblock_signals(set)
191#else
192# define SIGSET_DECL(set)
193# define BLOCK_SIGNALS(set) do { /**/ } while (0)
194# define UNBLOCK_SIGNALS(set) do { /**/ } while (0)
195#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100196static int have_wildcard(int, char_u **);
197static int have_dollars(int, char_u **);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100199static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000200
201#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000202# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000203#endif
204
Bram Moolenaar0f873732019-12-05 20:28:46 +0100205// volatile because it is used in signal handler sig_winch().
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200206static volatile sig_atomic_t do_resize = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000207static char_u *extra_shell_arg = NULL;
208static int show_shell_mess = TRUE;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100209// volatile because it is used in signal handler deathtrap().
210static volatile sig_atomic_t deadly_signal = 0; // The signal we caught
211// volatile because it is used in signal handler deathtrap().
212static volatile sig_atomic_t in_mch_delay = FALSE; // sleeping in mch_delay()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000213
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +0100214#if defined(FEAT_JOB_CHANNEL) && !defined(USE_SYSTEM)
215static int dont_check_job_ended = 0;
216#endif
217
Bram Moolenaar26e86442020-05-17 14:06:16 +0200218// Current terminal mode from mch_settmode(). Can differ from cur_tmode.
219static tmode_T mch_cur_tmode = TMODE_COOK;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220
221#ifdef USE_XSMP
222typedef struct
223{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100224 SmcConn smcconn; // The SM connection ID
225 IceConn iceconn; // The ICE connection ID
226 char *clientid; // The client ID for the current smc session
227 Bool save_yourself; // If we're in the middle of a save_yourself
228 Bool shutdown; // If we're in shutdown mode
Bram Moolenaar071d4272004-06-13 20:20:40 +0000229} xsmp_config_T;
230
231static xsmp_config_T xsmp;
232#endif
233
234#ifdef SYS_SIGLIST_DECLARED
235/*
236 * I have seen
237 * extern char *_sys_siglist[NSIG];
238 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
239 * that describe the signals. That is nearly what we want here. But
240 * autoconf does only check for sys_siglist (without the underscore), I
241 * do not want to change everything today.... jw.
Bram Moolenaar3f7d0902016-11-12 21:13:42 +0100242 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.ac.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000243 */
244#endif
245
246static struct signalinfo
247{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100248 int sig; // Signal number, eg. SIGSEGV etc
249 char *name; // Signal name (not char_u!).
250 char deadly; // Catch as a deadly signal?
Bram Moolenaar071d4272004-06-13 20:20:40 +0000251} signal_info[] =
252{
253#ifdef SIGHUP
254 {SIGHUP, "HUP", TRUE},
255#endif
256#ifdef SIGQUIT
257 {SIGQUIT, "QUIT", TRUE},
258#endif
259#ifdef SIGILL
260 {SIGILL, "ILL", TRUE},
261#endif
262#ifdef SIGTRAP
263 {SIGTRAP, "TRAP", TRUE},
264#endif
265#ifdef SIGABRT
266 {SIGABRT, "ABRT", TRUE},
267#endif
268#ifdef SIGEMT
269 {SIGEMT, "EMT", TRUE},
270#endif
271#ifdef SIGFPE
272 {SIGFPE, "FPE", TRUE},
273#endif
274#ifdef SIGBUS
275 {SIGBUS, "BUS", TRUE},
276#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100277#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100278 // MzScheme uses SEGV in its garbage collector
Bram Moolenaar071d4272004-06-13 20:20:40 +0000279 {SIGSEGV, "SEGV", TRUE},
280#endif
281#ifdef SIGSYS
282 {SIGSYS, "SYS", TRUE},
283#endif
284#ifdef SIGALRM
Bram Moolenaar0f873732019-12-05 20:28:46 +0100285 {SIGALRM, "ALRM", FALSE}, // Perl's alarm() can trigger it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000286#endif
287#ifdef SIGTERM
288 {SIGTERM, "TERM", TRUE},
289#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100290#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000291 {SIGVTALRM, "VTALRM", TRUE},
292#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000293#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100294 // MzScheme uses SIGPROF for its own needs; On Linux with profiling
295 // this makes Vim exit. WE_ARE_PROFILING is defined in Makefile.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000296 {SIGPROF, "PROF", TRUE},
297#endif
298#ifdef SIGXCPU
299 {SIGXCPU, "XCPU", TRUE},
300#endif
301#ifdef SIGXFSZ
302 {SIGXFSZ, "XFSZ", TRUE},
303#endif
304#ifdef SIGUSR1
305 {SIGUSR1, "USR1", TRUE},
306#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000307#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100308 // Used for sysmouse handling
Bram Moolenaar071d4272004-06-13 20:20:40 +0000309 {SIGUSR2, "USR2", TRUE},
310#endif
311#ifdef SIGINT
312 {SIGINT, "INT", FALSE},
313#endif
314#ifdef SIGWINCH
315 {SIGWINCH, "WINCH", FALSE},
316#endif
317#ifdef SIGTSTP
318 {SIGTSTP, "TSTP", FALSE},
319#endif
320#ifdef SIGPIPE
321 {SIGPIPE, "PIPE", FALSE},
322#endif
323 {-1, "Unknown!", FALSE}
324};
325
Bram Moolenaar25724922009-07-14 15:38:41 +0000326 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100327mch_chdir(char *path)
Bram Moolenaar25724922009-07-14 15:38:41 +0000328{
329 if (p_verbose >= 5)
330 {
331 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100332 smsg("chdir(%s)", path);
Bram Moolenaar25724922009-07-14 15:38:41 +0000333 verbose_leave();
334 }
335# ifdef VMS
336 return chdir(vms_fixfilename(path));
337# else
338 return chdir(path);
339# endif
340}
341
Bram Moolenaar0f873732019-12-05 20:28:46 +0100342// Why is NeXT excluded here (and not in os_unixx.h)?
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +0100343#if defined(ECHOE) && defined(ICANON) \
344 && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) \
345 && !defined(__NeXT__)
Bram Moolenaar4f44b882017-08-13 20:06:18 +0200346# define NEW_TTY_SYSTEM
347#endif
348
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000349/*
Bram Moolenaard23a8232018-02-10 18:45:26 +0100350 * Write s[len] to the screen (stdout).
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000351 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100353mch_write(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354{
Bram Moolenaar42335f52018-09-13 15:33:43 +0200355 vim_ignored = (int)write(1, (char *)s, len);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100356 if (p_wd) // Unix is too fast, slow down a bit more
Bram Moolenaar8fdd7212016-03-26 19:41:48 +0100357 RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000358}
359
360/*
Bram Moolenaare40b9d42019-01-27 16:55:47 +0100361 * Function passed to inchar_loop() to handle window resizing.
362 * If "check_only" is TRUE: Return whether there was a resize.
363 * If "check_only" is FALSE: Deal with the window resized.
364 */
365 static int
366resize_func(int check_only)
367{
368 if (check_only)
369 return do_resize;
370 while (do_resize)
371 handle_resize();
372 return FALSE;
373}
374
375/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000376 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377 * Get a characters from the keyboard.
378 * Return the number of characters that are available.
379 * If wtime == 0 do not wait for characters.
380 * If wtime == n wait a short time for characters.
381 * If wtime == -1 wait forever for characters.
382 */
383 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100384mch_inchar(
385 char_u *buf,
386 int maxlen,
Bram Moolenaar0f873732019-12-05 20:28:46 +0100387 long wtime, // don't use "time", MIPS cannot handle it
Bram Moolenaar05540972016-01-30 20:31:25 +0100388 int tb_change_cnt)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389{
Bram Moolenaare40b9d42019-01-27 16:55:47 +0100390 return inchar_loop(buf, maxlen, wtime, tb_change_cnt,
391 WaitForChar, resize_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392}
393
394 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100395handle_resize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000396{
397 do_resize = FALSE;
398 shell_resized();
399}
400
401/*
Bram Moolenaar40b1b542016-04-20 20:18:23 +0200402 * Return non-zero if a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000403 */
404 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100405mch_char_avail(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406{
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200407 return WaitForChar(0L, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408}
409
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200410#if defined(FEAT_TERMINAL) || defined(PROTO)
411/*
412 * Check for any pending input or messages.
413 */
414 int
415mch_check_messages(void)
416{
417 return WaitForChar(0L, NULL, TRUE);
418}
419#endif
420
Bram Moolenaar071d4272004-06-13 20:20:40 +0000421#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
422# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000423# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424# endif
425# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
426# include <sys/sysctl.h>
427# endif
428# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
429# include <sys/sysinfo.h>
430# endif
Bram Moolenaar362dc332018-03-05 21:59:37 +0100431# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100432# include <mach/mach_host.h>
433# include <mach/mach_port.h>
Bram Moolenaar988615f2018-02-27 17:58:20 +0100434# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000435
436/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000437 * Return total amount of memory available in Kbyte.
438 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000440 long_u
Bram Moolenaar05540972016-01-30 20:31:25 +0100441mch_total_mem(int special UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000442{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443 long_u mem = 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100444 long_u shiftright = 10; // how much to shift "mem" right for Kbyte
Bram Moolenaar071d4272004-06-13 20:20:40 +0000445
Bram Moolenaar362dc332018-03-05 21:59:37 +0100446# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100447 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100448 // Mac (Darwin) way of getting the amount of RAM available
Bram Moolenaar988615f2018-02-27 17:58:20 +0100449 mach_port_t host = mach_host_self();
450 kern_return_t kret;
451# ifdef HOST_VM_INFO64
452 struct vm_statistics64 vm_stat;
453 natural_t count = HOST_VM_INFO64_COUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000454
Bram Moolenaar988615f2018-02-27 17:58:20 +0100455 kret = host_statistics64(host, HOST_VM_INFO64,
456 (host_info64_t)&vm_stat, &count);
457# else
458 struct vm_statistics vm_stat;
459 natural_t count = HOST_VM_INFO_COUNT;
460
461 kret = host_statistics(host, HOST_VM_INFO,
462 (host_info_t)&vm_stat, &count);
463# endif
464 if (kret == KERN_SUCCESS)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100465 // get the amount of user memory by summing each usage
Bram Moolenaar988615f2018-02-27 17:58:20 +0100466 mem = (long_u)(vm_stat.free_count + vm_stat.active_count
467 + vm_stat.inactive_count
468# ifdef MAC_OS_X_VERSION_10_9
469 + vm_stat.compressor_page_count
470# endif
Bram Moolenaar62b7f6a2018-03-22 21:44:07 +0100471 ) * sysconf(_SC_PAGESIZE);
Bram Moolenaar988615f2018-02-27 17:58:20 +0100472 mach_port_deallocate(mach_task_self(), host);
473 }
474# endif
475
476# ifdef HAVE_SYSCTL
477 if (mem == 0)
478 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100479 // BSD way of getting the amount of RAM available.
Bram Moolenaar988615f2018-02-27 17:58:20 +0100480 int mib[2];
481 size_t len = sizeof(long_u);
482# ifdef HW_USERMEM64
483 long_u physmem;
484# else
Bram Moolenaar0f873732019-12-05 20:28:46 +0100485 // sysctl() may return 32 bit or 64 bit, accept both
Bram Moolenaar988615f2018-02-27 17:58:20 +0100486 union {
487 int_u u32;
488 long_u u64;
489 } physmem;
490# endif
491
492 mib[0] = CTL_HW;
493# ifdef HW_USERMEM64
494 mib[1] = HW_USERMEM64;
495# else
496 mib[1] = HW_USERMEM;
497# endif
498 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
499 {
500# ifdef HW_USERMEM64
501 mem = (long_u)physmem;
502# else
503 if (len == sizeof(physmem.u64))
504 mem = (long_u)physmem.u64;
505 else
506 mem = (long_u)physmem.u32;
507# endif
508 }
509 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200510# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200512# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513 if (mem == 0)
514 {
515 struct sysinfo sinfo;
516
Bram Moolenaar0f873732019-12-05 20:28:46 +0100517 // Linux way of getting amount of RAM available
Bram Moolenaar071d4272004-06-13 20:20:40 +0000518 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000519 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200520# ifdef HAVE_SYSINFO_MEM_UNIT
Bram Moolenaar0f873732019-12-05 20:28:46 +0100521 // avoid overflow as much as possible
Bram Moolenaar914572a2007-05-01 11:37:47 +0000522 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
523 {
524 sinfo.mem_unit = sinfo.mem_unit >> 1;
525 --shiftright;
526 }
527 mem = sinfo.totalram * sinfo.mem_unit;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200528# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529 mem = sinfo.totalram;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200530# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000531 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200533# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200535# ifdef HAVE_SYSCONF
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536 if (mem == 0)
537 {
538 long pagesize, pagecount;
539
Bram Moolenaar0f873732019-12-05 20:28:46 +0100540 // Solaris way of getting amount of RAM available
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541 pagesize = sysconf(_SC_PAGESIZE);
542 pagecount = sysconf(_SC_PHYS_PAGES);
543 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000544 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100545 // avoid overflow as much as possible
Bram Moolenaar914572a2007-05-01 11:37:47 +0000546 while (shiftright > 0 && (pagesize & 1) == 0)
547 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000548 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000549 --shiftright;
550 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000552 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200554# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555
Bram Moolenaar0f873732019-12-05 20:28:46 +0100556 // Return the minimum of the physical memory and the user limit, because
557 // using more than the user limit may cause Vim to be terminated.
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200558# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000559 {
560 struct rlimit rlp;
561
562 if (getrlimit(RLIMIT_DATA, &rlp) == 0
563 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200564# ifdef RLIM_INFINITY
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565 && rlp.rlim_cur != RLIM_INFINITY
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200566# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000567 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000569 {
570 mem = (long_u)rlp.rlim_cur;
571 shiftright = 10;
572 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000573 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200574# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575
576 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000577 return mem >> shiftright;
578 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579}
580#endif
581
582 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100583mch_delay(long msec, int ignoreinput)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584{
Bram Moolenaar26e86442020-05-17 14:06:16 +0200585 tmode_T old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000586#ifdef FEAT_MZSCHEME
Bram Moolenaar0f873732019-12-05 20:28:46 +0100587 long total = msec; // remember original value
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000588#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000589
590 if (ignoreinput)
591 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100592 // Go to cooked mode without echo, to allow SIGINT interrupting us
593 // here. But we don't want QUIT to kill us (CTRL-\ used in a
594 // shell may produce SIGQUIT).
Bram Moolenaar26e86442020-05-17 14:06:16 +0200595 // Only do this if sleeping for more than half a second.
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000596 in_mch_delay = TRUE;
Bram Moolenaar26e86442020-05-17 14:06:16 +0200597 old_tmode = mch_cur_tmode;
598 if (mch_cur_tmode == TMODE_RAW && msec > 500)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000599 settmode(TMODE_SLEEP);
600
601 /*
602 * Everybody sleeps in a different way...
603 * Prefer nanosleep(), some versions of usleep() can only sleep up to
604 * one second.
605 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000606#ifdef FEAT_MZSCHEME
607 do
608 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100609 // if total is large enough, wait by portions in p_mzq
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000610 if (total > p_mzq)
611 msec = p_mzq;
612 else
613 msec = total;
614 total -= msec;
615#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000616#ifdef HAVE_NANOSLEEP
617 {
618 struct timespec ts;
619
620 ts.tv_sec = msec / 1000;
621 ts.tv_nsec = (msec % 1000) * 1000000;
622 (void)nanosleep(&ts, NULL);
623 }
624#else
625# ifdef HAVE_USLEEP
626 while (msec >= 1000)
627 {
628 usleep((unsigned int)(999 * 1000));
629 msec -= 999;
630 }
631 usleep((unsigned int)(msec * 1000));
632# else
633# ifndef HAVE_SELECT
634 poll(NULL, 0, (int)msec);
635# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000636 {
637 struct timeval tv;
638
639 tv.tv_sec = msec / 1000;
640 tv.tv_usec = (msec % 1000) * 1000;
641 /*
642 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
643 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
644 */
645 select(0, NULL, NULL, NULL, &tv);
646 }
Bram Moolenaar0f873732019-12-05 20:28:46 +0100647# endif // HAVE_SELECT
648# endif // HAVE_NANOSLEEP
649#endif // HAVE_USLEEP
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000650#ifdef FEAT_MZSCHEME
651 }
652 while (total > 0);
653#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654
Bram Moolenaar26e86442020-05-17 14:06:16 +0200655 if (msec > 500)
656 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000657 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000658 }
659 else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200660 WaitForChar(msec, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661}
662
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000663#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000664 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
665# define HAVE_CHECK_STACK_GROWTH
666/*
667 * Support for checking for an almost-out-of-stack-space situation.
668 */
669
670/*
671 * Return a pointer to an item on the stack. Used to find out if the stack
672 * grows up or down.
673 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000674static int stack_grows_downwards;
675
676/*
677 * Find out if the stack grows upwards or downwards.
678 * "p" points to a variable on the stack of the caller.
679 */
680 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100681check_stack_growth(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000682{
683 int i;
684
685 stack_grows_downwards = (p > (char *)&i);
686}
687#endif
688
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000689#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000690static char *stack_limit = NULL;
691
692#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
693# include <pthread.h>
694# include <pthread_np.h>
695#endif
696
697/*
698 * Find out until how var the stack can grow without getting into trouble.
699 * Called when starting up and when switching to the signal stack in
700 * deathtrap().
701 */
702 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100703get_stack_limit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704{
705 struct rlimit rlp;
706 int i;
707 long lim;
708
Bram Moolenaar0f873732019-12-05 20:28:46 +0100709 // Set the stack limit to 15/16 of the allowable size. Skip this when the
710 // limit doesn't fit in a long (rlim_cur might be "long long").
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711 if (getrlimit(RLIMIT_STACK, &rlp) == 0
712 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
713# ifdef RLIM_INFINITY
714 && rlp.rlim_cur != RLIM_INFINITY
715# endif
716 )
717 {
718 lim = (long)rlp.rlim_cur;
719#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
720 {
721 pthread_attr_t attr;
722 size_t size;
723
Bram Moolenaar0f873732019-12-05 20:28:46 +0100724 // On FreeBSD the initial thread always has a fixed stack size, no
725 // matter what the limits are set to. Normally it's 1 Mbyte.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726 pthread_attr_init(&attr);
727 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
728 {
729 pthread_attr_getstacksize(&attr, &size);
730 if (lim > (long)size)
731 lim = (long)size;
732 }
733 pthread_attr_destroy(&attr);
734 }
735#endif
736 if (stack_grows_downwards)
737 {
738 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
739 if (stack_limit >= (char *)&i)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100740 // overflow, set to 1/16 of current stack position
Bram Moolenaar071d4272004-06-13 20:20:40 +0000741 stack_limit = (char *)((long)&i / 16L);
742 }
743 else
744 {
745 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
746 if (stack_limit <= (char *)&i)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100747 stack_limit = NULL; // overflow
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 }
749 }
750}
751
752/*
753 * Return FAIL when running out of stack space.
754 * "p" must point to any variable local to the caller that's on the stack.
755 */
756 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100757mch_stackcheck(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758{
759 if (stack_limit != NULL)
760 {
761 if (stack_grows_downwards)
762 {
763 if (p < stack_limit)
764 return FAIL;
765 }
766 else if (p > stack_limit)
767 return FAIL;
768 }
769 return OK;
770}
771#endif
772
773#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
774/*
775 * Support for using the signal stack.
776 * This helps when we run out of stack space, which causes a SIGSEGV. The
777 * signal handler then must run on another stack, since the normal stack is
778 * completely full.
779 */
780
781#ifndef SIGSTKSZ
Bram Moolenaar0f873732019-12-05 20:28:46 +0100782# define SIGSTKSZ 8000 // just a guess of how much stack is needed...
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783#endif
784
785# ifdef HAVE_SIGALTSTACK
Bram Moolenaar0f873732019-12-05 20:28:46 +0100786static stack_t sigstk; // for sigaltstack()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787# else
Bram Moolenaar0f873732019-12-05 20:28:46 +0100788static struct sigstack sigstk; // for sigstack()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789# endif
790
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791static char *signal_stack;
792
793 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100794init_signal_stack(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000795{
796 if (signal_stack != NULL)
797 {
798# ifdef HAVE_SIGALTSTACK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000799# ifdef HAVE_SS_BASE
800 sigstk.ss_base = signal_stack;
801# else
802 sigstk.ss_sp = signal_stack;
803# endif
804 sigstk.ss_size = SIGSTKSZ;
805 sigstk.ss_flags = 0;
806 (void)sigaltstack(&sigstk, NULL);
807# else
808 sigstk.ss_sp = signal_stack;
809 if (stack_grows_downwards)
810 sigstk.ss_sp += SIGSTKSZ - 1;
811 sigstk.ss_onstack = 0;
812 (void)sigstack(&sigstk, NULL);
813# endif
814 }
815}
816#endif
817
818/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000819 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820 * will barf when the second argument to signal() is ``wrong''.
821 * Let me try it with a few tricky defines from my own osdef.h (jw).
822 */
823#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000824 static RETSIGTYPE
825sig_winch SIGDEFARG(sigarg)
826{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100827 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaar071d4272004-06-13 20:20:40 +0000828 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
829 do_resize = TRUE;
830 SIGRETURN;
831}
832#endif
833
834#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 static RETSIGTYPE
836catch_sigint SIGDEFARG(sigarg)
837{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100838 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaar071d4272004-06-13 20:20:40 +0000839 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
840 got_int = TRUE;
841 SIGRETURN;
842}
843#endif
844
845#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 static RETSIGTYPE
847catch_sigpwr SIGDEFARG(sigarg)
848{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100849 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000850 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000851 /*
852 * I'm not sure we get the SIGPWR signal when the system is really going
853 * down or when the batteries are almost empty. Just preserve the swap
854 * files and don't exit, that can't do any harm.
855 */
856 ml_sync_all(FALSE, FALSE);
857 SIGRETURN;
858}
859#endif
860
861#ifdef SET_SIG_ALARM
862/*
863 * signal function for alarm().
864 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 static RETSIGTYPE
866sig_alarm SIGDEFARG(sigarg)
867{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100868 // doesn't do anything, just to break a system call
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 sig_alarm_called = TRUE;
870 SIGRETURN;
871}
872#endif
873
Bram Moolenaaredce7422019-01-20 18:39:30 +0100874#if (defined(HAVE_SETJMP_H) \
875 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
876 || defined(FEAT_LIBCALL))) \
877 || defined(PROTO)
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100878# define USING_SETJMP 1
Bram Moolenaaredce7422019-01-20 18:39:30 +0100879
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100880// argument to SETJMP()
881static JMP_BUF lc_jump_env;
882
883# ifdef SIGHASARG
Bram Moolenaar32aa1022019-11-02 22:54:41 +0100884// Caught signal number, 0 when no signal was caught; used for mch_libcall().
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100885// Volatile because it is used in signal handlers.
886static volatile sig_atomic_t lc_signal;
887# endif
888
889// TRUE when lc_jump_env is valid.
890// Volatile because it is used in signal handler deathtrap().
891static volatile sig_atomic_t lc_active INIT(= FALSE);
892
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893/*
894 * A simplistic version of setjmp() that only allows one level of using.
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100895 * Used to protect areas where we could crash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 * Don't call twice before calling mch_endjmp()!.
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100897 *
Bram Moolenaar071d4272004-06-13 20:20:40 +0000898 * Usage:
899 * mch_startjmp();
900 * if (SETJMP(lc_jump_env) != 0)
901 * {
902 * mch_didjmp();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100903 * emsg("crash!");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000904 * }
905 * else
906 * {
907 * do_the_work;
908 * mch_endjmp();
909 * }
910 * Note: Can't move SETJMP() here, because a function calling setjmp() must
911 * not return before the saved environment is used.
912 * Returns OK for normal return, FAIL when the protected code caused a
913 * problem and LONGJMP() was used.
914 */
Bram Moolenaar113e1072019-01-20 15:30:40 +0100915 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100916mch_startjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917{
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100918# ifdef SIGHASARG
Bram Moolenaar071d4272004-06-13 20:20:40 +0000919 lc_signal = 0;
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100920# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000921 lc_active = TRUE;
922}
923
Bram Moolenaar113e1072019-01-20 15:30:40 +0100924 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100925mch_endjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000926{
927 lc_active = FALSE;
928}
929
Bram Moolenaar113e1072019-01-20 15:30:40 +0100930 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100931mch_didjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000932{
933# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100934 // On FreeBSD the signal stack has to be reset after using siglongjmp(),
935 // otherwise catching the signal only works once.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000936 init_signal_stack();
937# endif
938}
939#endif
940
941/*
942 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200943 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000944 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200945 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
946 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000947 */
948 static RETSIGTYPE
949deathtrap SIGDEFARG(sigarg)
950{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100951 static int entered = 0; // count the number of times we got here.
952 // Note: when memory has been corrupted
953 // this may get an arbitrary value!
Bram Moolenaar071d4272004-06-13 20:20:40 +0000954#ifdef SIGHASARG
955 int i;
956#endif
957
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100958#if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000959 /*
960 * Catch a crash in protected code.
961 * Restores the environment saved in lc_jump_env, which looks like
962 * SETJMP() returns 1.
963 */
964 if (lc_active)
965 {
966# if defined(SIGHASARG)
967 lc_signal = sigarg;
968# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +0100969 lc_active = FALSE; // don't jump again
Bram Moolenaar071d4272004-06-13 20:20:40 +0000970 LONGJMP(lc_jump_env, 1);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100971 // NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +0000972 }
973#endif
974
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000975#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000976# ifdef SIGQUIT
Bram Moolenaar0f873732019-12-05 20:28:46 +0100977 // While in mch_delay() we go to cooked mode to allow a CTRL-C to
978 // interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
979 // pressing CTRL-\, but we don't want Vim to exit then.
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000980 if (in_mch_delay && sigarg == SIGQUIT)
981 SIGRETURN;
982# endif
983
Bram Moolenaar0f873732019-12-05 20:28:46 +0100984 // When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
985 // here. This avoids that a non-reentrant function is interrupted, e.g.,
986 // free(). Calling free() again may then cause a crash.
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000987 if (entered == 0
988 && (0
989# ifdef SIGHUP
990 || sigarg == SIGHUP
991# endif
992# ifdef SIGQUIT
993 || sigarg == SIGQUIT
994# endif
995# ifdef SIGTERM
996 || sigarg == SIGTERM
997# endif
998# ifdef SIGPWR
999 || sigarg == SIGPWR
1000# endif
1001# ifdef SIGUSR1
1002 || sigarg == SIGUSR1
1003# endif
1004# ifdef SIGUSR2
1005 || sigarg == SIGUSR2
1006# endif
1007 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001008 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001009 SIGRETURN;
1010#endif
1011
Bram Moolenaar0f873732019-12-05 20:28:46 +01001012 // Remember how often we have been called.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001013 ++entered;
1014
Bram Moolenaar0f873732019-12-05 20:28:46 +01001015 // Executing autocommands is likely to use more stack space than we have
1016 // available in the signal stack.
Bram Moolenaare429e702016-06-10 19:49:14 +02001017 block_autocmds();
Bram Moolenaare429e702016-06-10 19:49:14 +02001018
Bram Moolenaar071d4272004-06-13 20:20:40 +00001019#ifdef FEAT_EVAL
Bram Moolenaar0f873732019-12-05 20:28:46 +01001020 // Set the v:dying variable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001021 set_vim_var_nr(VV_DYING, (long)entered);
1022#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001023 v_dying = entered;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001024
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001025#ifdef HAVE_STACK_LIMIT
Bram Moolenaar0f873732019-12-05 20:28:46 +01001026 // Since we are now using the signal stack, need to reset the stack
1027 // limit. Otherwise using a regexp will fail.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001028 get_stack_limit();
1029#endif
1030
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001031#if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01001032 // This is for opening gdb the moment Vim crashes.
1033 // You need to manually adjust the file name and Vim executable name.
1034 // Suggested by SungHyun Nam.
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001035 {
1036# define VI_GDB_FILE "/tmp/vimgdb"
1037# define VIM_NAME "/usr/bin/vim"
1038 FILE *fp = fopen(VI_GDB_FILE, "w");
1039 if (fp)
1040 {
1041 fprintf(fp,
1042 "file %s\n"
1043 "attach %d\n"
1044 "set height 1000\n"
1045 "bt full\n"
1046 , VIM_NAME, getpid());
1047 fclose(fp);
1048 system("xterm -e gdb -x "VI_GDB_FILE);
1049 unlink(VI_GDB_FILE);
1050 }
1051 }
1052#endif
1053
Bram Moolenaar071d4272004-06-13 20:20:40 +00001054#ifdef SIGHASARG
Bram Moolenaar0f873732019-12-05 20:28:46 +01001055 // try to find the name of this signal
Bram Moolenaar071d4272004-06-13 20:20:40 +00001056 for (i = 0; signal_info[i].sig != -1; i++)
1057 if (sigarg == signal_info[i].sig)
1058 break;
1059 deadly_signal = sigarg;
1060#endif
1061
Bram Moolenaar0f873732019-12-05 20:28:46 +01001062 full_screen = FALSE; // don't write message to the GUI, it might be
1063 // part of the problem...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064 /*
1065 * If something goes wrong after entering here, we may get here again.
1066 * When this happens, give a message and try to exit nicely (resetting the
1067 * terminal mode, etc.)
1068 * When this happens twice, just exit, don't even try to give a message,
1069 * stack may be corrupt or something weird.
1070 * When this still happens again (or memory was corrupted in such a way
1071 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1072 */
1073 if (entered >= 3)
1074 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001075 reset_signals(); // don't catch any signals anymore
Bram Moolenaar071d4272004-06-13 20:20:40 +00001076 may_core_dump();
1077 if (entered >= 4)
1078 _exit(8);
1079 exit(7);
1080 }
1081 if (entered == 2)
1082 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001083 // No translation, it may call malloc().
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001084 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085 out_flush();
1086 getout(1);
1087 }
1088
Bram Moolenaar0f873732019-12-05 20:28:46 +01001089 // No translation, it may call malloc().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001090#ifdef SIGHASARG
Bram Moolenaar69212b12020-05-10 14:14:03 +02001091 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\r\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092 signal_info[i].name);
1093#else
Bram Moolenaar69212b12020-05-10 14:14:03 +02001094 sprintf((char *)IObuff, "Vim: Caught deadly signal\r\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001095#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001096
Bram Moolenaar0f873732019-12-05 20:28:46 +01001097 // Preserve files and exit. This sets the really_exiting flag to prevent
1098 // calling free().
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001099 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001100
Bram Moolenaar0f873732019-12-05 20:28:46 +01001101 // NOTREACHED
Bram Moolenaare429e702016-06-10 19:49:14 +02001102
Bram Moolenaar009b2592004-10-24 19:18:58 +00001103#ifdef NBDEBUG
1104 reset_signals();
1105 may_core_dump();
1106 abort();
1107#endif
1108
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109 SIGRETURN;
1110}
1111
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112/*
Bram Moolenaar2e310482018-08-21 13:09:10 +02001113 * Invoked after receiving SIGCONT. We don't know what happened while
1114 * sleeping, deal with part of that.
1115 */
1116 static void
1117after_sigcont(void)
1118{
1119# ifdef FEAT_TITLE
1120 // Don't change "oldtitle" in a signal handler, set a flag to obtain it
1121 // again later.
1122 oldtitle_outdated = TRUE;
1123# endif
1124 settmode(TMODE_RAW);
1125 need_check_timestamps = TRUE;
1126 did_check_timestamps = FALSE;
1127}
1128
1129#if defined(SIGCONT)
1130static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar8e82c052018-08-21 19:47:48 +02001131static volatile sig_atomic_t in_mch_suspend = FALSE;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001132
1133/*
1134 * With multi-threading, suspending might not work immediately. Catch the
1135 * SIGCONT signal, which will be used as an indication whether the suspending
1136 * has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001137 *
1138 * On Linux, signal is not always handled immediately either.
1139 * See https://bugs.launchpad.net/bugs/291373
Bram Moolenaar2e310482018-08-21 13:09:10 +02001140 * Probably because the signal is handled in another thread.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001141 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001142 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001143 */
Bram Moolenaar8e82c052018-08-21 19:47:48 +02001144static volatile sig_atomic_t sigcont_received;
Bram Moolenaarf1883472018-08-20 21:58:57 +02001145static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146
1147/*
1148 * signal handler for SIGCONT
1149 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001150 static RETSIGTYPE
1151sigcont_handler SIGDEFARG(sigarg)
1152{
Bram Moolenaar2e310482018-08-21 13:09:10 +02001153 if (in_mch_suspend)
1154 {
1155 sigcont_received = TRUE;
1156 }
1157 else
1158 {
1159 // We didn't suspend ourselves, assume we were stopped by a SIGSTOP
1160 // signal (which can't be intercepted) and get a SIGCONT. Need to get
1161 // back to a sane mode. We should redraw, but we can't really do that
1162 // in a signal handler, do a redraw later.
1163 after_sigcont();
1164 redraw_later(CLEAR);
1165 cursor_on_force();
1166 out_flush();
1167 }
1168
Bram Moolenaar071d4272004-06-13 20:20:40 +00001169 SIGRETURN;
1170}
1171#endif
1172
Bram Moolenaar6dff58f2018-09-30 21:43:26 +02001173#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001174# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001175static void *clip_star_save = NULL;
1176static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001177# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001178
1179/*
1180 * Called when Vim is going to sleep or execute a shell command.
1181 * We can't respond to requests for the X selections. Lose them, otherwise
1182 * other applications will hang. But first copy the text to cut buffer 0.
1183 */
1184 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001185loose_clipboard(void)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001186{
1187 if (clip_star.owned || clip_plus.owned)
1188 {
1189 x11_export_final_selection();
1190 if (clip_star.owned)
1191 clip_lose_selection(&clip_star);
1192 if (clip_plus.owned)
1193 clip_lose_selection(&clip_plus);
1194 if (x11_display != NULL)
1195 XFlush(x11_display);
1196 }
1197}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001198
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001199# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001200/*
1201 * Save clipboard text to restore later.
1202 */
1203 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001204save_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001205{
1206 if (clip_star.owned)
1207 clip_star_save = get_register('*', TRUE);
1208 if (clip_plus.owned)
1209 clip_plus_save = get_register('+', TRUE);
1210}
1211
1212/*
1213 * Restore clipboard text if no one own the X selection.
1214 */
1215 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001216restore_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001217{
1218 if (clip_star_save != NULL)
1219 {
1220 if (!clip_gen_owner_exists(&clip_star))
1221 put_register('*', clip_star_save);
1222 else
1223 free_register(clip_star_save);
1224 clip_star_save = NULL;
1225 }
1226 if (clip_plus_save != NULL)
1227 {
1228 if (!clip_gen_owner_exists(&clip_plus))
1229 put_register('+', clip_plus_save);
1230 else
1231 free_register(clip_plus_save);
1232 clip_plus_save = NULL;
1233 }
1234}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001235# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001236#endif
1237
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238/*
1239 * If the machine has job control, use it to suspend the program,
1240 * otherwise fake it by starting a new shell.
1241 */
1242 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001243mch_suspend(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001244{
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001245 if (ignore_sigtstp)
1246 return;
1247
Bram Moolenaar0f873732019-12-05 20:28:46 +01001248 // BeOS does have SIGTSTP, but it doesn't work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001249#if defined(SIGTSTP) && !defined(__BEOS__)
Bram Moolenaar2e310482018-08-21 13:09:10 +02001250 in_mch_suspend = TRUE;
1251
Bram Moolenaar0f873732019-12-05 20:28:46 +01001252 out_flush(); // needed to make cursor visible on some systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00001253 settmode(TMODE_COOK);
Bram Moolenaar0f873732019-12-05 20:28:46 +01001254 out_flush(); // needed to disable mouse on some systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00001255
1256# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001257 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001258# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001259# if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001260 sigcont_received = FALSE;
1261# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001262
Bram Moolenaar0f873732019-12-05 20:28:46 +01001263 kill(0, SIGTSTP); // send ourselves a STOP signal
Bram Moolenaar2e310482018-08-21 13:09:10 +02001264
1265# if defined(SIGCONT)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001266 /*
1267 * Wait for the SIGCONT signal to be handled. It generally happens
Bram Moolenaar2e310482018-08-21 13:09:10 +02001268 * immediately, but somehow not all the time, probably because it's handled
1269 * in another thread. Do not call pause() because there would be race
1270 * condition which would hang Vim if signal happened in between the test of
1271 * sigcont_received and the call to pause(). If signal is not yet received,
1272 * sleep 0, 1, 2, 3 ms. Don't bother waiting further if signal is not
1273 * received after 1+2+3 ms (not expected to happen).
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001274 */
1275 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001276 long wait_time;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001277
Bram Moolenaar262735e2009-07-14 10:20:22 +00001278 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar262735e2009-07-14 10:20:22 +00001279 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001280 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001282 in_mch_suspend = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001283
Bram Moolenaar2e310482018-08-21 13:09:10 +02001284 after_sigcont();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001285#else
1286 suspend_shell();
1287#endif
1288}
1289
1290 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001291mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292{
1293 Columns = 80;
1294 Rows = 24;
1295
1296 out_flush();
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001297
1298#ifdef SIGTSTP
1299 // Check whether we were invoked with SIGTSTP set to be ignored. If it is
1300 // that indicates the shell (or program) that launched us does not support
1301 // tty job control and thus we should ignore that signal. If invoked as a
1302 // restricted editor (e.g., as "rvim") SIGTSTP is always ignored.
1303 ignore_sigtstp = restricted || SIG_IGN == signal(SIGTSTP, SIG_ERR);
1304#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001306
Bram Moolenaar56718732006-03-15 22:53:57 +00001307#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001308 mac_conv_init();
1309#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001310#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1311 win_clip_init();
1312#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313}
1314
1315 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001316set_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001317{
1318#if defined(SIGWINCH)
1319 /*
1320 * WINDOW CHANGE signal is handled with sig_winch().
1321 */
1322 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1323#endif
1324
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325#ifdef SIGTSTP
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001326 // See mch_init() for the conditions under which we ignore SIGTSTP.
1327 signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001328#endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001329#if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001330 signal(SIGCONT, sigcont_handler);
1331#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001332 /*
1333 * We want to ignore breaking of PIPEs.
1334 */
1335#ifdef SIGPIPE
1336 signal(SIGPIPE, SIG_IGN);
1337#endif
1338
Bram Moolenaar071d4272004-06-13 20:20:40 +00001339#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001340 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001341#endif
1342
1343 /*
1344 * Ignore alarm signals (Perl's alarm() generates it).
1345 */
1346#ifdef SIGALRM
1347 signal(SIGALRM, SIG_IGN);
1348#endif
1349
1350 /*
1351 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1352 * work will be lost.
1353 */
1354#ifdef SIGPWR
1355 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1356#endif
1357
1358 /*
1359 * Arrange for other signals to gracefully shutdown Vim.
1360 */
1361 catch_signals(deathtrap, SIG_ERR);
1362
1363#if defined(FEAT_GUI) && defined(SIGHUP)
1364 /*
1365 * When the GUI is running, ignore the hangup signal.
1366 */
1367 if (gui.in_use)
1368 signal(SIGHUP, SIG_IGN);
1369#endif
1370}
1371
Bram Moolenaardf177f62005-02-22 08:39:57 +00001372#if defined(SIGINT) || defined(PROTO)
1373/*
1374 * Catch CTRL-C (only works while in Cooked mode).
1375 */
1376 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001377catch_int_signal(void)
Bram Moolenaardf177f62005-02-22 08:39:57 +00001378{
1379 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1380}
1381#endif
1382
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001384reset_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001385{
1386 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar2e310482018-08-21 13:09:10 +02001387#if defined(SIGCONT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001388 // SIGCONT isn't in the list, because its default action is ignore
Bram Moolenaar071d4272004-06-13 20:20:40 +00001389 signal(SIGCONT, SIG_DFL);
1390#endif
1391}
1392
1393 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001394catch_signals(
1395 RETSIGTYPE (*func_deadly)(),
1396 RETSIGTYPE (*func_other)())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001397{
1398 int i;
1399
1400 for (i = 0; signal_info[i].sig != -1; i++)
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001401 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001402 if (signal_info[i].deadly)
1403 {
1404#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1405 struct sigaction sa;
1406
Bram Moolenaar0f873732019-12-05 20:28:46 +01001407 // Setup to use the alternate stack for the signal function.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001408 sa.sa_handler = func_deadly;
1409 sigemptyset(&sa.sa_mask);
1410# if defined(__linux__) && defined(_REENTRANT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001411 // On Linux, with glibc compiled for kernel 2.2, there is a bug in
1412 // thread handling in combination with using the alternate stack:
1413 // pthread library functions try to use the stack pointer to
1414 // identify the current thread, causing a SEGV signal, which
1415 // recursively calls deathtrap() and hangs.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001416 sa.sa_flags = 0;
1417# else
1418 sa.sa_flags = SA_ONSTACK;
1419# endif
1420 sigaction(signal_info[i].sig, &sa, NULL);
1421#else
1422# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1423 struct sigvec sv;
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 sv.sv_handler = func_deadly;
1427 sv.sv_mask = 0;
1428 sv.sv_flags = SV_ONSTACK;
1429 sigvec(signal_info[i].sig, &sv, NULL);
1430# else
1431 signal(signal_info[i].sig, func_deadly);
1432# endif
1433#endif
1434 }
1435 else if (func_other != SIG_ERR)
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001436 {
1437 // Deal with non-deadly signals.
1438#ifdef SIGTSTP
1439 signal(signal_info[i].sig,
1440 signal_info[i].sig == SIGTSTP && ignore_sigtstp
1441 ? SIG_IGN : func_other);
1442#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001443 signal(signal_info[i].sig, func_other);
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001444#endif
1445 }
1446 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001447}
1448
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001449#ifdef HAVE_SIGPROCMASK
1450 static void
1451block_signals(sigset_t *set)
1452{
1453 sigset_t newset;
1454 int i;
1455
1456 sigemptyset(&newset);
1457
1458 for (i = 0; signal_info[i].sig != -1; i++)
1459 sigaddset(&newset, signal_info[i].sig);
1460
Bram Moolenaar2e310482018-08-21 13:09:10 +02001461# if defined(SIGCONT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001462 // SIGCONT isn't in the list, because its default action is ignore
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001463 sigaddset(&newset, SIGCONT);
1464# endif
1465
1466 sigprocmask(SIG_BLOCK, &newset, set);
1467}
1468
1469 static void
1470unblock_signals(sigset_t *set)
1471{
1472 sigprocmask(SIG_SETMASK, set, NULL);
1473}
1474#endif
1475
Bram Moolenaar071d4272004-06-13 20:20:40 +00001476/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001477 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001478 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1479 * return TRUE
1480 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1481 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001482 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001483 * Returns TRUE when Vim should exit.
1484 */
1485 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001486vim_handle_signal(int sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001487{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001488 static int got_signal = 0;
1489 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001490
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001491 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001492 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001493 case SIGNAL_BLOCK: blocked = TRUE;
1494 break;
1495
1496 case SIGNAL_UNBLOCK: blocked = FALSE;
1497 if (got_signal != 0)
1498 {
1499 kill(getpid(), got_signal);
1500 got_signal = 0;
1501 }
1502 break;
1503
1504 default: if (!blocked)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001505 return TRUE; // exit!
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001506 got_signal = sig;
1507#ifdef SIGPWR
1508 if (sig != SIGPWR)
1509#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01001510 got_int = TRUE; // break any loops
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001511 break;
1512 }
1513 return FALSE;
1514}
1515
1516/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001517 * Check_win checks whether we have an interactive stdout.
1518 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001519 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001520mch_check_win(int argc UNUSED, char **argv UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001521{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001522 if (isatty(1))
1523 return OK;
1524 return FAIL;
1525}
1526
1527/*
1528 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1529 */
1530 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001531mch_input_isatty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001532{
1533 if (isatty(read_cmd_fd))
1534 return TRUE;
1535 return FALSE;
1536}
1537
1538#ifdef FEAT_X11
1539
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001540# if defined(ELAPSED_TIMEVAL) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1542
Bram Moolenaar071d4272004-06-13 20:20:40 +00001543/*
1544 * Give a message about the elapsed time for opening the X window.
1545 */
1546 static void
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001547xopen_message(long elapsed_msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001548{
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001549 smsg(_("Opening the X display took %ld msec"), elapsed_msec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001550}
1551# endif
1552#endif
1553
1554#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1555/*
1556 * A few functions shared by X11 title and clipboard code.
1557 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001558
1559static int got_x_error = FALSE;
1560
1561/*
1562 * X Error handler, otherwise X just exits! (very rude) -- webb
1563 */
1564 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001565x_error_handler(Display *dpy, XErrorEvent *error_event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001566{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001567 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568 STRCAT(IObuff, _("\nVim: Got X error\n"));
1569
Bram Moolenaarb1062eb2020-05-09 16:11:33 +02001570 // In the GUI we cannot print a message and continue, because no X calls
1571 // are allowed here (causes my system to hang). Silently continuing seems
1572 // like the best alternative. Do preserve files, in case we crash.
1573 ml_sync_all(FALSE, FALSE);
1574
1575#ifdef FEAT_GUI
1576 if (!gui.in_use)
1577#endif
1578 msg((char *)IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001579
Bram Moolenaar0f873732019-12-05 20:28:46 +01001580 return 0; // NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +00001581}
1582
1583/*
1584 * Another X Error handler, just used to check for errors.
1585 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001586 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001587x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588{
1589 got_x_error = TRUE;
1590 return 0;
1591}
1592
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001593/*
1594 * Return TRUE when connection to the X server is desired.
1595 */
1596 static int
1597x_connect_to_server(void)
1598{
1599 // No point in connecting if we are exiting or dying.
1600 if (exiting || v_dying)
1601 return FALSE;
1602
1603#if defined(FEAT_CLIENTSERVER)
1604 if (x_force_connect)
1605 return TRUE;
1606#endif
1607 if (x_no_connect)
1608 return FALSE;
1609
Bram Moolenaara8bfa172018-12-29 22:28:46 +01001610 // Check for a match with "exclude:" from 'clipboard'.
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001611 if (clip_exclude_prog != NULL)
1612 {
Bram Moolenaara8bfa172018-12-29 22:28:46 +01001613 // Just in case we get called recursively, return FALSE. This could
1614 // happen if vpeekc() is used while executing the prog and it causes a
1615 // related callback to be invoked.
1616 if (regprog_in_use(clip_exclude_prog))
1617 return FALSE;
1618
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001619 if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
1620 return FALSE;
1621 }
1622 return TRUE;
1623}
1624
Bram Moolenaar071d4272004-06-13 20:20:40 +00001625#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaarb2148f52019-01-20 23:43:57 +01001626# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001627/*
1628 * An X IO Error handler, used to catch error while opening the display.
1629 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001630 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001631x_IOerror_check(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001632{
Bram Moolenaar0f873732019-12-05 20:28:46 +01001633 // This function should not return, it causes exit(). Longjump instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001634 LONGJMP(lc_jump_env, 1);
Bram Moolenaar1eed5322019-02-26 17:03:54 +01001635# if defined(VMS) || defined(__CYGWIN__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001636 return 0; // avoid the compiler complains about missing return value
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001637# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001638}
1639# endif
1640
1641/*
1642 * An X IO Error handler, used to catch terminal errors.
1643 */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001644static int xterm_dpy_retry_count = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001645
Bram Moolenaar071d4272004-06-13 20:20:40 +00001646 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001647x_IOerror_handler(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648{
1649 xterm_dpy = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001650 xterm_dpy_retry_count = 5; // Try reconnecting five times
Bram Moolenaar071d4272004-06-13 20:20:40 +00001651 x11_window = 0;
1652 x11_display = NULL;
1653 xterm_Shell = (Widget)0;
1654
Bram Moolenaar0f873732019-12-05 20:28:46 +01001655 // This function should not return, it causes exit(). Longjump instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001656 LONGJMP(x_jump_env, 1);
Bram Moolenaar1eed5322019-02-26 17:03:54 +01001657# if defined(VMS) || defined(__CYGWIN__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001658 return 0; // avoid the compiler complains about missing return value
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001659# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001660}
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001661
1662/*
1663 * If the X11 connection was lost try to restore it.
1664 * Helps when the X11 server was stopped and restarted while Vim was inactive
Bram Moolenaarcaad4f02014-12-17 14:36:14 +01001665 * (e.g. through tmux).
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001666 */
1667 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001668may_restore_clipboard(void)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001669{
Bram Moolenaar01e51e52018-12-29 13:09:46 +01001670 // No point in restoring the connecting if we are exiting or dying.
1671 if (!exiting && !v_dying && xterm_dpy_retry_count > 0)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001672 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001673 --xterm_dpy_retry_count;
Bram Moolenaar527a6782014-12-17 17:59:31 +01001674
1675# ifndef LESSTIF_VERSION
Bram Moolenaar0f873732019-12-05 20:28:46 +01001676 // This has been reported to avoid Vim getting stuck.
Bram Moolenaar527a6782014-12-17 17:59:31 +01001677 if (app_context != (XtAppContext)NULL)
1678 {
1679 XtDestroyApplicationContext(app_context);
1680 app_context = (XtAppContext)NULL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01001681 x11_display = NULL; // freed by XtDestroyApplicationContext()
Bram Moolenaar527a6782014-12-17 17:59:31 +01001682 }
1683# endif
1684
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001685 setup_term_clip();
1686 get_x11_title(FALSE);
1687 }
1688}
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001689
1690 void
1691ex_xrestore(exarg_T *eap)
1692{
1693 if (eap->arg != NULL && STRLEN(eap->arg) > 0)
1694 {
1695 if (xterm_display_allocated)
1696 vim_free(xterm_display);
1697 xterm_display = (char *)vim_strsave(eap->arg);
1698 xterm_display_allocated = TRUE;
1699 }
1700 smsg(_("restoring display %s"), xterm_display == NULL
Bram Moolenaar0c5c3fa2019-11-30 22:38:16 +01001701 ? (char *)mch_getenv((char_u *)"DISPLAY") : xterm_display);
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001702
1703 clear_xterm_clip();
1704 x11_window = 0;
1705 xterm_dpy_retry_count = 5; // Try reconnecting five times
1706 may_restore_clipboard();
1707}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001708#endif
1709
1710/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711 * Test if "dpy" and x11_window are valid by getting the window title.
1712 * I don't actually want it yet, so there may be a simpler call to use, but
1713 * this will cause the error handler x_error_check() to be called if anything
1714 * is wrong, such as the window pointer being invalid (as can happen when the
1715 * user changes his DISPLAY, but not his WINDOWID) -- webb
1716 */
1717 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001718test_x11_window(Display *dpy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719{
1720 int (*old_handler)();
1721 XTextProperty text_prop;
1722
1723 old_handler = XSetErrorHandler(x_error_check);
1724 got_x_error = FALSE;
1725 if (XGetWMName(dpy, x11_window, &text_prop))
1726 XFree((void *)text_prop.value);
1727 XSync(dpy, False);
1728 (void)XSetErrorHandler(old_handler);
1729
1730 if (p_verbose > 0 && got_x_error)
Bram Moolenaar32526b32019-01-19 17:43:09 +01001731 verb_msg(_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732
1733 return (got_x_error ? FAIL : OK);
1734}
1735#endif
1736
1737#ifdef FEAT_TITLE
1738
1739#ifdef FEAT_X11
1740
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001741static int get_x11_thing(int get_title, int test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742
1743/*
1744 * try to get x11 window and display
1745 *
1746 * return FAIL for failure, OK otherwise
1747 */
1748 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001749get_x11_windis(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001750{
1751 char *winid;
1752 static int result = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01001753#define XD_NONE 0 // x11_display not set here
1754#define XD_HERE 1 // x11_display opened here
1755#define XD_GUI 2 // x11_display used from gui.dpy
1756#define XD_XTERM 3 // x11_display used from xterm_dpy
Bram Moolenaar071d4272004-06-13 20:20:40 +00001757 static int x11_display_from = XD_NONE;
1758 static int did_set_error_handler = FALSE;
1759
1760 if (!did_set_error_handler)
1761 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001762 // X just exits if it finds an error otherwise!
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763 (void)XSetErrorHandler(x_error_handler);
1764 did_set_error_handler = TRUE;
1765 }
1766
Bram Moolenaar9372a112005-12-06 19:59:18 +00001767#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001768 if (gui.in_use)
1769 {
1770 /*
1771 * If the X11 display was opened here before, for the window where Vim
1772 * was started, close that one now to avoid a memory leak.
1773 */
1774 if (x11_display_from == XD_HERE && x11_display != NULL)
1775 {
1776 XCloseDisplay(x11_display);
1777 x11_display_from = XD_NONE;
1778 }
1779 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1780 {
1781 x11_display_from = XD_GUI;
1782 return OK;
1783 }
1784 x11_display = NULL;
1785 return FAIL;
1786 }
1787 else if (x11_display_from == XD_GUI)
1788 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001789 // GUI must have stopped somehow, clear x11_display
Bram Moolenaar071d4272004-06-13 20:20:40 +00001790 x11_window = 0;
1791 x11_display = NULL;
1792 x11_display_from = XD_NONE;
1793 }
1794#endif
1795
Bram Moolenaar0f873732019-12-05 20:28:46 +01001796 // When started with the "-X" argument, don't try connecting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001797 if (!x_connect_to_server())
1798 return FAIL;
1799
1800 /*
1801 * If WINDOWID not set, should try another method to find out
1802 * what the current window number is. The only code I know for
1803 * this is very complicated.
1804 * We assume that zero is invalid for WINDOWID.
1805 */
1806 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1807 x11_window = (Window)atol(winid);
1808
1809#ifdef FEAT_XCLIPBOARD
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001810 if (xterm_dpy == x11_display)
1811 // x11_display may have been set to xterm_dpy elsewhere
1812 x11_display_from = XD_XTERM;
1813
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814 if (xterm_dpy != NULL && x11_window != 0)
1815 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001816 // We may have checked it already, but Gnome terminal can move us to
1817 // another window, so we need to check every time.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001818 if (x11_display_from != XD_XTERM)
1819 {
1820 /*
1821 * If the X11 display was opened here before, for the window where
1822 * Vim was started, close that one now to avoid a memory leak.
1823 */
1824 if (x11_display_from == XD_HERE && x11_display != NULL)
1825 XCloseDisplay(x11_display);
1826 x11_display = xterm_dpy;
1827 x11_display_from = XD_XTERM;
1828 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829 if (test_x11_window(x11_display) == FAIL)
1830 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001831 // probably bad $WINDOWID
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832 x11_window = 0;
1833 x11_display = NULL;
1834 x11_display_from = XD_NONE;
1835 return FAIL;
1836 }
1837 return OK;
1838 }
1839#endif
1840
1841 if (x11_window == 0 || x11_display == NULL)
1842 result = -1;
1843
Bram Moolenaar0f873732019-12-05 20:28:46 +01001844 if (result != -1) // Have already been here and set this
1845 return result; // Don't do all these X calls again
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846
1847 if (x11_window != 0 && x11_display == NULL)
1848 {
1849#ifdef SET_SIG_ALARM
1850 RETSIGTYPE (*sig_save)();
1851#endif
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01001852#ifdef ELAPSED_FUNC
1853 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001854
1855 if (p_verbose > 0)
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01001856 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857#endif
1858
1859#ifdef SET_SIG_ALARM
1860 /*
1861 * Opening the Display may hang if the DISPLAY setting is wrong, or
1862 * the network connection is bad. Set an alarm timer to get out.
1863 */
1864 sig_alarm_called = FALSE;
1865 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1866 (RETSIGTYPE (*)())sig_alarm);
1867 alarm(2);
1868#endif
1869 x11_display = XOpenDisplay(NULL);
1870
1871#ifdef SET_SIG_ALARM
1872 alarm(0);
1873 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1874 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaar563bbea2019-01-22 21:45:40 +01001875 verb_msg(_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876#endif
1877 if (x11_display != NULL)
1878 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001879# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00001880 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001881 {
1882 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001883 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001884 verbose_leave();
1885 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886# endif
1887 if (test_x11_window(x11_display) == FAIL)
1888 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001889 // Maybe window id is bad
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890 x11_window = 0;
1891 XCloseDisplay(x11_display);
1892 x11_display = NULL;
1893 }
1894 else
1895 x11_display_from = XD_HERE;
1896 }
1897 }
1898 if (x11_window == 0 || x11_display == NULL)
1899 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001900
1901# ifdef FEAT_EVAL
1902 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1903# endif
1904
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905 return (result = OK);
1906}
1907
1908/*
1909 * Determine original x11 Window Title
1910 */
1911 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001912get_x11_title(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001913{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001914 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915}
1916
1917/*
1918 * Determine original x11 Window icon
1919 */
1920 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001921get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001922{
1923 int retval = FALSE;
1924
1925 retval = get_x11_thing(FALSE, test_only);
1926
Bram Moolenaar0f873732019-12-05 20:28:46 +01001927 // could not get old icon, use terminal name
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928 if (oldicon == NULL && !test_only)
1929 {
1930 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001931 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001932 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001933 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934 }
1935
1936 return retval;
1937}
1938
1939 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001940get_x11_thing(
Bram Moolenaar0f873732019-12-05 20:28:46 +01001941 int get_title, // get title string
Bram Moolenaar05540972016-01-30 20:31:25 +01001942 int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943{
1944 XTextProperty text_prop;
1945 int retval = FALSE;
1946 Status status;
1947
1948 if (get_x11_windis() == OK)
1949 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001950 // Get window/icon name if any
Bram Moolenaar071d4272004-06-13 20:20:40 +00001951 if (get_title)
1952 status = XGetWMName(x11_display, x11_window, &text_prop);
1953 else
1954 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1955
1956 /*
1957 * If terminal is xterm, then x11_window may be a child window of the
1958 * outer xterm window that actually contains the window/icon name, so
1959 * keep traversing up the tree until a window with a title/icon is
1960 * found.
1961 */
Bram Moolenaar4b96df52020-01-26 22:00:26 +01001962 // Previously this was only done for xterm and alike. I don't see a
Bram Moolenaar0f873732019-12-05 20:28:46 +01001963 // reason why it would fail for other terminal emulators.
1964 // if (term_is_xterm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001965 {
1966 Window root;
1967 Window parent;
1968 Window win = x11_window;
1969 Window *children;
1970 unsigned int num_children;
1971
1972 while (!status || text_prop.value == NULL)
1973 {
1974 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1975 &num_children))
1976 break;
1977 if (children)
1978 XFree((void *)children);
1979 if (parent == root || parent == 0)
1980 break;
1981
1982 win = parent;
1983 if (get_title)
1984 status = XGetWMName(x11_display, win, &text_prop);
1985 else
1986 status = XGetWMIconName(x11_display, win, &text_prop);
1987 }
1988 }
1989 if (status && text_prop.value != NULL)
1990 {
1991 retval = TRUE;
1992 if (!test_only)
1993 {
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01001994 if (get_title)
1995 vim_free(oldtitle);
1996 else
1997 vim_free(oldicon);
Bram Moolenaara12a1612019-01-24 16:39:02 +01001998 if (text_prop.encoding == XA_STRING && !has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001999 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002000 if (get_title)
2001 oldtitle = vim_strsave((char_u *)text_prop.value);
2002 else
2003 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002004 }
2005 else
2006 {
2007 char **cl;
2008 Status transform_status;
2009 int n = 0;
2010
2011 transform_status = XmbTextPropertyToTextList(x11_display,
2012 &text_prop,
2013 &cl, &n);
2014 if (transform_status >= Success && n > 0 && cl[0])
2015 {
2016 if (get_title)
2017 oldtitle = vim_strsave((char_u *) cl[0]);
2018 else
2019 oldicon = vim_strsave((char_u *) cl[0]);
2020 XFreeStringList(cl);
2021 }
2022 else
2023 {
2024 if (get_title)
2025 oldtitle = vim_strsave((char_u *)text_prop.value);
2026 else
2027 oldicon = vim_strsave((char_u *)text_prop.value);
2028 }
2029 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002030 }
2031 XFree((void *)text_prop.value);
2032 }
2033 }
2034 return retval;
2035}
2036
Bram Moolenaar0f873732019-12-05 20:28:46 +01002037// Xutf8 functions are not available on older systems. Note that on some
2038// systems X_HAVE_UTF8_STRING may be defined in a header file but
2039// Xutf8SetWMProperties() is not in the X11 library. Configure checks for
2040// that and defines HAVE_XUTF8SETWMPROPERTIES.
Bram Moolenaara12a1612019-01-24 16:39:02 +01002041#if defined(X_HAVE_UTF8_STRING)
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002042# if X_HAVE_UTF8_STRING && HAVE_XUTF8SETWMPROPERTIES
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043# define USE_UTF8_STRING
2044# endif
2045#endif
2046
2047/*
2048 * Set x11 Window Title
2049 *
2050 * get_x11_windis() must be called before this and have returned OK
2051 */
2052 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002053set_x11_title(char_u *title)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002054{
Bram Moolenaar0f873732019-12-05 20:28:46 +01002055 // XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
2056 // when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
2057 // supported everywhere and STRING doesn't work for multi-byte titles.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002058#ifdef USE_UTF8_STRING
2059 if (enc_utf8)
2060 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
2061 NULL, NULL, 0, NULL, NULL, NULL);
2062 else
2063#endif
2064 {
2065#if XtSpecificationRelease >= 4
2066# ifdef FEAT_XFONTSET
2067 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
2068 NULL, NULL, 0, NULL, NULL, NULL);
2069# else
2070 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002071 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002072
Bram Moolenaar0f873732019-12-05 20:28:46 +01002073 // directly from example 3-18 "basicwin" of Xlib Programming Manual
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002074 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075 XSetWMProperties(x11_display, x11_window, &text_prop,
2076 NULL, NULL, 0, NULL, NULL, NULL);
2077# endif
2078#else
2079 XStoreName(x11_display, x11_window, (char *)title);
2080#endif
2081 }
2082 XFlush(x11_display);
2083}
2084
2085/*
2086 * Set x11 Window icon
2087 *
2088 * get_x11_windis() must be called before this and have returned OK
2089 */
2090 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002091set_x11_icon(char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002092{
Bram Moolenaar0f873732019-12-05 20:28:46 +01002093 // See above for comments about using X*SetWMProperties().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094#ifdef USE_UTF8_STRING
2095 if (enc_utf8)
2096 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2097 NULL, 0, NULL, NULL, NULL);
2098 else
2099#endif
2100 {
2101#if XtSpecificationRelease >= 4
2102# ifdef FEAT_XFONTSET
2103 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2104 NULL, 0, NULL, NULL, NULL);
2105# else
2106 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002107 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002108
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002109 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002110 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2111 NULL, 0, NULL, NULL, NULL);
2112# endif
2113#else
2114 XSetIconName(x11_display, x11_window, (char *)icon);
2115#endif
2116 }
2117 XFlush(x11_display);
2118}
2119
Bram Moolenaar0f873732019-12-05 20:28:46 +01002120#else // FEAT_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002121
Bram Moolenaar071d4272004-06-13 20:20:40 +00002122 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002123get_x11_title(int test_only UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124{
2125 return FALSE;
2126}
2127
2128 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002129get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002130{
2131 if (!test_only)
2132 {
2133 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002134 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002135 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002136 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002137 }
2138 return FALSE;
2139}
2140
Bram Moolenaar0f873732019-12-05 20:28:46 +01002141#endif // FEAT_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002142
2143 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002144mch_can_restore_title(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002145{
2146 return get_x11_title(TRUE);
2147}
2148
2149 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002150mch_can_restore_icon(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002151{
2152 return get_x11_icon(TRUE);
2153}
2154
2155/*
2156 * Set the window title and icon.
2157 */
2158 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002159mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002160{
2161 int type = 0;
2162 static int recursive = 0;
2163
Bram Moolenaar0f873732019-12-05 20:28:46 +01002164 if (T_NAME == NULL) // no terminal name (yet)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 return;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002166 if (title == NULL && icon == NULL) // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00002167 return;
2168
Bram Moolenaar0f873732019-12-05 20:28:46 +01002169 // When one of the X11 functions causes a deadly signal, we get here again
2170 // recursively. Avoid hanging then (something is probably locked).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002171 if (recursive)
2172 return;
2173 ++recursive;
2174
2175 /*
2176 * if the window ID and the display is known, we may use X11 calls
2177 */
2178#ifdef FEAT_X11
2179 if (get_x11_windis() == OK)
2180 type = 1;
2181#else
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002182# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) \
2183 || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002184 if (gui.in_use)
2185 type = 1;
2186# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002187#endif
2188
2189 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002190 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002191 * than x11 calls, because the x11 calls don't always work
2192 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002193 if ((type || *T_TS != NUL) && title != NULL)
2194 {
Bram Moolenaard8f0cef2018-08-19 22:20:16 +02002195 if (oldtitle_outdated)
2196 {
2197 oldtitle_outdated = FALSE;
2198 VIM_CLEAR(oldtitle);
2199 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200 if (oldtitle == NULL
2201#ifdef FEAT_GUI
2202 && !gui.in_use
2203#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002204 ) // first call but not in GUI, save title
Bram Moolenaar071d4272004-06-13 20:20:40 +00002205 (void)get_x11_title(FALSE);
2206
Bram Moolenaar0f873732019-12-05 20:28:46 +01002207 if (*T_TS != NUL) // it's OK if t_fs is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00002208 term_settitle(title);
2209#ifdef FEAT_X11
2210 else
2211# ifdef FEAT_GUI_GTK
Bram Moolenaar0f873732019-12-05 20:28:46 +01002212 if (!gui.in_use) // don't do this if GTK+ is running
Bram Moolenaar071d4272004-06-13 20:20:40 +00002213# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002214 set_x11_title(title); // x11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002215#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002216#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2218 else
2219 gui_mch_settitle(title, icon);
2220#endif
Bram Moolenaardac13472019-09-16 21:06:21 +02002221 unix_did_set_title = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002222 }
2223
2224 if ((type || *T_CIS != NUL) && icon != NULL)
2225 {
2226 if (oldicon == NULL
2227#ifdef FEAT_GUI
2228 && !gui.in_use
2229#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002230 ) // first call, save icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002231 get_x11_icon(FALSE);
2232
2233 if (*T_CIS != NUL)
2234 {
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02002235 out_str(T_CIS); // set icon start
Bram Moolenaar071d4272004-06-13 20:20:40 +00002236 out_str_nf(icon);
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02002237 out_str(T_CIE); // set icon end
Bram Moolenaar071d4272004-06-13 20:20:40 +00002238 out_flush();
2239 }
2240#ifdef FEAT_X11
2241 else
2242# ifdef FEAT_GUI_GTK
Bram Moolenaar0f873732019-12-05 20:28:46 +01002243 if (!gui.in_use) // don't do this if GTK+ is running
Bram Moolenaar071d4272004-06-13 20:20:40 +00002244# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002245 set_x11_icon(icon); // x11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002246#endif
2247 did_set_icon = TRUE;
2248 }
2249 --recursive;
2250}
2251
2252/*
2253 * Restore the window/icon title.
2254 * "which" is one of:
Bram Moolenaar40385db2018-08-07 22:31:44 +02002255 * SAVE_RESTORE_TITLE only restore title
2256 * SAVE_RESTORE_ICON only restore icon
2257 * SAVE_RESTORE_BOTH restore title and icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002258 */
2259 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002260mch_restore_title(int which)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002261{
Bram Moolenaardac13472019-09-16 21:06:21 +02002262 int do_push_pop = unix_did_set_title || did_set_icon;
Bram Moolenaare5c83282019-05-03 23:15:37 +02002263
Bram Moolenaar0f873732019-12-05 20:28:46 +01002264 // only restore the title or icon when it has been set
Bram Moolenaardac13472019-09-16 21:06:21 +02002265 mch_settitle(((which & SAVE_RESTORE_TITLE) && unix_did_set_title) ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 (oldtitle ? oldtitle : p_titleold) : NULL,
Bram Moolenaar40385db2018-08-07 22:31:44 +02002267 ((which & SAVE_RESTORE_ICON) && did_set_icon) ? oldicon : NULL);
2268
Bram Moolenaare5c83282019-05-03 23:15:37 +02002269 if (do_push_pop)
2270 {
2271 // pop and push from/to the stack
2272 term_pop_title(which);
2273 term_push_title(which);
2274 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002275}
2276
Bram Moolenaar0f873732019-12-05 20:28:46 +01002277#endif // FEAT_TITLE
Bram Moolenaar071d4272004-06-13 20:20:40 +00002278
2279/*
2280 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002281 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 */
2283 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002284vim_is_xterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285{
2286 if (name == NULL)
2287 return FALSE;
2288 return (STRNICMP(name, "xterm", 5) == 0
2289 || STRNICMP(name, "nxterm", 6) == 0
2290 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002291 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292 || STRNICMP(name, "rxvt", 4) == 0
Bram Moolenaar995e4af2017-09-01 20:24:03 +02002293 || STRNICMP(name, "screen.xterm", 12) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002294 || STRCMP(name, "builtin_xterm") == 0);
2295}
2296
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002297#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2298/*
2299 * Return TRUE if "name" appears to be that of a terminal
2300 * known to support the xterm-style mouse protocol.
2301 * Relies on term_is_xterm having been set to its correct value.
2302 */
2303 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002304use_xterm_like_mouse(char_u *name)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002305{
2306 return (name != NULL
Bram Moolenaare56132b2016-08-14 18:23:21 +02002307 && (term_is_xterm
2308 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002309 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaare56132b2016-08-14 18:23:21 +02002310 || STRICMP(name, "st") == 0
2311 || STRNICMP(name, "st-", 3) == 0
2312 || STRNICMP(name, "stterm", 6) == 0));
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002313}
2314#endif
2315
Bram Moolenaar071d4272004-06-13 20:20:40 +00002316/*
2317 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2318 * Return 1 for "xterm".
2319 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002320 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002321 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322 */
2323 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002324use_xterm_mouse(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002325{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002326 if (ttym_flags == TTYM_SGR)
2327 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002328 if (ttym_flags == TTYM_URXVT)
2329 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002330 if (ttym_flags == TTYM_XTERM2)
2331 return 2;
2332 if (ttym_flags == TTYM_XTERM)
2333 return 1;
2334 return 0;
2335}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002336
2337 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002338vim_is_iris(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339{
2340 if (name == NULL)
2341 return FALSE;
2342 return (STRNICMP(name, "iris-ansi", 9) == 0
2343 || STRCMP(name, "builtin_iris-ansi") == 0);
2344}
2345
2346 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002347vim_is_vt300(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348{
2349 if (name == NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01002350 return FALSE; // actually all ANSI comp. terminals should be here
2351 // catch VT100 - VT5xx
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002352 return ((STRNICMP(name, "vt", 2) == 0
2353 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354 || STRCMP(name, "builtin_vt320") == 0);
2355}
2356
2357/*
2358 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2359 * This should include all windowed terminal emulators.
2360 */
2361 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002362vim_is_fastterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363{
2364 if (name == NULL)
2365 return FALSE;
2366 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2367 return TRUE;
2368 return ( STRNICMP(name, "hpterm", 6) == 0
2369 || STRNICMP(name, "sun-cmd", 7) == 0
2370 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002371 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372 || STRNICMP(name, "dtterm", 6) == 0);
2373}
2374
2375/*
2376 * Insert user name in s[len].
2377 * Return OK if a name found.
2378 */
2379 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002380mch_get_user_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381{
2382#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002383 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384 return OK;
2385#else
2386 return mch_get_uname(getuid(), s, len);
2387#endif
2388}
2389
2390/*
2391 * Insert user name for "uid" in s[len].
2392 * Return OK if a name found.
2393 */
2394 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002395mch_get_uname(uid_t uid, char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002396{
2397#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2398 struct passwd *pw;
2399
2400 if ((pw = getpwuid(uid)) != NULL
2401 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2402 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002403 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404 return OK;
2405 }
2406#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002407 sprintf((char *)s, "%d", (int)uid); // assumes s is long enough
2408 return FAIL; // a number is not a name
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409}
2410
2411/*
2412 * Insert host name is s[len].
2413 */
2414
2415#ifdef HAVE_SYS_UTSNAME_H
2416 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002417mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002418{
2419 struct utsname vutsname;
2420
2421 if (uname(&vutsname) < 0)
2422 *s = NUL;
2423 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002424 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002426#else // HAVE_SYS_UTSNAME_H
Bram Moolenaar071d4272004-06-13 20:20:40 +00002427
2428# ifdef HAVE_SYS_SYSTEMINFO_H
2429# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2430# endif
2431
2432 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002433mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434{
2435# ifdef VAXC
2436 vaxc$gethostname((char *)s, len);
2437# else
2438 gethostname((char *)s, len);
2439# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002440 s[len - 1] = NUL; // make sure it's terminated
Bram Moolenaar071d4272004-06-13 20:20:40 +00002441}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002442#endif // HAVE_SYS_UTSNAME_H
Bram Moolenaar071d4272004-06-13 20:20:40 +00002443
2444/*
2445 * return process ID
2446 */
2447 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002448mch_get_pid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002449{
2450 return (long)getpid();
2451}
2452
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002453/*
2454 * return TRUE if process "pid" is still running
2455 */
2456 int
Bram Moolenaar1b243ea2019-04-28 22:50:40 +02002457mch_process_running(long pid)
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002458{
2459 // EMX kill() not working correctly, it seems
2460 return kill(pid, 0) == 0;
2461}
2462
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 static char *
Bram Moolenaar05540972016-01-30 20:31:25 +01002465strerror(int err)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466{
2467 extern int sys_nerr;
2468 extern char *sys_errlist[];
2469 static char er[20];
2470
2471 if (err > 0 && err < sys_nerr)
2472 return (sys_errlist[err]);
2473 sprintf(er, "Error %d", err);
2474 return er;
2475}
2476#endif
2477
2478/*
Bram Moolenaar964b3742019-05-24 18:54:09 +02002479 * Get name of current directory into buffer "buf" of length "len" bytes.
2480 * "len" must be at least PATH_MAX.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481 * Return OK for success, FAIL for failure.
2482 */
2483 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002484mch_dirname(char_u *buf, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002485{
2486#if defined(USE_GETCWD)
2487 if (getcwd((char *)buf, len) == NULL)
2488 {
2489 STRCPY(buf, strerror(errno));
2490 return FAIL;
2491 }
2492 return OK;
2493#else
2494 return (getwd((char *)buf) != NULL ? OK : FAIL);
2495#endif
2496}
2497
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002499 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500 *
2501 * return FAIL for failure, OK for success
2502 */
2503 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002504mch_FullName(
2505 char_u *fname,
2506 char_u *buf,
2507 int len,
Bram Moolenaar0f873732019-12-05 20:28:46 +01002508 int force) // also expand when already absolute path
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509{
2510 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002511#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512 int fd = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002513 static int dont_fchdir = FALSE; // TRUE when fchdir() doesn't work
Bram Moolenaar38323e42007-03-06 19:22:53 +00002514#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002515 char_u olddir[MAXPATHL];
2516 char_u *p;
2517 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002518#ifdef __CYGWIN__
Bram Moolenaar0f873732019-12-05 20:28:46 +01002519 char_u posix_fname[MAXPATHL]; // Cygwin docs mention MAX_PATH, but
2520 // it's not always defined
Bram Moolenaarbf820722008-06-21 11:12:49 +00002521#endif
2522
Bram Moolenaar38323e42007-03-06 19:22:53 +00002523#ifdef VMS
2524 fname = vms_fixfilename(fname);
2525#endif
2526
Bram Moolenaara2442432007-04-26 14:26:37 +00002527#ifdef __CYGWIN__
2528 /*
2529 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2530 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002531# if CYGWIN_VERSION_DLL_MAJOR >= 1007
Bram Moolenaar0f873732019-12-05 20:28:46 +01002532 // Use CCP_RELATIVE to avoid that it sometimes returns a path that ends in
2533 // a forward slash.
Bram Moolenaar06b07342015-12-31 22:26:28 +01002534 cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE,
2535 fname, posix_fname, MAXPATHL);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002536# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002537 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002538# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002539 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002540#endif
2541
Bram Moolenaar0f873732019-12-05 20:28:46 +01002542 // Expand it if forced or not an absolute path.
2543 // Do not do it for "/file", the result is always "/".
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002544 if ((force || !mch_isFullName(fname))
2545 && ((p = vim_strrchr(fname, '/')) == NULL || p != fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002546 {
2547 /*
2548 * If the file name has a path, change to that directory for a moment,
Bram Moolenaar964b3742019-05-24 18:54:09 +02002549 * and then get the directory (and get back to where we were).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002550 * This will get the correct path name with "../" things.
2551 */
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002552 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002553 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002554#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555 /*
2556 * Use fchdir() if possible, it's said to be faster and more
2557 * reliable. But on SunOS 4 it might not work. Check this by
2558 * doing a fchdir() right now.
2559 */
2560 if (!dont_fchdir)
2561 {
2562 fd = open(".", O_RDONLY | O_EXTRA, 0);
2563 if (fd >= 0 && fchdir(fd) < 0)
2564 {
2565 close(fd);
2566 fd = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002567 dont_fchdir = TRUE; // don't try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 }
2569 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002570#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571
Bram Moolenaar0f873732019-12-05 20:28:46 +01002572 // Only change directory when we are sure we can return to where
2573 // we are now. After doing "su" chdir(".") might not work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002575#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002576 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002577#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002578 (mch_dirname(olddir, MAXPATHL) == FAIL
2579 || mch_chdir((char *)olddir) != 0))
2580 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002581 p = NULL; // can't get current dir: don't chdir
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582 retval = FAIL;
2583 }
2584 else
2585 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002586 // The directory is copied into buf[], to be able to remove
2587 // the file name without changing it (could be a string in
2588 // read-only memory)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 if (p - fname >= len)
2590 retval = FAIL;
2591 else
2592 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002593 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594 if (mch_chdir((char *)buf))
2595 retval = FAIL;
2596 else
2597 fname = p + 1;
2598 *buf = NUL;
2599 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002600 }
2601 }
2602 if (mch_dirname(buf, len) == FAIL)
2603 {
2604 retval = FAIL;
2605 *buf = NUL;
2606 }
2607 if (p != NULL)
2608 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002609#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610 if (fd >= 0)
2611 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002612 if (p_verbose >= 5)
2613 {
2614 verbose_enter();
Bram Moolenaar32526b32019-01-19 17:43:09 +01002615 msg("fchdir() to previous dir");
Bram Moolenaar25724922009-07-14 15:38:41 +00002616 verbose_leave();
2617 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618 l = fchdir(fd);
2619 close(fd);
2620 }
2621 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002622#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002623 l = mch_chdir((char *)olddir);
2624 if (l != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002625 emsg(_(e_prev_dir));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 }
2627
2628 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002629 if (l >= len - 1)
Bram Moolenaar0f873732019-12-05 20:28:46 +01002630 retval = FAIL; // no space for trailing "/"
Bram Moolenaar38323e42007-03-06 19:22:53 +00002631#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002632 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002633 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002634 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002635#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002636 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002637
Bram Moolenaar0f873732019-12-05 20:28:46 +01002638 // Catch file names which are too long.
Bram Moolenaar78a15312009-05-15 19:33:18 +00002639 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002640 return FAIL;
2641
Bram Moolenaar0f873732019-12-05 20:28:46 +01002642 // Do not append ".", "/dir/." is equal to "/dir".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002643 if (STRCMP(fname, ".") != 0)
2644 STRCAT(buf, fname);
2645
2646 return OK;
2647}
2648
2649/*
2650 * Return TRUE if "fname" does not depend on the current directory.
2651 */
2652 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002653mch_isFullName(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002654{
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002655#ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002656 return ( fname[0] == '/' || fname[0] == '.' ||
2657 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2658 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2659 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002660#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002661 return (*fname == '/' || *fname == '~');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002662#endif
2663}
2664
Bram Moolenaar24552be2005-12-10 20:17:30 +00002665#if defined(USE_FNAME_CASE) || defined(PROTO)
2666/*
2667 * Set the case of the file name, if it already exists. This will cause the
2668 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002669 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002670 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002671 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002672fname_case(
2673 char_u *name,
Bram Moolenaar0f873732019-12-05 20:28:46 +01002674 int len UNUSED) // buffer size, only used when name gets longer
Bram Moolenaar24552be2005-12-10 20:17:30 +00002675{
2676 struct stat st;
2677 char_u *slash, *tail;
2678 DIR *dirp;
2679 struct dirent *dp;
2680
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002681 if (mch_lstat((char *)name, &st) >= 0)
Bram Moolenaar24552be2005-12-10 20:17:30 +00002682 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002683 // Open the directory where the file is located.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002684 slash = vim_strrchr(name, '/');
2685 if (slash == NULL)
2686 {
2687 dirp = opendir(".");
2688 tail = name;
2689 }
2690 else
2691 {
2692 *slash = NUL;
2693 dirp = opendir((char *)name);
2694 *slash = '/';
2695 tail = slash + 1;
2696 }
2697
2698 if (dirp != NULL)
2699 {
2700 while ((dp = readdir(dirp)) != NULL)
2701 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002702 // Only accept names that differ in case and are the same byte
2703 // length. TODO: accept different length name.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002704 if (STRICMP(tail, dp->d_name) == 0
2705 && STRLEN(tail) == STRLEN(dp->d_name))
2706 {
2707 char_u newname[MAXPATHL + 1];
2708 struct stat st2;
2709
Bram Moolenaar0f873732019-12-05 20:28:46 +01002710 // Verify the inode is equal.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002711 vim_strncpy(newname, name, MAXPATHL);
2712 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2713 MAXPATHL - (tail - name));
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002714 if (mch_lstat((char *)newname, &st2) >= 0
Bram Moolenaar24552be2005-12-10 20:17:30 +00002715 && st.st_ino == st2.st_ino
2716 && st.st_dev == st2.st_dev)
2717 {
2718 STRCPY(tail, dp->d_name);
2719 break;
2720 }
2721 }
2722 }
2723
2724 closedir(dirp);
2725 }
2726 }
2727}
2728#endif
2729
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730/*
2731 * Get file permissions for 'name'.
2732 * Returns -1 when it doesn't exist.
2733 */
2734 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002735mch_getperm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002736{
2737 struct stat statb;
2738
Bram Moolenaar0f873732019-12-05 20:28:46 +01002739 // Keep the #ifdef outside of stat(), it may be a macro.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002740#ifdef VMS
2741 if (stat((char *)vms_fixfilename(name), &statb))
2742#else
2743 if (stat((char *)name, &statb))
2744#endif
2745 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002746#ifdef __INTERIX
Bram Moolenaar0f873732019-12-05 20:28:46 +01002747 // The top bit makes the value negative, which means the file doesn't
2748 // exist. Remove the bit, we don't use it.
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002749 return statb.st_mode & ~S_ADDACE;
2750#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002751 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002752#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753}
2754
2755/*
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002756 * Set file permission for "name" to "perm".
2757 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002758 */
2759 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002760mch_setperm(char_u *name, long perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002761{
2762 return (chmod((char *)
2763#ifdef VMS
2764 vms_fixfilename(name),
2765#else
2766 name,
2767#endif
2768 (mode_t)perm) == 0 ? OK : FAIL);
2769}
2770
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002771#if defined(HAVE_FCHMOD) || defined(PROTO)
2772/*
2773 * Set file permission for open file "fd" to "perm".
2774 * Return FAIL for failure, OK otherwise.
2775 */
2776 int
2777mch_fsetperm(int fd, long perm)
2778{
2779 return (fchmod(fd, (mode_t)perm) == 0 ? OK : FAIL);
2780}
2781#endif
2782
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783#if defined(HAVE_ACL) || defined(PROTO)
2784# ifdef HAVE_SYS_ACL_H
2785# include <sys/acl.h>
2786# endif
2787# ifdef HAVE_SYS_ACCESS_H
2788# include <sys/access.h>
2789# endif
2790
2791# ifdef HAVE_SOLARIS_ACL
2792typedef struct vim_acl_solaris_T {
2793 int acl_cnt;
2794 aclent_t *acl_entry;
2795} vim_acl_solaris_T;
2796# endif
2797
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002798#if defined(HAVE_SELINUX) || defined(PROTO)
2799/*
2800 * Copy security info from "from_file" to "to_file".
2801 */
2802 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002803mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002804{
2805 if (from_file == NULL)
2806 return;
2807
2808 if (selinux_enabled == -1)
2809 selinux_enabled = is_selinux_enabled();
2810
2811 if (selinux_enabled > 0)
2812 {
2813 security_context_t from_context = NULL;
2814 security_context_t to_context = NULL;
2815
2816 if (getfilecon((char *)from_file, &from_context) < 0)
2817 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002818 // If the filesystem doesn't support extended attributes,
2819 // the original had no special security context and the
2820 // target cannot have one either.
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002821 if (errno == EOPNOTSUPP)
2822 return;
2823
Bram Moolenaar32526b32019-01-19 17:43:09 +01002824 msg_puts(_("\nCould not get security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002825 msg_outtrans(from_file);
2826 msg_putchar('\n');
2827 return;
2828 }
2829 if (getfilecon((char *)to_file, &to_context) < 0)
2830 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01002831 msg_puts(_("\nCould not get security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002832 msg_outtrans(to_file);
2833 msg_putchar('\n');
2834 freecon (from_context);
2835 return ;
2836 }
2837 if (strcmp(from_context, to_context) != 0)
2838 {
2839 if (setfilecon((char *)to_file, from_context) < 0)
2840 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01002841 msg_puts(_("\nCould not set security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002842 msg_outtrans(to_file);
2843 msg_putchar('\n');
2844 }
2845 }
2846 freecon(to_context);
2847 freecon(from_context);
2848 }
2849}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002850#endif // HAVE_SELINUX
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002851
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002852#if defined(HAVE_SMACK) && !defined(PROTO)
2853/*
2854 * Copy security info from "from_file" to "to_file".
2855 */
2856 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002857mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002858{
Bram Moolenaar62f167f2014-04-23 12:52:40 +02002859 static const char * const smack_copied_attributes[] =
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002860 {
2861 XATTR_NAME_SMACK,
2862 XATTR_NAME_SMACKEXEC,
2863 XATTR_NAME_SMACKMMAP
2864 };
2865
2866 char buffer[SMACK_LABEL_LEN];
2867 const char *name;
2868 int index;
2869 int ret;
2870 ssize_t size;
2871
2872 if (from_file == NULL)
2873 return;
2874
2875 for (index = 0 ; index < (int)(sizeof(smack_copied_attributes)
2876 / sizeof(smack_copied_attributes)[0]) ; index++)
2877 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002878 // get the name of the attribute to copy
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002879 name = smack_copied_attributes[index];
2880
Bram Moolenaar0f873732019-12-05 20:28:46 +01002881 // get the value of the attribute in buffer
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002882 size = getxattr((char*)from_file, name, buffer, sizeof(buffer));
2883 if (size >= 0)
2884 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002885 // copy the attribute value of buffer
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002886 ret = setxattr((char*)to_file, name, buffer, (size_t)size, 0);
2887 if (ret < 0)
2888 {
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002889 vim_snprintf((char *)IObuff, IOSIZE,
2890 _("Could not set security context %s for %s"),
2891 name, to_file);
2892 msg_outtrans(IObuff);
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002893 msg_putchar('\n');
2894 }
2895 }
2896 else
2897 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002898 // what reason of not having the attribute value?
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002899 switch (errno)
2900 {
2901 case ENOTSUP:
Bram Moolenaar0f873732019-12-05 20:28:46 +01002902 // extended attributes aren't supported or enabled
2903 // should a message be echoed? not sure...
2904 return; // leave because it isn't useful to continue
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002905
2906 case ERANGE:
2907 default:
Bram Moolenaar0f873732019-12-05 20:28:46 +01002908 // no enough size OR unexpected error
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002909 vim_snprintf((char *)IObuff, IOSIZE,
2910 _("Could not get security context %s for %s. Removing it!"),
2911 name, from_file);
Bram Moolenaar32526b32019-01-19 17:43:09 +01002912 msg_puts((char *)IObuff);
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002913 msg_putchar('\n');
Bram Moolenaar0f873732019-12-05 20:28:46 +01002914 // FALLTHROUGH to remove the attribute
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002915
2916 case ENODATA:
Bram Moolenaar0f873732019-12-05 20:28:46 +01002917 // no attribute of this name
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002918 ret = removexattr((char*)to_file, name);
Bram Moolenaar0f873732019-12-05 20:28:46 +01002919 // Silently ignore errors, apparently this happens when
2920 // smack is not actually being used.
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002921 break;
2922 }
2923 }
2924 }
2925}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002926#endif // HAVE_SMACK
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002927
Bram Moolenaar071d4272004-06-13 20:20:40 +00002928/*
2929 * Return a pointer to the ACL of file "fname" in allocated memory.
2930 * Return NULL if the ACL is not available for whatever reason.
2931 */
2932 vim_acl_T
Bram Moolenaar05540972016-01-30 20:31:25 +01002933mch_get_acl(char_u *fname UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002934{
2935 vim_acl_T ret = NULL;
2936#ifdef HAVE_POSIX_ACL
2937 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2938#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002939#ifdef HAVE_SOLARIS_ZFS_ACL
2940 acl_t *aclent;
2941
2942 if (acl_get((char *)fname, 0, &aclent) < 0)
2943 return NULL;
2944 ret = (vim_acl_T)aclent;
2945#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946#ifdef HAVE_SOLARIS_ACL
2947 vim_acl_solaris_T *aclent;
2948
2949 aclent = malloc(sizeof(vim_acl_solaris_T));
2950 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2951 {
2952 free(aclent);
2953 return NULL;
2954 }
2955 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2956 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2957 {
2958 free(aclent->acl_entry);
2959 free(aclent);
2960 return NULL;
2961 }
2962 ret = (vim_acl_T)aclent;
2963#else
2964#if defined(HAVE_AIX_ACL)
2965 int aclsize;
2966 struct acl *aclent;
2967
2968 aclsize = sizeof(struct acl);
2969 aclent = malloc(aclsize);
2970 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2971 {
2972 if (errno == ENOSPC)
2973 {
2974 aclsize = aclent->acl_len;
2975 aclent = realloc(aclent, aclsize);
2976 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2977 {
2978 free(aclent);
2979 return NULL;
2980 }
2981 }
2982 else
2983 {
2984 free(aclent);
2985 return NULL;
2986 }
2987 }
2988 ret = (vim_acl_T)aclent;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002989#endif // HAVE_AIX_ACL
2990#endif // HAVE_SOLARIS_ACL
2991#endif // HAVE_SOLARIS_ZFS_ACL
2992#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002993 return ret;
2994}
2995
2996/*
2997 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2998 */
2999 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003000mch_set_acl(char_u *fname UNUSED, vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003001{
3002 if (aclent == NULL)
3003 return;
3004#ifdef HAVE_POSIX_ACL
3005 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
3006#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003007#ifdef HAVE_SOLARIS_ZFS_ACL
3008 acl_set((char *)fname, (acl_t *)aclent);
3009#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010#ifdef HAVE_SOLARIS_ACL
3011 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
3012 ((vim_acl_solaris_T *)aclent)->acl_entry);
3013#else
3014#ifdef HAVE_AIX_ACL
3015 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003016#endif // HAVE_AIX_ACL
3017#endif // HAVE_SOLARIS_ACL
3018#endif // HAVE_SOLARIS_ZFS_ACL
3019#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020}
3021
3022 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003023mch_free_acl(vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003024{
3025 if (aclent == NULL)
3026 return;
3027#ifdef HAVE_POSIX_ACL
3028 acl_free((acl_t)aclent);
3029#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003030#ifdef HAVE_SOLARIS_ZFS_ACL
3031 acl_free((acl_t *)aclent);
3032#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003033#ifdef HAVE_SOLARIS_ACL
3034 free(((vim_acl_solaris_T *)aclent)->acl_entry);
3035 free(aclent);
3036#else
3037#ifdef HAVE_AIX_ACL
3038 free(aclent);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003039#endif // HAVE_AIX_ACL
3040#endif // HAVE_SOLARIS_ACL
3041#endif // HAVE_SOLARIS_ZFS_ACL
3042#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003043}
3044#endif
3045
3046/*
3047 * Set hidden flag for "name".
3048 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003050mch_hide(char_u *name UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051{
Bram Moolenaar0f873732019-12-05 20:28:46 +01003052 // can't hide a file
Bram Moolenaar071d4272004-06-13 20:20:40 +00003053}
3054
3055/*
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003056 * return TRUE if "name" is a directory or a symlink to a directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057 * return FALSE if "name" is not a directory
3058 * return FALSE for error
3059 */
3060 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003061mch_isdir(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062{
3063 struct stat statb;
3064
Bram Moolenaar0f873732019-12-05 20:28:46 +01003065 if (*name == NUL) // Some stat()s don't flag "" as an error.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066 return FALSE;
3067 if (stat((char *)name, &statb))
3068 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003070}
3071
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003072/*
3073 * return TRUE if "name" is a directory, NOT a symlink to a directory
3074 * return FALSE if "name" is not a directory
3075 * return FALSE for error
3076 */
3077 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003078mch_isrealdir(char_u *name)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003079{
3080 struct stat statb;
3081
Bram Moolenaar0f873732019-12-05 20:28:46 +01003082 if (*name == NUL) // Some stat()s don't flag "" as an error.
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003083 return FALSE;
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01003084 if (mch_lstat((char *)name, &statb))
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003085 return FALSE;
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003086 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003087}
3088
Bram Moolenaar071d4272004-06-13 20:20:40 +00003089/*
3090 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
3091 */
3092 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003093executable_file(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094{
3095 struct stat st;
3096
3097 if (stat((char *)name, &st))
3098 return 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003099#ifdef VMS
Bram Moolenaar0f873732019-12-05 20:28:46 +01003100 // Like on Unix system file can have executable rights but not necessarily
3101 // be an executable, but on Unix is not a default for an ordinary file to
3102 // have an executable flag - on VMS it is in most cases.
3103 // Therefore, this check does not have any sense - let keep us to the
3104 // conventions instead:
3105 // *.COM and *.EXE files are the executables - the rest are not. This is
3106 // not ideal but better then it was.
Bram Moolenaar206f0112014-03-12 16:51:55 +01003107 int vms_executable = 0;
3108 if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
3109 {
3110 if (strstr(vms_tolower((char*)name),".exe") != NULL
3111 || strstr(vms_tolower((char*)name),".com")!= NULL)
3112 vms_executable = 1;
3113 }
3114 return vms_executable;
3115#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003117#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003118}
3119
3120/*
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01003121 * Return TRUE if "name" can be found in $PATH and executed, FALSE if not.
Bram Moolenaarb5971142015-03-21 17:32:19 +01003122 * If "use_path" is FALSE only check if "name" is executable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003123 * Return -1 if unknown.
3124 */
3125 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003126mch_can_exe(char_u *name, char_u **path, int use_path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003127{
3128 char_u *buf;
3129 char_u *p, *e;
3130 int retval;
3131
Bram Moolenaar0f873732019-12-05 20:28:46 +01003132 // When "use_path" is false and if it's an absolute or relative path don't
3133 // need to use $PATH.
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003134 if (!use_path || gettail(name) != name)
Bram Moolenaar206f0112014-03-12 16:51:55 +01003135 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003136 // There must be a path separator, files in the current directory
3137 // can't be executed.
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003138 if ((use_path || gettail(name) != name) && executable_file(name))
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003139 {
3140 if (path != NULL)
3141 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003142 if (name[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003143 *path = FullName_save(name, TRUE);
3144 else
3145 *path = vim_strsave(name);
3146 }
3147 return TRUE;
3148 }
3149 return FALSE;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003150 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151
3152 p = (char_u *)getenv("PATH");
3153 if (p == NULL || *p == NUL)
3154 return -1;
Bram Moolenaar964b3742019-05-24 18:54:09 +02003155 buf = alloc(STRLEN(name) + STRLEN(p) + 2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003156 if (buf == NULL)
3157 return -1;
3158
3159 /*
3160 * Walk through all entries in $PATH to check if "name" exists there and
3161 * is an executable file.
3162 */
3163 for (;;)
3164 {
3165 e = (char_u *)strchr((char *)p, ':');
3166 if (e == NULL)
3167 e = p + STRLEN(p);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003168 if (e - p <= 1) // empty entry means current dir
Bram Moolenaar071d4272004-06-13 20:20:40 +00003169 STRCPY(buf, "./");
3170 else
3171 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003172 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003173 add_pathsep(buf);
3174 }
3175 STRCAT(buf, name);
3176 retval = executable_file(buf);
3177 if (retval == 1)
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003178 {
3179 if (path != NULL)
3180 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003181 if (buf[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003182 *path = FullName_save(buf, TRUE);
3183 else
3184 *path = vim_strsave(buf);
3185 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 break;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003187 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003188
3189 if (*e != ':')
3190 break;
3191 p = e + 1;
3192 }
3193
3194 vim_free(buf);
3195 return retval;
3196}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197
3198/*
3199 * Check what "name" is:
3200 * NODE_NORMAL: file or directory (or doesn't exist)
3201 * NODE_WRITABLE: writable device, socket, fifo, etc.
3202 * NODE_OTHER: non-writable things
3203 */
3204 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003205mch_nodetype(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003206{
3207 struct stat st;
3208
3209 if (stat((char *)name, &st))
3210 return NODE_NORMAL;
3211 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3212 return NODE_NORMAL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003213 if (S_ISBLK(st.st_mode)) // block device isn't writable
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214 return NODE_OTHER;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003215 // Everything else is writable?
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216 return NODE_WRITABLE;
3217}
3218
3219 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003220mch_early_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221{
3222#ifdef HAVE_CHECK_STACK_GROWTH
3223 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003224
Bram Moolenaar071d4272004-06-13 20:20:40 +00003225 check_stack_growth((char *)&i);
3226
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003227# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228 get_stack_limit();
3229# endif
3230
3231#endif
3232
3233 /*
3234 * Setup an alternative stack for signals. Helps to catch signals when
3235 * running out of stack space.
3236 * Use of sigaltstack() is preferred, it's more portable.
3237 * Ignore any errors.
3238 */
3239#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003240 signal_stack = alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241 init_signal_stack();
3242#endif
3243}
3244
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003245#if defined(EXITFREE) || defined(PROTO)
3246 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003247mch_free_mem(void)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003248{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003249# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3250 if (clip_star.owned)
3251 clip_lose_selection(&clip_star);
3252 if (clip_plus.owned)
3253 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003254# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003255# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003256 if (xterm_Shell != (Widget)0)
3257 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003258# ifndef LESSTIF_VERSION
Bram Moolenaar0f873732019-12-05 20:28:46 +01003259 // Lesstif crashes here, lose some memory
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003260 if (xterm_dpy != NULL)
3261 XtCloseDisplay(xterm_dpy);
3262 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003263 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003264 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003265# ifdef FEAT_X11
Bram Moolenaar0f873732019-12-05 20:28:46 +01003266 x11_display = NULL; // freed by XtDestroyApplicationContext()
Bram Moolenaare8208012008-06-20 09:59:25 +00003267# endif
3268 }
3269# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003270# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003271# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003272 if (x11_display != NULL
3273# ifdef FEAT_XCLIPBOARD
3274 && x11_display != xterm_dpy
3275# endif
3276 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003277 XCloseDisplay(x11_display);
3278# endif
3279# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaard23a8232018-02-10 18:45:26 +01003280 VIM_CLEAR(signal_stack);
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003281# endif
3282# ifdef FEAT_TITLE
3283 vim_free(oldtitle);
3284 vim_free(oldicon);
3285# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003286}
3287#endif
3288
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289/*
3290 * Output a newline when exiting.
3291 * Make sure the newline goes to the same stream as the text.
3292 */
3293 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003294exit_scroll(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003296 if (silent_mode)
3297 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298 if (newline_on_exit || msg_didout)
3299 {
3300 if (msg_use_printf())
3301 {
3302 if (info_message)
3303 mch_msg("\n");
3304 else
3305 mch_errmsg("\r\n");
3306 }
3307 else
3308 out_char('\n');
3309 }
3310 else
3311 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003312 restore_cterm_colors(); // get original colors back
3313 msg_clr_eos_force(); // clear the rest of the display
3314 windgoto((int)Rows - 1, 0); // may have moved the cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00003315 }
3316}
3317
Bram Moolenaarb4151682020-05-11 22:13:28 +02003318#ifdef USE_GCOV_FLUSH
3319extern void __gcov_flush();
3320#endif
3321
Bram Moolenaar071d4272004-06-13 20:20:40 +00003322 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003323mch_exit(int r)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324{
3325 exiting = TRUE;
3326
3327#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3328 x11_export_final_selection();
3329#endif
3330
3331#ifdef FEAT_GUI
3332 if (!gui.in_use)
3333#endif
3334 {
3335 settmode(TMODE_COOK);
3336#ifdef FEAT_TITLE
Bram Moolenaar40385db2018-08-07 22:31:44 +02003337 // restore xterm title and icon name
3338 mch_restore_title(SAVE_RESTORE_BOTH);
3339 term_pop_title(SAVE_RESTORE_BOTH);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340#endif
3341 /*
3342 * When t_ti is not empty but it doesn't cause swapping terminal
3343 * pages, need to output a newline when msg_didout is set. But when
3344 * t_ti does swap pages it should not go to the shell page. Do this
3345 * before stoptermcap().
3346 */
3347 if (swapping_screen() && !newline_on_exit)
3348 exit_scroll();
3349
Bram Moolenaar0f873732019-12-05 20:28:46 +01003350 // Stop termcap: May need to check for T_CRV response, which
3351 // requires RAW mode.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003352 stoptermcap();
3353
3354 /*
3355 * A newline is only required after a message in the alternate screen.
3356 * This is set to TRUE by wait_return().
3357 */
3358 if (!swapping_screen() || newline_on_exit)
3359 exit_scroll();
3360
Bram Moolenaar0f873732019-12-05 20:28:46 +01003361 // Cursor may have been switched off without calling starttermcap()
3362 // when doing "vim -u vimrc" and vimrc contains ":q".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363 if (full_screen)
3364 cursor_on();
3365 }
3366 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01003367 ml_close_all(TRUE); // remove all memfiles
Bram Moolenaarb4151682020-05-11 22:13:28 +02003368
3369#ifdef USE_GCOV_FLUSH
3370 // Flush coverage info before possibly being killed by a deadly signal.
3371 __gcov_flush();
3372#endif
3373
Bram Moolenaar071d4272004-06-13 20:20:40 +00003374 may_core_dump();
3375#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003376 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377 gui_exit(r);
3378#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003379
Bram Moolenaar56718732006-03-15 22:53:57 +00003380#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003381 mac_conv_cleanup();
3382#endif
3383
Bram Moolenaar071d4272004-06-13 20:20:40 +00003384#ifdef __QNX__
Bram Moolenaar0f873732019-12-05 20:28:46 +01003385 // A core dump won't be created if the signal handler
3386 // doesn't return, so we can't call exit()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003387 if (deadly_signal != 0)
3388 return;
3389#endif
3390
Bram Moolenaar009b2592004-10-24 19:18:58 +00003391#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003392 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003393#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003394
3395#ifdef EXITFREE
3396 free_all_mem();
3397#endif
3398
Bram Moolenaar071d4272004-06-13 20:20:40 +00003399 exit(r);
3400}
3401
3402 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003403may_core_dump(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003404{
3405 if (deadly_signal != 0)
3406 {
3407 signal(deadly_signal, SIG_DFL);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003408 kill(getpid(), deadly_signal); // Die using the signal we caught
Bram Moolenaar071d4272004-06-13 20:20:40 +00003409 }
3410}
3411
3412#ifndef VMS
3413
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003414/*
3415 * Get the file descriptor to use for tty operations.
3416 */
3417 static int
3418get_tty_fd(int fd)
3419{
3420 int tty_fd = fd;
3421
3422#if defined(HAVE_SVR4_PTYS) && defined(SUN_SYSTEM)
3423 // On SunOS: Get the terminal parameters from "fd", or the slave device of
3424 // "fd" when it is a master device.
3425 if (mch_isatty(fd) > 1)
3426 {
3427 char *name;
3428
3429 name = ptsname(fd);
3430 if (name == NULL)
3431 return -1;
3432
3433 tty_fd = open(name, O_RDONLY | O_NOCTTY | O_EXTRA, 0);
3434 if (tty_fd < 0)
3435 return -1;
3436 }
3437#endif
3438 return tty_fd;
3439}
3440
3441 static int
3442mch_tcgetattr(int fd, void *term)
3443{
3444 int tty_fd;
3445 int retval = -1;
3446
3447 tty_fd = get_tty_fd(fd);
3448 if (tty_fd >= 0)
3449 {
3450#ifdef NEW_TTY_SYSTEM
3451# ifdef HAVE_TERMIOS_H
3452 retval = tcgetattr(tty_fd, (struct termios *)term);
3453# else
3454 retval = ioctl(tty_fd, TCGETA, (struct termio *)term);
3455# endif
3456#else
3457 // for "old" tty systems
3458 retval = ioctl(tty_fd, TIOCGETP, (struct sgttyb *)term);
3459#endif
3460 if (tty_fd != fd)
3461 close(tty_fd);
3462 }
3463 return retval;
3464}
3465
Bram Moolenaar071d4272004-06-13 20:20:40 +00003466 void
Bram Moolenaar26e86442020-05-17 14:06:16 +02003467mch_settmode(tmode_T tmode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003468{
3469 static int first = TRUE;
3470
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003471#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003472# ifdef HAVE_TERMIOS_H
3473 static struct termios told;
3474 struct termios tnew;
3475# else
3476 static struct termio told;
3477 struct termio tnew;
3478# endif
3479
3480 if (first)
3481 {
3482 first = FALSE;
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003483 mch_tcgetattr(read_cmd_fd, &told);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484 }
3485
3486 tnew = told;
3487 if (tmode == TMODE_RAW)
3488 {
3489 /*
3490 * ~ICRNL enables typing ^V^M
3491 */
3492 tnew.c_iflag &= ~ICRNL;
3493 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3494# if defined(IEXTEN) && !defined(__MINT__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01003495 | IEXTEN // IEXTEN enables typing ^V on SOLARIS
3496 // but it breaks function keys on MINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003497# endif
3498 );
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003499# ifdef ONLCR
3500 // Don't map NL -> CR NL, we do it ourselves.
3501 // Also disable expanding tabs if possible.
3502# ifdef XTABS
3503 tnew.c_oflag &= ~(ONLCR | XTABS);
3504# else
3505# ifdef TAB3
3506 tnew.c_oflag &= ~(ONLCR | TAB3);
3507# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003508 tnew.c_oflag &= ~ONLCR;
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003509# endif
3510# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511# endif
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003512 tnew.c_cc[VMIN] = 1; // return after 1 char
3513 tnew.c_cc[VTIME] = 0; // don't wait
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514 }
3515 else if (tmode == TMODE_SLEEP)
Bram Moolenaar40de4562016-07-01 15:03:46 +02003516 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003517 // Also reset ICANON here, otherwise on Solaris select() won't see
3518 // typeahead characters.
Bram Moolenaar40de4562016-07-01 15:03:46 +02003519 tnew.c_lflag &= ~(ICANON | ECHO);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003520 tnew.c_cc[VMIN] = 1; // return after 1 char
3521 tnew.c_cc[VTIME] = 0; // don't wait
Bram Moolenaar40de4562016-07-01 15:03:46 +02003522 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003523
3524# if defined(HAVE_TERMIOS_H)
3525 {
3526 int n = 10;
3527
Bram Moolenaar0f873732019-12-05 20:28:46 +01003528 // A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3529 // few times.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003530 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3531 && errno == EINTR && n > 0)
3532 --n;
3533 }
3534# else
3535 ioctl(read_cmd_fd, TCSETA, &tnew);
3536# endif
3537
3538#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003539 /*
3540 * for "old" tty systems
3541 */
3542# ifndef TIOCSETN
Bram Moolenaar0f873732019-12-05 20:28:46 +01003543# define TIOCSETN TIOCSETP // for hpux 9.0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003544# endif
3545 static struct sgttyb ttybold;
3546 struct sgttyb ttybnew;
3547
3548 if (first)
3549 {
3550 first = FALSE;
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003551 mch_tcgetattr(read_cmd_fd, &ttybold);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552 }
3553
3554 ttybnew = ttybold;
3555 if (tmode == TMODE_RAW)
3556 {
3557 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3558 ttybnew.sg_flags |= RAW;
3559 }
3560 else if (tmode == TMODE_SLEEP)
3561 ttybnew.sg_flags &= ~(ECHO);
3562 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3563#endif
Bram Moolenaar26e86442020-05-17 14:06:16 +02003564 mch_cur_tmode = tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565}
3566
3567/*
3568 * Try to get the code for "t_kb" from the stty setting
3569 *
3570 * Even if termcap claims a backspace key, the user's setting *should*
3571 * prevail. stty knows more about reality than termcap does, and if
3572 * somebody's usual erase key is DEL (which, for most BSD users, it will
3573 * be), they're going to get really annoyed if their erase key starts
3574 * doing forward deletes for no reason. (Eric Fischer)
3575 */
3576 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003577get_stty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578{
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003579 ttyinfo_T info;
3580 char_u buf[2];
3581 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003582
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003583 if (get_tty_info(read_cmd_fd, &info) == OK)
3584 {
3585 intr_char = info.interrupt;
3586 buf[0] = info.backspace;
3587 buf[1] = NUL;
3588 add_termcode((char_u *)"kb", buf, FALSE);
3589
Bram Moolenaar0f873732019-12-05 20:28:46 +01003590 // If <BS> and <DEL> are now the same, redefine <DEL>.
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003591 p = find_termcode((char_u *)"kD");
3592 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3593 do_fixdel(NULL);
3594 }
3595}
3596
3597/*
3598 * Obtain the characters that Backspace and Enter produce on "fd".
3599 * Returns OK or FAIL.
3600 */
3601 int
3602get_tty_info(int fd, ttyinfo_T *info)
3603{
3604#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003605# ifdef HAVE_TERMIOS_H
3606 struct termios keys;
3607# else
3608 struct termio keys;
3609# endif
3610
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003611 if (mch_tcgetattr(fd, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003612 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003613 info->backspace = keys.c_cc[VERASE];
3614 info->interrupt = keys.c_cc[VINTR];
3615 if (keys.c_iflag & ICRNL)
3616 info->enter = NL;
3617 else
3618 info->enter = CAR;
3619 if (keys.c_oflag & ONLCR)
3620 info->nl_does_cr = TRUE;
3621 else
3622 info->nl_does_cr = FALSE;
3623 return OK;
3624 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003625#else
Bram Moolenaar0f873732019-12-05 20:28:46 +01003626 // for "old" tty systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00003627 struct sgttyb keys;
3628
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003629 if (mch_tcgetattr(fd, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003630 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003631 info->backspace = keys.sg_erase;
3632 info->interrupt = keys.sg_kill;
3633 info->enter = CAR;
3634 info->nl_does_cr = TRUE;
3635 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003636 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003637#endif
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003638 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003639}
3640
Bram Moolenaar0f873732019-12-05 20:28:46 +01003641#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00003642
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003643static int mouse_ison = FALSE;
3644
Bram Moolenaar071d4272004-06-13 20:20:40 +00003645/*
3646 * Set mouse clicks on or off.
3647 */
3648 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003649mch_setmouse(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003650{
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003651#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003652 static int bevalterm_ison = FALSE;
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003653#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003654 int xterm_mouse_vers;
3655
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003656#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaara06afc72018-08-27 23:24:16 +02003657 if (!on)
3658 // Make sure not tracing mouse movements. Important when a button-down
3659 // was received but no release yet.
3660 stop_xterm_trace();
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003661#endif
Bram Moolenaara06afc72018-08-27 23:24:16 +02003662
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003663 if (on == mouse_ison
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003664#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003665 && p_bevalterm == bevalterm_ison
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003666#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003667 )
Bram Moolenaar0f873732019-12-05 20:28:46 +01003668 // return quickly if nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669 return;
3670
3671 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003672
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003673#ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003674 if (ttym_flags == TTYM_URXVT)
3675 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003676 out_str_nf((char_u *)
3677 (on
3678 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3679 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003680 mouse_ison = on;
Bram Moolenaarc8427482011-10-20 21:09:35 +02003681 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003682#endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003683
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003684 if (ttym_flags == TTYM_SGR)
3685 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003686 // SGR mode supports columns above 223
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003687 out_str_nf((char_u *)
3688 (on
3689 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3690 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003691 mouse_ison = on;
3692 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003693
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003694#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003695 if (bevalterm_ison != (p_bevalterm && on))
3696 {
3697 bevalterm_ison = (p_bevalterm && on);
3698 if (xterm_mouse_vers > 1 && !bevalterm_ison)
Bram Moolenaar0f873732019-12-05 20:28:46 +01003699 // disable mouse movement events, enabling is below
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003700 out_str_nf((char_u *)
3701 (IF_EB("\033[?1003l", ESC_STR "[?1003l")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003702 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003703#endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003704
Bram Moolenaar071d4272004-06-13 20:20:40 +00003705 if (xterm_mouse_vers > 0)
3706 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003707 if (on) // enable mouse events, use mouse tracking if available
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708 out_str_nf((char_u *)
3709 (xterm_mouse_vers > 1
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003710 ? (
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003711#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003712 bevalterm_ison
3713 ? IF_EB("\033[?1003h", ESC_STR "[?1003h") :
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003714#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003715 IF_EB("\033[?1002h", ESC_STR "[?1002h"))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
Bram Moolenaar0f873732019-12-05 20:28:46 +01003717 else // disable mouse events, could probably always send the same
Bram Moolenaar071d4272004-06-13 20:20:40 +00003718 out_str_nf((char_u *)
3719 (xterm_mouse_vers > 1
3720 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3721 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003722 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003723 }
3724
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003725#ifdef FEAT_MOUSE_DEC
Bram Moolenaar071d4272004-06-13 20:20:40 +00003726 else if (ttym_flags == TTYM_DEC)
3727 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003728 if (on) // enable mouse events
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
Bram Moolenaar0f873732019-12-05 20:28:46 +01003730 else // disable mouse events
Bram Moolenaar071d4272004-06-13 20:20:40 +00003731 out_str_nf((char_u *)"\033['z");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003732 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003733 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003734#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003735
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003736#ifdef FEAT_MOUSE_GPM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737 else
3738 {
3739 if (on)
3740 {
3741 if (gpm_open())
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003742 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003743 }
3744 else
3745 {
3746 gpm_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003747 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003748 }
3749 }
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_SYSMOUSE
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003753 else
3754 {
3755 if (on)
3756 {
3757 if (sysmouse_open() == OK)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003758 mouse_ison = TRUE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003759 }
3760 else
3761 {
3762 sysmouse_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003763 mouse_ison = FALSE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003764 }
3765 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003766#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003767
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003768#ifdef FEAT_MOUSE_JSB
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769 else
3770 {
3771 if (on)
3772 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003773 // D - Enable Mouse up/down messages
3774 // L - Enable Left Button Reporting
3775 // M - Enable Middle Button Reporting
3776 // R - Enable Right Button Reporting
3777 // K - Enable SHIFT and CTRL key Reporting
3778 // + - Enable Advanced messaging of mouse moves and up/down messages
3779 // Q - Quiet No Ack
3780 // # - Numeric value of mouse pointer required
3781 // 0 = Multiview 2000 cursor, used as standard
3782 // 1 = Windows Arrow
3783 // 2 = Windows I Beam
3784 // 3 = Windows Hour Glass
3785 // 4 = Windows Cross Hair
3786 // 5 = Windows UP Arrow
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003787# ifdef JSBTERM_MOUSE_NONADVANCED
Bram Moolenaar0f873732019-12-05 20:28:46 +01003788 // Disables full feedback of pointer movements
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3790 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003791# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003792 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3793 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003794# endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003795 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003796 }
3797 else
3798 {
3799 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3800 ESC_STR "[0~ZwQ" ESC_STR "\\"));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003801 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802 }
3803 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003804#endif
3805#ifdef FEAT_MOUSE_PTERM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003806 else
3807 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003808 // 1 = button press, 6 = release, 7 = drag, 1h...9l = right button
Bram Moolenaar071d4272004-06-13 20:20:40 +00003809 if (on)
3810 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3811 else
3812 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003813 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003815#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003816}
3817
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003818#if defined(FEAT_BEVAL_TERM) || defined(PROTO)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003819/*
3820 * Called when 'balloonevalterm' changed.
3821 */
3822 void
3823mch_bevalterm_changed(void)
3824{
3825 mch_setmouse(mouse_ison);
3826}
3827#endif
3828
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829/*
3830 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3831 */
3832 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003833check_mouse_termcode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003834{
3835# ifdef FEAT_MOUSE_XTERM
3836 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003837# ifdef FEAT_MOUSE_URXVT
3838 && use_xterm_mouse() != 3
3839# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003840# ifdef FEAT_GUI
3841 && !gui.in_use
3842# endif
3843 )
3844 {
3845 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003846 ? IF_EB("\233M", CSI_STR "M")
3847 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003848 if (*p_mouse != NUL)
3849 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003850 // force mouse off and maybe on to send possibly new mouse
3851 // activation sequence to the xterm, with(out) drag tracing.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003852 mch_setmouse(FALSE);
3853 setmouse();
3854 }
3855 }
3856 else
3857 del_mouse_termcode(KS_MOUSE);
3858# endif
3859
3860# ifdef FEAT_MOUSE_GPM
3861 if (!use_xterm_mouse()
3862# ifdef FEAT_GUI
3863 && !gui.in_use
3864# endif
3865 )
Bram Moolenaarbedf0912019-05-04 16:58:45 +02003866 set_mouse_termcode(KS_GPM_MOUSE,
3867 (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3868 else
3869 del_mouse_termcode(KS_GPM_MOUSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003870# endif
3871
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003872# ifdef FEAT_SYSMOUSE
3873 if (!use_xterm_mouse()
3874# ifdef FEAT_GUI
3875 && !gui.in_use
3876# endif
3877 )
3878 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3879# endif
3880
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881# ifdef FEAT_MOUSE_JSB
Bram Moolenaar0f873732019-12-05 20:28:46 +01003882 // Conflicts with xterm mouse: "\033[" and "\033[M" ???
Bram Moolenaar071d4272004-06-13 20:20:40 +00003883 if (!use_xterm_mouse()
3884# ifdef FEAT_GUI
3885 && !gui.in_use
3886# endif
3887 )
3888 set_mouse_termcode(KS_JSBTERM_MOUSE,
3889 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3890 else
3891 del_mouse_termcode(KS_JSBTERM_MOUSE);
3892# endif
3893
3894# ifdef FEAT_MOUSE_NET
Bram Moolenaar0f873732019-12-05 20:28:46 +01003895 // There is no conflict, but one may type "ESC }" from Insert mode. Don't
3896 // define it in the GUI or when using an xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003897 if (!use_xterm_mouse()
3898# ifdef FEAT_GUI
3899 && !gui.in_use
3900# endif
3901 )
3902 set_mouse_termcode(KS_NETTERM_MOUSE,
3903 (char_u *)IF_EB("\033}", ESC_STR "}"));
3904 else
3905 del_mouse_termcode(KS_NETTERM_MOUSE);
3906# endif
3907
3908# ifdef FEAT_MOUSE_DEC
Bram Moolenaar0f873732019-12-05 20:28:46 +01003909 // Conflicts with xterm mouse: "\033[" and "\033[M"
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003910 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003911# ifdef FEAT_GUI
3912 && !gui.in_use
3913# endif
3914 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003915 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3916 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003917 else
3918 del_mouse_termcode(KS_DEC_MOUSE);
3919# endif
3920# ifdef FEAT_MOUSE_PTERM
Bram Moolenaar0f873732019-12-05 20:28:46 +01003921 // same conflict as the dec mouse
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003922 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003923# ifdef FEAT_GUI
3924 && !gui.in_use
3925# endif
3926 )
3927 set_mouse_termcode(KS_PTERM_MOUSE,
3928 (char_u *) IF_EB("\033[", ESC_STR "["));
3929 else
3930 del_mouse_termcode(KS_PTERM_MOUSE);
3931# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003932# ifdef FEAT_MOUSE_URXVT
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003933 if (use_xterm_mouse() == 3
Bram Moolenaarc8427482011-10-20 21:09:35 +02003934# ifdef FEAT_GUI
3935 && !gui.in_use
3936# endif
3937 )
3938 {
3939 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02003940 ? IF_EB("\233*M", CSI_STR "*M")
3941 : IF_EB("\033[*M", ESC_STR "[*M")));
Bram Moolenaarc8427482011-10-20 21:09:35 +02003942
3943 if (*p_mouse != NUL)
3944 {
3945 mch_setmouse(FALSE);
3946 setmouse();
3947 }
3948 }
3949 else
3950 del_mouse_termcode(KS_URXVT_MOUSE);
3951# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003952 if (use_xterm_mouse() == 4
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003953# ifdef FEAT_GUI
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003954 && !gui.in_use
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003955# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003956 )
3957 {
3958 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02003959 ? IF_EB("\233<*M", CSI_STR "<*M")
3960 : IF_EB("\033[<*M", ESC_STR "[<*M")));
3961
3962 set_mouse_termcode(KS_SGR_MOUSE_RELEASE, (char_u *)(term_is_8bit(T_NAME)
3963 ? IF_EB("\233<*m", CSI_STR "<*m")
3964 : IF_EB("\033[<*m", ESC_STR "[<*m")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003965
3966 if (*p_mouse != NUL)
3967 {
3968 mch_setmouse(FALSE);
3969 setmouse();
3970 }
3971 }
3972 else
Bram Moolenaara529ce02017-06-22 22:37:57 +02003973 {
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003974 del_mouse_termcode(KS_SGR_MOUSE);
Bram Moolenaara529ce02017-06-22 22:37:57 +02003975 del_mouse_termcode(KS_SGR_MOUSE_RELEASE);
3976 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003977}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003978
Bram Moolenaar071d4272004-06-13 20:20:40 +00003979#ifndef VMS
3980
3981/*
3982 * Try to get the current window size:
3983 * 1. with an ioctl(), most accurate method
3984 * 2. from the environment variables LINES and COLUMNS
3985 * 3. from the termcap
3986 * 4. keep using the old values
3987 * Return OK when size could be determined, FAIL otherwise.
3988 */
3989 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003990mch_get_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003991{
3992 long rows = 0;
3993 long columns = 0;
3994 char_u *p;
3995
3996 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003997 * 1. try using an ioctl. It is the most accurate method.
3998 *
3999 * Try using TIOCGWINSZ first, some systems that have it also define
4000 * TIOCGSIZE but don't have a struct ttysize.
4001 */
4002# ifdef TIOCGWINSZ
4003 {
4004 struct winsize ws;
4005 int fd = 1;
4006
Bram Moolenaar0f873732019-12-05 20:28:46 +01004007 // When stdout is not a tty, use stdin for the ioctl().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004008 if (!isatty(fd) && isatty(read_cmd_fd))
4009 fd = read_cmd_fd;
4010 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
4011 {
4012 columns = ws.ws_col;
4013 rows = ws.ws_row;
4014 }
4015 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004016# else // TIOCGWINSZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00004017# ifdef TIOCGSIZE
4018 {
4019 struct ttysize ts;
4020 int fd = 1;
4021
Bram Moolenaar0f873732019-12-05 20:28:46 +01004022 // When stdout is not a tty, use stdin for the ioctl().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023 if (!isatty(fd) && isatty(read_cmd_fd))
4024 fd = read_cmd_fd;
4025 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
4026 {
4027 columns = ts.ts_cols;
4028 rows = ts.ts_lines;
4029 }
4030 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004031# endif // TIOCGSIZE
4032# endif // TIOCGWINSZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00004033
4034 /*
4035 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004036 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
4037 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004038 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004039 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040 {
4041 if ((p = (char_u *)getenv("LINES")))
4042 rows = atoi((char *)p);
4043 if ((p = (char_u *)getenv("COLUMNS")))
4044 columns = atoi((char *)p);
4045 }
4046
4047#ifdef HAVE_TGETENT
4048 /*
4049 * 3. try reading "co" and "li" entries from termcap
4050 */
4051 if (columns == 0 || rows == 0)
4052 getlinecol(&columns, &rows);
4053#endif
4054
4055 /*
4056 * 4. If everything fails, use the old values
4057 */
4058 if (columns <= 0 || rows <= 0)
4059 return FAIL;
4060
4061 Rows = rows;
4062 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02004063 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004064 return OK;
4065}
4066
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004067#if defined(FEAT_TERMINAL) || defined(PROTO)
4068/*
4069 * Report the windows size "rows" and "cols" to tty "fd".
4070 */
4071 int
4072mch_report_winsize(int fd, int rows, int cols)
4073{
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004074 int tty_fd;
4075 int retval = -1;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004076
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004077 tty_fd = get_tty_fd(fd);
4078 if (tty_fd >= 0)
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004079 {
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004080# if defined(TIOCSWINSZ)
4081 struct winsize ws;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004082
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004083 ws.ws_col = cols;
4084 ws.ws_row = rows;
4085 ws.ws_xpixel = cols * 5;
4086 ws.ws_ypixel = rows * 10;
4087 retval = ioctl(tty_fd, TIOCSWINSZ, &ws);
4088 ch_log(NULL, "ioctl(TIOCSWINSZ) %s",
4089 retval == 0 ? "success" : "failed");
4090# elif defined(TIOCSSIZE)
4091 struct ttysize ts;
4092
4093 ts.ts_cols = cols;
4094 ts.ts_lines = rows;
4095 retval = ioctl(tty_fd, TIOCSSIZE, &ts);
4096 ch_log(NULL, "ioctl(TIOCSSIZE) %s",
4097 retval == 0 ? "success" : "failed");
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004098# endif
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004099 if (tty_fd != fd)
4100 close(tty_fd);
4101 }
4102 return retval == 0 ? OK : FAIL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004103}
4104#endif
4105
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106/*
4107 * Try to set the window size to Rows and Columns.
4108 */
4109 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004110mch_set_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004111{
4112 if (*T_CWS)
4113 {
4114 /*
4115 * NOTE: if you get an error here that term_set_winsize() is
4116 * undefined, check the output of configure. It could probably not
4117 * find a ncurses, termcap or termlib library.
4118 */
4119 term_set_winsize((int)Rows, (int)Columns);
4120 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01004121 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122 }
4123}
4124
Bram Moolenaar0f873732019-12-05 20:28:46 +01004125#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126
4127/*
4128 * Rows and/or Columns has changed.
4129 */
4130 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004131mch_new_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004132{
Bram Moolenaar0f873732019-12-05 20:28:46 +01004133 // Nothing to do.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004134}
4135
Bram Moolenaar205b8862011-09-07 15:04:31 +02004136/*
4137 * Wait for process "child" to end.
4138 * Return "child" if it exited properly, <= 0 on error.
4139 */
4140 static pid_t
Bram Moolenaar05540972016-01-30 20:31:25 +01004141wait4pid(pid_t child, waitstatus *status)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004142{
4143 pid_t wait_pid = 0;
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004144 long delay_msec = 1;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004145
4146 while (wait_pid != child)
4147 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004148 // When compiled with Python threads are probably used, in which case
4149 // wait() sometimes hangs for no obvious reason. Use waitpid()
4150 // instead and loop (like the GUI). Also needed for other interfaces,
4151 // they might call system().
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004152# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004153 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004154# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02004155 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004156# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02004157 if (wait_pid == 0)
4158 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004159 // Wait for 1 to 10 msec before trying again.
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004160 mch_delay(delay_msec, TRUE);
4161 if (++delay_msec > 10)
4162 delay_msec = 10;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004163 continue;
4164 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004165 if (wait_pid <= 0
4166# ifdef ECHILD
4167 && errno == ECHILD
4168# endif
4169 )
4170 break;
4171 }
4172 return wait_pid;
4173}
4174
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01004175#if !defined(USE_SYSTEM) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar7da34602017-08-01 17:14:21 +02004176/*
4177 * Set the environment for a child process.
4178 */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004179 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004180set_child_environment(
4181 long rows,
4182 long columns,
4183 char *term,
4184 int is_terminal UNUSED)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004185{
4186# ifdef HAVE_SETENV
4187 char envbuf[50];
4188# else
Bram Moolenaar5f7e7bd2017-07-22 14:08:43 +02004189 static char envbuf_Term[30];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004190 static char envbuf_Rows[20];
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004191 static char envbuf_Lines[20];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004192 static char envbuf_Columns[20];
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004193 static char envbuf_Colors[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004194# ifdef FEAT_TERMINAL
Bram Moolenaard7a137f2018-06-12 18:05:24 +02004195 static char envbuf_Version[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004196# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004197# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004198 static char envbuf_Servername[60];
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004199# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004200# endif
4201
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004202# ifdef HAVE_SETENV
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004203 setenv("TERM", term, 1);
4204 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004205 setenv("ROWS", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004206 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004207 setenv("LINES", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004208 sprintf((char *)envbuf, "%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004209 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaar759d8152020-04-26 16:52:49 +02004210 sprintf((char *)envbuf, "%d", t_colors);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004211 setenv("COLORS", (char *)envbuf, 1);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004212# ifdef FEAT_TERMINAL
4213 if (is_terminal)
4214 {
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004215 sprintf((char *)envbuf, "%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004216 setenv("VIM_TERMINAL", (char *)envbuf, 1);
4217 }
4218# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004219# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004220 setenv("VIM_SERVERNAME", serverName == NULL ? "" : (char *)serverName, 1);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004221# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004222# else
4223 /*
4224 * Putenv does not copy the string, it has to remain valid.
4225 * Use a static array to avoid losing allocated memory.
Bram Moolenaar7da34602017-08-01 17:14:21 +02004226 * This won't work well when running multiple children...
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004227 */
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004228 vim_snprintf(envbuf_Term, sizeof(envbuf_Term), "TERM=%s", term);
4229 putenv(envbuf_Term);
4230 vim_snprintf(envbuf_Rows, sizeof(envbuf_Rows), "ROWS=%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004231 putenv(envbuf_Rows);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004232 vim_snprintf(envbuf_Lines, sizeof(envbuf_Lines), "LINES=%ld", rows);
4233 putenv(envbuf_Lines);
4234 vim_snprintf(envbuf_Columns, sizeof(envbuf_Columns),
4235 "COLUMNS=%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004236 putenv(envbuf_Columns);
Bram Moolenaaraffc8fd2020-04-28 21:58:29 +02004237 vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", t_colors);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004238 putenv(envbuf_Colors);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004239# ifdef FEAT_TERMINAL
4240 if (is_terminal)
4241 {
4242 vim_snprintf(envbuf_Version, sizeof(envbuf_Version),
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004243 "VIM_TERMINAL=%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004244 putenv(envbuf_Version);
4245 }
4246# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004247# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004248 vim_snprintf(envbuf_Servername, sizeof(envbuf_Servername),
4249 "VIM_SERVERNAME=%s", serverName == NULL ? "" : (char *)serverName);
4250 putenv(envbuf_Servername);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004251# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004252# endif
4253}
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004254
4255 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004256set_default_child_environment(int is_terminal)
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004257{
Bram Moolenaar493359e2018-06-12 20:25:52 +02004258 set_child_environment(Rows, Columns, "dumb", is_terminal);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004259}
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004260#endif
4261
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004262#if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004263/*
4264 * Open a PTY, with FD for the master and slave side.
4265 * When failing "pty_master_fd" and "pty_slave_fd" are -1.
Bram Moolenaar59386482019-02-10 22:43:46 +01004266 * When successful both file descriptors are stored and the allocated pty name
4267 * is stored in both "*name1" and "*name2".
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004268 */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004269 static void
Bram Moolenaar59386482019-02-10 22:43:46 +01004270open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **name1, char_u **name2)
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004271{
4272 char *tty_name;
4273
Bram Moolenaar59386482019-02-10 22:43:46 +01004274 if (name1 != NULL)
4275 *name1 = NULL;
4276 if (name2 != NULL)
4277 *name2 = NULL;
4278
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004279 *pty_master_fd = mch_openpty(&tty_name); // open pty
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004280 if (*pty_master_fd >= 0)
4281 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004282 // Leaving out O_NOCTTY may lead to waitpid() always returning
4283 // 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4284 // adding O_NOCTTY always works when defined.
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004285#ifdef O_NOCTTY
4286 *pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4287#else
4288 *pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4289#endif
4290 if (*pty_slave_fd < 0)
4291 {
4292 close(*pty_master_fd);
4293 *pty_master_fd = -1;
4294 }
Bram Moolenaar59386482019-02-10 22:43:46 +01004295 else
4296 {
4297 if (name1 != NULL)
4298 *name1 = vim_strsave((char_u *)tty_name);
4299 if (name2 != NULL)
4300 *name2 = vim_strsave((char_u *)tty_name);
4301 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004302 }
4303}
4304#endif
4305
Bram Moolenaarfae42832017-08-01 22:24:26 +02004306/*
4307 * Send SIGINT to a child process if "c" is an interrupt character.
4308 */
Bram Moolenaar840d16f2019-09-10 21:27:18 +02004309 static void
Bram Moolenaarfae42832017-08-01 22:24:26 +02004310may_send_sigint(int c UNUSED, pid_t pid UNUSED, pid_t wpid UNUSED)
4311{
4312# ifdef SIGINT
4313 if (c == Ctrl_C || c == intr_char)
4314 {
4315# ifdef HAVE_SETSID
4316 kill(-pid, SIGINT);
4317# else
4318 kill(0, SIGINT);
4319# endif
4320 if (wpid > 0)
4321 kill(wpid, SIGINT);
4322 }
4323# endif
4324}
4325
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004326#if !defined(USE_SYSTEM) || defined(FEAT_TERMINAL) || defined(PROTO)
Bram Moolenaar13568252018-03-16 20:46:58 +01004327
Bram Moolenaar0f873732019-12-05 20:28:46 +01004328/*
4329 * Parse "cmd" and return the result in "argvp" which is an allocated array of
4330 * pointers, the last one is NULL.
4331 * The "sh_tofree" and "shcf_tofree" must be later freed by the caller.
4332 */
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004333 int
4334unix_build_argv(
Bram Moolenaar13568252018-03-16 20:46:58 +01004335 char_u *cmd,
4336 char ***argvp,
4337 char_u **sh_tofree,
4338 char_u **shcf_tofree)
4339{
4340 char **argv = NULL;
4341 int argc;
4342
4343 *sh_tofree = vim_strsave(p_sh);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004344 if (*sh_tofree == NULL) // out of memory
Bram Moolenaar13568252018-03-16 20:46:58 +01004345 return FAIL;
4346
4347 if (mch_parse_cmd(*sh_tofree, TRUE, &argv, &argc) == FAIL)
4348 return FAIL;
4349 *argvp = argv;
4350
4351 if (cmd != NULL)
4352 {
4353 char_u *s;
4354 char_u *p;
4355
4356 if (extra_shell_arg != NULL)
4357 argv[argc++] = (char *)extra_shell_arg;
4358
Bram Moolenaar0f873732019-12-05 20:28:46 +01004359 // Break 'shellcmdflag' into white separated parts. This doesn't
4360 // handle quoted strings, they are very unlikely to appear.
Bram Moolenaar964b3742019-05-24 18:54:09 +02004361 *shcf_tofree = alloc(STRLEN(p_shcf) + 1);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004362 if (*shcf_tofree == NULL) // out of memory
Bram Moolenaar13568252018-03-16 20:46:58 +01004363 return FAIL;
4364 s = *shcf_tofree;
4365 p = p_shcf;
4366 while (*p != NUL)
4367 {
4368 argv[argc++] = (char *)s;
4369 while (*p && *p != ' ' && *p != TAB)
4370 *s++ = *p++;
4371 *s++ = NUL;
4372 p = skipwhite(p);
4373 }
4374
4375 argv[argc++] = (char *)cmd;
4376 }
4377 argv[argc] = NULL;
4378 return OK;
4379}
4380#endif
4381
4382#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
4383/*
4384 * Use a terminal window to run a shell command in.
4385 */
4386 static int
4387mch_call_shell_terminal(
4388 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004389 int options UNUSED) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01004390{
4391 jobopt_T opt;
4392 char **argv = NULL;
4393 char_u *tofree1 = NULL;
4394 char_u *tofree2 = NULL;
4395 int retval = -1;
4396 buf_T *buf;
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004397 job_T *job;
Bram Moolenaar13568252018-03-16 20:46:58 +01004398 aco_save_T aco;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004399 oparg_T oa; // operator arguments
Bram Moolenaar13568252018-03-16 20:46:58 +01004400
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004401 if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar13568252018-03-16 20:46:58 +01004402 goto theend;
4403
4404 init_job_options(&opt);
4405 ch_log(NULL, "starting terminal for system command '%s'", cmd);
4406 buf = term_start(NULL, argv, &opt, TERM_START_SYSTEM);
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004407 if (buf == NULL)
4408 goto theend;
4409
4410 job = term_getjob(buf->b_term);
4411 ++job->jv_refcount;
Bram Moolenaar13568252018-03-16 20:46:58 +01004412
Bram Moolenaar0f873732019-12-05 20:28:46 +01004413 // Find a window to make "buf" curbuf.
Bram Moolenaar13568252018-03-16 20:46:58 +01004414 aucmd_prepbuf(&aco, buf);
4415
4416 clear_oparg(&oa);
4417 while (term_use_loop())
4418 {
4419 if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active)
4420 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004421 // If terminal_loop() returns OK we got a key that is handled
4422 // in Normal model. We don't do redrawing anyway.
Bram Moolenaar13568252018-03-16 20:46:58 +01004423 if (terminal_loop(TRUE) == OK)
4424 normal_cmd(&oa, TRUE);
4425 }
4426 else
4427 normal_cmd(&oa, TRUE);
4428 }
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004429 retval = job->jv_exitval;
Bram Moolenaar13568252018-03-16 20:46:58 +01004430 ch_log(NULL, "system command finished");
4431
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004432 job_unref(job);
4433
Bram Moolenaar0f873732019-12-05 20:28:46 +01004434 // restore curwin/curbuf and a few other things
Bram Moolenaar13568252018-03-16 20:46:58 +01004435 aucmd_restbuf(&aco);
4436
4437 wait_return(TRUE);
4438 do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
4439
4440theend:
4441 vim_free(argv);
4442 vim_free(tofree1);
4443 vim_free(tofree2);
4444 return retval;
4445}
4446#endif
4447
4448#ifdef USE_SYSTEM
4449/*
4450 * Use system() to start the shell: simple but slow.
4451 */
4452 static int
4453mch_call_shell_system(
Bram Moolenaar05540972016-01-30 20:31:25 +01004454 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004455 int options) // SHELL_*, see vim.h
Bram Moolenaar071d4272004-06-13 20:20:40 +00004456{
4457#ifdef VMS
4458 char *ifn = NULL;
4459 char *ofn = NULL;
4460#endif
Bram Moolenaar26e86442020-05-17 14:06:16 +02004461 tmode_T tmode = cur_tmode;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004462 char_u *newcmd; // only needed for unix
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01004463 int x;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004464
4465 out_flush();
4466
4467 if (options & SHELL_COOKED)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004468 settmode(TMODE_COOK); // set to normal mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00004469
Bram Moolenaar62b42182010-09-21 22:09:37 +02004470# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004471 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02004472 loose_clipboard();
4473# endif
4474
Bram Moolenaar071d4272004-06-13 20:20:40 +00004475 if (cmd == NULL)
4476 x = system((char *)p_sh);
4477 else
4478 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004479# ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004480 if (ofn = strchr((char *)cmd, '>'))
4481 *ofn++ = '\0';
4482 if (ifn = strchr((char *)cmd, '<'))
4483 {
4484 char *p;
4485
4486 *ifn++ = '\0';
Bram Moolenaar0f873732019-12-05 20:28:46 +01004487 p = strchr(ifn,' '); // chop off any trailing spaces
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488 if (p)
4489 *p = '\0';
4490 }
4491 if (ofn)
4492 x = vms_sys((char *)cmd, ofn, ifn);
4493 else
4494 x = system((char *)cmd);
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004495# else
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004496 newcmd = alloc(STRLEN(p_sh)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004497 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004498 + STRLEN(p_shcf) + STRLEN(cmd) + 4);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004499 if (newcmd == NULL)
4500 x = 0;
4501 else
4502 {
4503 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
4504 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
4505 (char *)p_shcf,
4506 (char *)cmd);
4507 x = system((char *)newcmd);
4508 vim_free(newcmd);
4509 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004510# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004511 }
4512# ifdef VMS
4513 x = vms_sys_status(x);
4514# endif
4515 if (emsg_silent)
4516 ;
4517 else if (x == 127)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004518 msg_puts(_("\nCannot execute shell sh\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004519 else if (x && !(options & SHELL_SILENT))
4520 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004521 msg_puts(_("\nshell returned "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522 msg_outnum((long)x);
4523 msg_putchar('\n');
4524 }
4525
4526 if (tmode == TMODE_RAW)
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004527 {
4528 // The shell may have messed with the mode, always set it.
4529 cur_tmode = TMODE_UNKNOWN;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004530 settmode(TMODE_RAW); // set to raw mode
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004531 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532# ifdef FEAT_TITLE
4533 resettitle();
4534# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004535# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4536 restore_clipboard();
4537# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004538 return x;
Bram Moolenaar13568252018-03-16 20:46:58 +01004539}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540
Bram Moolenaar0f873732019-12-05 20:28:46 +01004541#else // USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00004542
Bram Moolenaar0f873732019-12-05 20:28:46 +01004543# define EXEC_FAILED 122 // Exit code when shell didn't execute. Don't use
4544 // 127, some shells use that already
4545# define OPEN_NULL_FAILED 123 // Exit code if /dev/null can't be opened
Bram Moolenaar071d4272004-06-13 20:20:40 +00004546
Bram Moolenaar13568252018-03-16 20:46:58 +01004547/*
4548 * Don't use system(), use fork()/exec().
4549 */
4550 static int
4551mch_call_shell_fork(
4552 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004553 int options) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01004554{
Bram Moolenaar26e86442020-05-17 14:06:16 +02004555 tmode_T tmode = cur_tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004557 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558 pid_t wait_pid = 0;
4559# ifdef HAVE_UNION_WAIT
4560 union wait status;
4561# else
4562 int status = -1;
4563# endif
4564 int retval = -1;
4565 char **argv = NULL;
Bram Moolenaar13568252018-03-16 20:46:58 +01004566 char_u *tofree1 = NULL;
4567 char_u *tofree2 = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004568 int i;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004569 int pty_master_fd = -1; // for pty's
Bram Moolenaardf177f62005-02-22 08:39:57 +00004570# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571 int pty_slave_fd = -1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004572# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01004573 int fd_toshell[2]; // for pipes
Bram Moolenaar071d4272004-06-13 20:20:40 +00004574 int fd_fromshell[2];
4575 int pipe_error = FALSE;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004576 int did_settmode = FALSE; // settmode(TMODE_RAW) called
Bram Moolenaar071d4272004-06-13 20:20:40 +00004577
4578 out_flush();
4579 if (options & SHELL_COOKED)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004580 settmode(TMODE_COOK); // set to normal mode
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004581 if (tmode == TMODE_RAW)
4582 // The shell may have messed with the mode, always set it later.
4583 cur_tmode = TMODE_UNKNOWN;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004585 if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar835dc632016-02-07 14:27:38 +01004586 goto error;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004587
Bram Moolenaar071d4272004-06-13 20:20:40 +00004588 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004589 * For the GUI, when writing the output into the buffer and when reading
4590 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4591 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004593 if ((options & (SHELL_READ|SHELL_WRITE))
4594# ifdef FEAT_GUI
4595 || (gui.in_use && show_shell_mess)
4596# endif
4597 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004598 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004599# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600 /*
4601 * Try to open a master pty.
4602 * If this works, open the slave pty.
4603 * If the slave can't be opened, close the master pty.
4604 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004605 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar59386482019-02-10 22:43:46 +01004606 open_pty(&pty_master_fd, &pty_slave_fd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004607 /*
4608 * If not opening a pty or it didn't work, try using pipes.
4609 */
4610 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004611# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612 {
4613 pipe_error = (pipe(fd_toshell) < 0);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004614 if (!pipe_error) // pipe create OK
Bram Moolenaar071d4272004-06-13 20:20:40 +00004615 {
4616 pipe_error = (pipe(fd_fromshell) < 0);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004617 if (pipe_error) // pipe create failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00004618 {
4619 close(fd_toshell[0]);
4620 close(fd_toshell[1]);
4621 }
4622 }
4623 if (pipe_error)
4624 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004625 msg_puts(_("\nCannot create pipes\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 out_flush();
4627 }
4628 }
4629 }
4630
Bram Moolenaar0f873732019-12-05 20:28:46 +01004631 if (!pipe_error) // pty or pipe opened or not used
Bram Moolenaar071d4272004-06-13 20:20:40 +00004632 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004633 SIGSET_DECL(curset)
4634
Bram Moolenaarb3f74062020-02-26 16:16:53 +01004635# if defined(__BEOS__) && USE_THREAD_FOR_INPUT_WITH_TIMEOUT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636 beos_cleanup_read_thread();
4637# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004638
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004639 BLOCK_SIGNALS(&curset);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004640 pid = fork(); // maybe we should use vfork()
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004641 if (pid == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004643 UNBLOCK_SIGNALS(&curset);
4644
Bram Moolenaar32526b32019-01-19 17:43:09 +01004645 msg_puts(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004646 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004647# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004648 || (gui.in_use && show_shell_mess)
4649# endif
4650 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004651 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004652# ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01004653 if (pty_master_fd >= 0) // close the pseudo tty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654 {
4655 close(pty_master_fd);
4656 close(pty_slave_fd);
4657 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004658 else // close the pipes
Bram Moolenaardf177f62005-02-22 08:39:57 +00004659# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004660 {
4661 close(fd_toshell[0]);
4662 close(fd_toshell[1]);
4663 close(fd_fromshell[0]);
4664 close(fd_fromshell[1]);
4665 }
4666 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004667 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004668 else if (pid == 0) // child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004669 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004670 reset_signals(); // handle signals normally
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004671 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004672
Bram Moolenaar819524702018-02-27 19:10:00 +01004673# ifdef FEAT_JOB_CHANNEL
4674 if (ch_log_active())
Bram Moolenaar0f873732019-12-05 20:28:46 +01004675 // close the log file in the child
Bram Moolenaar819524702018-02-27 19:10:00 +01004676 ch_logfile((char_u *)"", (char_u *)"");
4677# endif
4678
Bram Moolenaar071d4272004-06-13 20:20:40 +00004679 if (!show_shell_mess || (options & SHELL_EXPAND))
4680 {
4681 int fd;
4682
4683 /*
4684 * Don't want to show any message from the shell. Can't just
4685 * close stdout and stderr though, because some systems will
4686 * break if you try to write to them after that, so we must
4687 * use dup() to replace them with something else -- webb
4688 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4689 * waiting for input.
4690 */
4691 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4692 fclose(stdin);
4693 fclose(stdout);
4694 fclose(stderr);
4695
4696 /*
4697 * If any of these open()'s and dup()'s fail, we just continue
4698 * anyway. It's not fatal, and on most systems it will make
4699 * no difference at all. On a few it will cause the execvp()
4700 * to exit with a non-zero status even when the completion
4701 * could be done, which is nothing too serious. If the open()
4702 * or dup() failed we'd just do the same thing ourselves
4703 * anyway -- webb
4704 */
4705 if (fd >= 0)
4706 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004707 vim_ignored = dup(fd); // To replace stdin (fd 0)
4708 vim_ignored = dup(fd); // To replace stdout (fd 1)
4709 vim_ignored = dup(fd); // To replace stderr (fd 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004710
Bram Moolenaar0f873732019-12-05 20:28:46 +01004711 // Don't need this now that we've duplicated it
Bram Moolenaar071d4272004-06-13 20:20:40 +00004712 close(fd);
4713 }
4714 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004715 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004716# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004717 || gui.in_use
4718# endif
4719 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004720 {
4721
Bram Moolenaardf177f62005-02-22 08:39:57 +00004722# ifdef HAVE_SETSID
Bram Moolenaar0f873732019-12-05 20:28:46 +01004723 // Create our own process group, so that the child and all its
4724 // children can be kill()ed. Don't do this when using pipes,
4725 // because stdin is not a tty, we would lose /dev/tty.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004726 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004727 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004728 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004729# if defined(SIGHUP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004730 // When doing "!xterm&" and 'shell' is bash: the shell
4731 // will exit and send SIGHUP to all processes in its
4732 // group, killing the just started process. Ignore SIGHUP
4733 // to avoid that. (suggested by Simon Schubert)
Bram Moolenaar07256082009-02-04 13:19:42 +00004734 signal(SIGHUP, SIG_IGN);
4735# endif
4736 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004737# endif
4738# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004739 if (pty_slave_fd >= 0)
4740 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004741 // push stream discipline modules
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004742 if (options & SHELL_COOKED)
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004743 setup_slavepty(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004744# ifdef TIOCSCTTY
Bram Moolenaar0f873732019-12-05 20:28:46 +01004745 // Try to become controlling tty (probably doesn't work,
4746 // unless run by root)
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004747 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004749 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004750# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02004751 set_default_child_environment(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004752
Bram Moolenaara5792f52005-11-23 21:25:05 +00004753 /*
4754 * stderr is only redirected when using the GUI, so that a
4755 * program like gpg can still access the terminal to get a
4756 * passphrase using stderr.
4757 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004758# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759 if (pty_master_fd >= 0)
4760 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004761 close(pty_master_fd); // close master side of pty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004762
Bram Moolenaar0f873732019-12-05 20:28:46 +01004763 // set up stdin/stdout/stderr for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004764 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004765 vim_ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004766 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004767 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004768 if (gui.in_use)
4769 {
4770 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004771 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004772 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004773
Bram Moolenaar0f873732019-12-05 20:28:46 +01004774 close(pty_slave_fd); // has been dupped, close it now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004775 }
4776 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004777# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004778 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004779 // set up stdin for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004780 close(fd_toshell[1]);
4781 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004782 vim_ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004783 close(fd_toshell[0]);
4784
Bram Moolenaar0f873732019-12-05 20:28:46 +01004785 // set up stdout for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 close(fd_fromshell[0]);
4787 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004788 vim_ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004789 close(fd_fromshell[1]);
4790
Bram Moolenaara5792f52005-11-23 21:25:05 +00004791# ifdef FEAT_GUI
4792 if (gui.in_use)
4793 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004794 // set up stderr for the child
Bram Moolenaara5792f52005-11-23 21:25:05 +00004795 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004796 vim_ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004797 }
4798# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004799 }
4800 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004801
Bram Moolenaar071d4272004-06-13 20:20:40 +00004802 /*
4803 * There is no type cast for the argv, because the type may be
4804 * different on different machines. This may cause a warning
4805 * message with strict compilers, don't worry about it.
4806 * Call _exit() instead of exit() to avoid closing the connection
4807 * to the X server (esp. with GTK, which uses atexit()).
4808 */
4809 execvp(argv[0], argv);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004810 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004812 else // parent
Bram Moolenaar071d4272004-06-13 20:20:40 +00004813 {
4814 /*
4815 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004816 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004817 */
4818 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004819 catch_int_signal();
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004820 UNBLOCK_SIGNALS(&curset);
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01004821# ifdef FEAT_JOB_CHANNEL
4822 ++dont_check_job_ended;
4823# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004824 /*
4825 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004826 * This is also used to pipe stdin/stdout to/from the external
4827 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004828 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004829 if ((options & (SHELL_READ|SHELL_WRITE))
4830# ifdef FEAT_GUI
4831 || (gui.in_use && show_shell_mess)
4832# endif
4833 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004834 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004835# define BUFLEN 100 // length for buffer, pseudo tty limit is 128
Bram Moolenaar071d4272004-06-13 20:20:40 +00004836 char_u buffer[BUFLEN + 1];
Bram Moolenaar0f873732019-12-05 20:28:46 +01004837 int buffer_off = 0; // valid bytes in buffer[]
4838 char_u ta_buf[BUFLEN + 1]; // TypeAHead
4839 int ta_len = 0; // valid bytes in ta_buf[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00004840 int len;
4841 int p_more_save;
4842 int old_State;
4843 int c;
4844 int toshell_fd;
4845 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004846 garray_T ga;
4847 int noread_cnt;
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01004848# ifdef ELAPSED_FUNC
4849 elapsed_T start_tv;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004850# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004851
Bram Moolenaardf177f62005-02-22 08:39:57 +00004852# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004853 if (pty_master_fd >= 0)
4854 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004855 fromshell_fd = pty_master_fd;
4856 toshell_fd = dup(pty_master_fd);
4857 }
4858 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004859# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004860 {
4861 close(fd_toshell[0]);
4862 close(fd_fromshell[1]);
4863 toshell_fd = fd_toshell[1];
4864 fromshell_fd = fd_fromshell[0];
4865 }
4866
4867 /*
4868 * Write to the child if there are typed characters.
4869 * Read from the child if there are characters available.
4870 * Repeat the reading a few times if more characters are
4871 * available. Need to check for typed keys now and then, but
4872 * not too often (delays when no chars are available).
4873 * This loop is quit if no characters can be read from the pty
4874 * (WaitForChar detected special condition), or there are no
4875 * characters available and the child has exited.
4876 * Only check if the child has exited when there is no more
4877 * output. The child may exit before all the output has
4878 * been printed.
4879 *
4880 * Currently this busy loops!
4881 * This can probably dead-lock when the write blocks!
4882 */
4883 p_more_save = p_more;
4884 p_more = FALSE;
4885 old_State = State;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004886 State = EXTERNCMD; // don't redraw at window resize
Bram Moolenaar071d4272004-06-13 20:20:40 +00004887
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004888 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004889 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004890 // Fork a process that will write the lines to the
4891 // external program.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004892 if ((wpid = fork()) == -1)
4893 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004894 msg_puts(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004895 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004896 else if (wpid == 0) // child
Bram Moolenaardf177f62005-02-22 08:39:57 +00004897 {
4898 linenr_T lnum = curbuf->b_op_start.lnum;
4899 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004900 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004901 size_t l;
4902
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004903 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004904 for (;;)
4905 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004906 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004907 if (l == 0)
4908 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004909 else if (lp[written] == NL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004910 // NL -> NUL translation
Bram Moolenaardf177f62005-02-22 08:39:57 +00004911 len = write(toshell_fd, "", (size_t)1);
4912 else
4913 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004914 char_u *s = vim_strchr(lp + written, NL);
4915
Bram Moolenaar89d40322006-08-29 15:30:07 +00004916 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004917 s == NULL ? l
4918 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004919 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004920 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004921 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004922 // Finished a line, add a NL, unless this line
4923 // should not have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004924 if (lnum != curbuf->b_op_end.lnum
Bram Moolenaar34d72d42015-07-17 14:18:08 +02004925 || (!curbuf->b_p_bin
4926 && curbuf->b_p_fixeol)
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004927 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004928 && (lnum !=
4929 curbuf->b_ml.ml_line_count
4930 || curbuf->b_p_eol)))
Bram Moolenaar42335f52018-09-13 15:33:43 +02004931 vim_ignored = write(toshell_fd, "\n",
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004932 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004933 ++lnum;
4934 if (lnum > curbuf->b_op_end.lnum)
4935 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004936 // finished all the lines, close pipe
Bram Moolenaardf177f62005-02-22 08:39:57 +00004937 close(toshell_fd);
4938 toshell_fd = -1;
4939 break;
4940 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004941 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004942 written = 0;
4943 }
4944 else if (len > 0)
4945 written += len;
4946 }
4947 _exit(0);
4948 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004949 else // parent
Bram Moolenaardf177f62005-02-22 08:39:57 +00004950 {
4951 close(toshell_fd);
4952 toshell_fd = -1;
4953 }
4954 }
4955
4956 if (options & SHELL_READ)
4957 ga_init2(&ga, 1, BUFLEN);
4958
4959 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004960# ifdef ELAPSED_FUNC
4961 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004962# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004963 for (;;)
4964 {
4965 /*
4966 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004967 * if there are any.
4968 * Don't do this if we are expanding wild cards (would eat
4969 * typeahead).
4970 * Don't do this when filtering and terminal is in cooked
4971 * mode, the shell command will handle the I/O. Avoids
4972 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004973 * Don't get characters when the child has already
4974 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004975 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004976 * while (noread_cnt > 4), avoids that ":r !ls" eats
4977 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004978 */
4979 len = 0;
4980 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004981 && ((options &
4982 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4983 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004984# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004985 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004986# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004987 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004988 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004989 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004990 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004991 if (ta_len == 0)
4992 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004993 // Get extra characters when we don't have any.
4994 // Reset the counter and timer.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004995 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004996# ifdef ELAPSED_FUNC
4997 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004998# endif
4999 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
5000 }
5001 if (ta_len > 0 || len > 0)
5002 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005003 /*
5004 * For pipes:
5005 * Check for CTRL-C: send interrupt signal to child.
5006 * Check for CTRL-D: EOF, close pipe to child.
5007 */
5008 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
5009 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005010 /*
5011 * Send SIGINT to the child's group or all
5012 * processes in our group.
5013 */
Bram Moolenaarfae42832017-08-01 22:24:26 +02005014 may_send_sigint(ta_buf[ta_len], pid, wpid);
5015
Bram Moolenaar071d4272004-06-13 20:20:40 +00005016 if (pty_master_fd < 0 && toshell_fd >= 0
5017 && ta_buf[ta_len] == Ctrl_D)
5018 {
5019 close(toshell_fd);
5020 toshell_fd = -1;
5021 }
5022 }
5023
Bram Moolenaarf4140482020-02-15 23:06:45 +01005024 term_replace_bs_del_keycode(ta_buf, ta_len, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005025
5026 /*
5027 * For pipes: echo the typed characters.
5028 * For a pty this does not seem to work.
5029 */
5030 if (pty_master_fd < 0)
5031 {
5032 for (i = ta_len; i < ta_len + len; ++i)
5033 {
5034 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
5035 msg_putchar(ta_buf[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005036 else if (has_mbyte)
5037 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005038 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005039
5040 msg_outtrans_len(ta_buf + i, l);
5041 i += l - 1;
5042 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005043 else
5044 msg_outtrans_len(ta_buf + i, 1);
5045 }
5046 windgoto(msg_row, msg_col);
5047 out_flush();
5048 }
5049
5050 ta_len += len;
5051
5052 /*
5053 * Write the characters to the child, unless EOF has
5054 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005055 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005056 * When writing buffer lines, drop the typed
5057 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005058 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005059 if (options & SHELL_WRITE)
5060 ta_len = 0;
5061 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005062 {
5063 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
5064 if (len > 0)
5065 {
5066 ta_len -= len;
5067 mch_memmove(ta_buf, ta_buf + len, ta_len);
5068 }
5069 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005070 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005071 }
5072
Bram Moolenaardf177f62005-02-22 08:39:57 +00005073 if (got_int)
5074 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005075 // CTRL-C sends a signal to the child, we ignore it
5076 // ourselves
Bram Moolenaardf177f62005-02-22 08:39:57 +00005077# ifdef HAVE_SETSID
5078 kill(-pid, SIGINT);
5079# else
5080 kill(0, SIGINT);
5081# endif
5082 if (wpid > 0)
5083 kill(wpid, SIGINT);
5084 got_int = FALSE;
5085 }
5086
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087 /*
5088 * Check if the child has any characters to be printed.
5089 * Read them and write them to our window. Repeat this as
5090 * long as there is something to do, avoid the 10ms wait
5091 * for mch_inchar(), or sending typeahead characters to
5092 * the external process.
5093 * TODO: This should handle escape sequences, compatible
5094 * to some terminal (vt52?).
5095 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005096 ++noread_cnt;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005097 while (RealWaitForChar(fromshell_fd, 10L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005098 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005099 len = read_eintr(fromshell_fd, buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00005100 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005101 );
Bram Moolenaar0f873732019-12-05 20:28:46 +01005102 if (len <= 0) // end of file or error
Bram Moolenaar071d4272004-06-13 20:20:40 +00005103 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005104
5105 noread_cnt = 0;
5106 if (options & SHELL_READ)
5107 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005108 // Do NUL -> NL translation, append NL separated
5109 // lines to the current buffer.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005110 for (i = 0; i < len; ++i)
5111 {
5112 if (buffer[i] == NL)
5113 append_ga_line(&ga);
5114 else if (buffer[i] == NUL)
5115 ga_append(&ga, NL);
5116 else
5117 ga_append(&ga, buffer[i]);
5118 }
5119 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005120 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121 {
5122 int l;
Bram Moolenaara2150ac2018-03-17 13:15:17 +01005123 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005124
Bram Moolenaardf177f62005-02-22 08:39:57 +00005125 len += buffer_off;
5126 buffer[len] = NUL;
5127
Bram Moolenaar0f873732019-12-05 20:28:46 +01005128 // Check if the last character in buffer[] is
5129 // incomplete, keep these bytes for the next
5130 // round.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005131 for (p = buffer; p < buffer + len; p += l)
5132 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02005133 l = MB_CPTR2LEN(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005134 if (l == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005135 l = 1; // NUL byte?
Bram Moolenaar071d4272004-06-13 20:20:40 +00005136 else if (MB_BYTE2LEN(*p) != l)
5137 break;
5138 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01005139 if (p == buffer) // no complete character
Bram Moolenaar071d4272004-06-13 20:20:40 +00005140 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005141 // avoid getting stuck at an illegal byte
Bram Moolenaar071d4272004-06-13 20:20:40 +00005142 if (len >= 12)
5143 ++p;
5144 else
5145 {
5146 buffer_off = len;
5147 continue;
5148 }
5149 }
5150 c = *p;
5151 *p = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005152 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005153 if (p < buffer + len)
5154 {
5155 *p = c;
5156 buffer_off = (buffer + len) - p;
5157 mch_memmove(buffer, p, buffer_off);
5158 continue;
5159 }
5160 buffer_off = 0;
5161 }
5162 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005163 {
5164 buffer[len] = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005165 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005166 }
5167
5168 windgoto(msg_row, msg_col);
5169 cursor_on();
5170 out_flush();
5171 if (got_int)
5172 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005173
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005174# ifdef ELAPSED_FUNC
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005175 if (wait_pid == 0)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005176 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005177 long msec = ELAPSED_FUNC(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005178
Bram Moolenaar0f873732019-12-05 20:28:46 +01005179 // Avoid that we keep looping here without
5180 // checking for a CTRL-C for a long time. Don't
5181 // break out too often to avoid losing typeahead.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005182 if (msec > 2000)
5183 {
5184 noread_cnt = 5;
5185 break;
5186 }
5187 }
5188# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005189 }
5190
Bram Moolenaar0f873732019-12-05 20:28:46 +01005191 // If we already detected the child has finished, continue
5192 // reading output for a short while. Some text may be
5193 // buffered.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005194 if (wait_pid == pid)
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005195 {
5196 if (noread_cnt < 5)
5197 continue;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005198 break;
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005199 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005200
Bram Moolenaar071d4272004-06-13 20:20:40 +00005201 /*
5202 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005203 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005204 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005205# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02005206 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005207# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005208 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005209# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005210 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5211 || (wait_pid == pid && WIFEXITED(status)))
5212 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005213 // Don't break the loop yet, try reading more
5214 // characters from "fromshell_fd" first. When using
5215 // pipes there might still be something to read and
5216 // then we'll break the loop at the "break" above.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005217 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005218 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005219 else
5220 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005221
Bram Moolenaar95a51352013-03-21 22:53:50 +01005222# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005223 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005224 clip_update();
5225# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005226 }
5227finished:
5228 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005229 if (options & SHELL_READ)
5230 {
5231 if (ga.ga_len > 0)
5232 {
5233 append_ga_line(&ga);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005234 // remember that the NL was missing
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005235 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005236 }
5237 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005238 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005239 ga_clear(&ga);
5240 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005241
Bram Moolenaar071d4272004-06-13 20:20:40 +00005242 /*
5243 * Give all typeahead that wasn't used back to ui_inchar().
5244 */
5245 if (ta_len)
5246 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005247 State = old_State;
5248 if (toshell_fd >= 0)
5249 close(toshell_fd);
5250 close(fromshell_fd);
5251 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01005252# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005253 else
5254 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005255 long delay_msec = 1;
5256
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005257 /*
5258 * Similar to the loop above, but only handle X events, no
5259 * I/O.
5260 */
5261 for (;;)
5262 {
5263 if (got_int)
5264 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005265 // CTRL-C sends a signal to the child, we ignore it
5266 // ourselves
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005267# ifdef HAVE_SETSID
5268 kill(-pid, SIGINT);
5269# else
5270 kill(0, SIGINT);
5271# endif
5272 got_int = FALSE;
5273 }
5274# ifdef __NeXT__
5275 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
5276# else
5277 wait_pid = waitpid(pid, &status, WNOHANG);
5278# endif
5279 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5280 || (wait_pid == pid && WIFEXITED(status)))
5281 {
5282 wait_pid = pid;
5283 break;
5284 }
5285
Bram Moolenaar0f873732019-12-05 20:28:46 +01005286 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005287 clip_update();
5288
Bram Moolenaar0f873732019-12-05 20:28:46 +01005289 // Wait for 1 to 10 msec. 1 is faster but gives the child
5290 // less time.
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005291 mch_delay(delay_msec, TRUE);
5292 if (++delay_msec > 10)
5293 delay_msec = 10;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005294 }
5295 }
5296# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005297
5298 /*
5299 * Wait until our child has exited.
5300 * Ignore wait() returning pids of other children and returning
5301 * because of some signal like SIGWINCH.
5302 * Don't wait if wait_pid was already set above, indicating the
5303 * child already exited.
5304 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02005305 if (wait_pid != pid)
5306 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005307
Bram Moolenaar624891f2010-10-13 16:22:09 +02005308# ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01005309 // Close slave side of pty. Only do this after the child has
5310 // exited, otherwise the child may hang when it tries to write on
5311 // the pty.
Bram Moolenaar624891f2010-10-13 16:22:09 +02005312 if (pty_master_fd >= 0)
5313 close(pty_slave_fd);
5314# endif
5315
Bram Moolenaar0f873732019-12-05 20:28:46 +01005316 // Make sure the child that writes to the external program is
5317 // dead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005318 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02005319 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00005320 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02005321 wait4pid(wpid, NULL);
5322 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005323
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005324# ifdef FEAT_JOB_CHANNEL
5325 --dont_check_job_ended;
5326# endif
5327
Bram Moolenaar071d4272004-06-13 20:20:40 +00005328 /*
5329 * Set to raw mode right now, otherwise a CTRL-C after
5330 * catch_signals() will kill Vim.
5331 */
5332 if (tmode == TMODE_RAW)
5333 settmode(TMODE_RAW);
5334 did_settmode = TRUE;
5335 set_signals();
5336
5337 if (WIFEXITED(status))
5338 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005339 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar071d4272004-06-13 20:20:40 +00005340 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01005341 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005342 {
5343 if (retval == EXEC_FAILED)
5344 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005345 msg_puts(_("\nCannot execute shell "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005346 msg_outtrans(p_sh);
5347 msg_putchar('\n');
5348 }
5349 else if (!(options & SHELL_SILENT))
5350 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005351 msg_puts(_("\nshell returned "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005352 msg_outnum((long)retval);
5353 msg_putchar('\n');
5354 }
5355 }
5356 }
5357 else
Bram Moolenaar32526b32019-01-19 17:43:09 +01005358 msg_puts(_("\nCommand terminated\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005359 }
5360 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005361
5362error:
5363 if (!did_settmode)
5364 if (tmode == TMODE_RAW)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005365 settmode(TMODE_RAW); // set to raw mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00005366# ifdef FEAT_TITLE
5367 resettitle();
5368# endif
Bram Moolenaar13568252018-03-16 20:46:58 +01005369 vim_free(argv);
5370 vim_free(tofree1);
5371 vim_free(tofree2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005372
5373 return retval;
Bram Moolenaar13568252018-03-16 20:46:58 +01005374}
Bram Moolenaar0f873732019-12-05 20:28:46 +01005375#endif // USE_SYSTEM
Bram Moolenaar13568252018-03-16 20:46:58 +01005376
5377 int
5378mch_call_shell(
5379 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01005380 int options) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01005381{
5382#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
5383 if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL)
5384 return mch_call_shell_terminal(cmd, options);
5385#endif
5386#ifdef USE_SYSTEM
5387 return mch_call_shell_system(cmd, options);
5388#else
5389 return mch_call_shell_fork(cmd, options);
5390#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005391}
5392
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005393#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005394 void
Bram Moolenaar493359e2018-06-12 20:25:52 +02005395mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005396{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005397 pid_t pid;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005398 int fd_in[2] = {-1, -1}; // for stdin
5399 int fd_out[2] = {-1, -1}; // for stdout
5400 int fd_err[2] = {-1, -1}; // for stderr
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005401 int pty_master_fd = -1;
5402 int pty_slave_fd = -1;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01005403 channel_T *channel = NULL;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005404 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
5405 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
5406 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005407 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005408 int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
5409 int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
Bram Moolenaarb2412082017-08-20 18:09:14 +02005410 int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER;
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005411 int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005412 SIGSET_DECL(curset)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005413
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005414 if (use_out_for_err && use_null_for_out)
5415 use_null_for_err = TRUE;
5416
Bram Moolenaar0f873732019-12-05 20:28:46 +01005417 // default is to fail
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005418 job->jv_status = JOB_FAILED;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005419
Bram Moolenaarb2412082017-08-20 18:09:14 +02005420 if (options->jo_pty
5421 && (!(use_file_for_in || use_null_for_in)
Bram Moolenaar59386482019-02-10 22:43:46 +01005422 || !(use_file_for_out || use_null_for_out)
Bram Moolenaarb2412082017-08-20 18:09:14 +02005423 || !(use_out_for_err || use_file_for_err || use_null_for_err)))
Bram Moolenaar59386482019-02-10 22:43:46 +01005424 open_pty(&pty_master_fd, &pty_slave_fd,
5425 &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005426
Bram Moolenaar0f873732019-12-05 20:28:46 +01005427 // TODO: without the channel feature connect the child to /dev/null?
5428 // Open pipes for stdin, stdout, stderr.
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005429 if (use_file_for_in)
5430 {
5431 char_u *fname = options->jo_io_name[PART_IN];
5432
5433 fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
5434 if (fd_in[0] < 0)
5435 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005436 semsg(_(e_notopen), fname);
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005437 goto failed;
5438 }
5439 }
Bram Moolenaarb2412082017-08-20 18:09:14 +02005440 else
Bram Moolenaar0f873732019-12-05 20:28:46 +01005441 // When writing buffer lines to the input don't use the pty, so that
5442 // the pipe can be closed when all lines were written.
Bram Moolenaarb2412082017-08-20 18:09:14 +02005443 if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in)
5444 && pipe(fd_in) < 0)
5445 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005446
5447 if (use_file_for_out)
5448 {
5449 char_u *fname = options->jo_io_name[PART_OUT];
5450
5451 fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
5452 if (fd_out[1] < 0)
5453 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005454 semsg(_(e_notopen), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005455 goto failed;
5456 }
5457 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005458 else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005459 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005460
5461 if (use_file_for_err)
5462 {
5463 char_u *fname = options->jo_io_name[PART_ERR];
5464
5465 fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
5466 if (fd_err[1] < 0)
5467 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005468 semsg(_(e_notopen), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005469 goto failed;
5470 }
5471 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005472 else if (!use_out_for_err && !use_null_for_err
5473 && pty_master_fd < 0 && pipe(fd_err) < 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005474 goto failed;
5475
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005476 if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5477 {
Bram Moolenaarde279892016-03-11 22:19:44 +01005478 if (options->jo_set & JO_CHANNEL)
5479 {
5480 channel = options->jo_channel;
5481 if (channel != NULL)
5482 ++channel->ch_refcount;
5483 }
5484 else
5485 channel = add_channel();
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005486 if (channel == NULL)
5487 goto failed;
Bram Moolenaarf3360612017-10-01 16:21:31 +02005488 if (job->jv_tty_out != NULL)
5489 ch_log(channel, "using pty %s on fd %d",
5490 job->jv_tty_out, pty_master_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005491 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005492
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005493 BLOCK_SIGNALS(&curset);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005494 pid = fork(); // maybe we should use vfork()
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005495 if (pid == -1)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005496 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005497 // failed to fork
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005498 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005499 goto failed;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005500 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005501 if (pid == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005502 {
Bram Moolenaar4694a172016-04-21 14:05:23 +02005503 int null_fd = -1;
5504 int stderr_works = TRUE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005505
Bram Moolenaar0f873732019-12-05 20:28:46 +01005506 // child
5507 reset_signals(); // handle signals normally
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005508 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005509
Bram Moolenaar819524702018-02-27 19:10:00 +01005510# ifdef FEAT_JOB_CHANNEL
5511 if (ch_log_active())
Bram Moolenaar0f873732019-12-05 20:28:46 +01005512 // close the log file in the child
Bram Moolenaar819524702018-02-27 19:10:00 +01005513 ch_logfile((char_u *)"", (char_u *)"");
5514# endif
5515
Bram Moolenaar835dc632016-02-07 14:27:38 +01005516# ifdef HAVE_SETSID
Bram Moolenaar0f873732019-12-05 20:28:46 +01005517 // Create our own process group, so that the child and all its
5518 // children can be kill()ed. Don't do this when using pipes,
5519 // because stdin is not a tty, we would lose /dev/tty.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005520 (void)setsid();
5521# endif
5522
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005523# ifdef FEAT_TERMINAL
5524 if (options->jo_term_rows > 0)
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005525 {
5526 char *term = (char *)T_NAME;
5527
5528#ifdef FEAT_GUI
5529 if (term_is_gui(T_NAME))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005530 // In the GUI 'term' is not what we want, use $TERM.
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005531 term = getenv("TERM");
5532#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005533 // Use 'term' or $TERM if it starts with "xterm", otherwise fall
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005534 // back to "xterm" or "xterm-color".
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005535 if (term == NULL || *term == NUL || STRNCMP(term, "xterm", 5) != 0)
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005536 {
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005537 if (t_colors >= 256)
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005538 // TODO: should we check this name is supported?
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005539 term = "xterm-256color";
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005540 else if (t_colors > 16)
5541 term = "xterm-color";
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005542 else
5543 term = "xterm";
5544 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005545 set_child_environment(
5546 (long)options->jo_term_rows,
5547 (long)options->jo_term_cols,
Bram Moolenaar493359e2018-06-12 20:25:52 +02005548 term,
5549 is_terminal);
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005550 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005551 else
5552# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02005553 set_default_child_environment(is_terminal);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005554
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005555 if (options->jo_env != NULL)
5556 {
5557 dict_T *dict = options->jo_env;
5558 hashitem_T *hi;
5559 int todo = (int)dict->dv_hashtab.ht_used;
5560
5561 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
5562 if (!HASHITEM_EMPTY(hi))
5563 {
5564 typval_T *item = &dict_lookup(hi)->di_tv;
5565
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005566 vim_setenv((char_u*)hi->hi_key, tv_get_string(item));
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005567 --todo;
5568 }
5569 }
5570
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005571 if (use_null_for_in || use_null_for_out || use_null_for_err)
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005572 {
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005573 null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005574 if (null_fd < 0)
5575 {
5576 perror("opening /dev/null failed");
5577 _exit(OPEN_NULL_FAILED);
5578 }
5579 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005580
Bram Moolenaar223896d2017-08-02 22:33:28 +02005581 if (pty_slave_fd >= 0)
5582 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005583 // push stream discipline modules
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01005584 setup_slavepty(pty_slave_fd);
Bram Moolenaar223896d2017-08-02 22:33:28 +02005585# ifdef TIOCSCTTY
Bram Moolenaar0f873732019-12-05 20:28:46 +01005586 // Try to become controlling tty (probably doesn't work,
5587 // unless run by root)
Bram Moolenaar223896d2017-08-02 22:33:28 +02005588 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
5589# endif
5590 }
5591
Bram Moolenaar0f873732019-12-05 20:28:46 +01005592 // set up stdin for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005593 close(0);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005594 if (use_null_for_in && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005595 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005596 else if (fd_in[0] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005597 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005598 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005599 vim_ignored = dup(fd_in[0]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005600
Bram Moolenaar0f873732019-12-05 20:28:46 +01005601 // set up stderr for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005602 close(2);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005603 if (use_null_for_err && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005604 {
Bram Moolenaar42335f52018-09-13 15:33:43 +02005605 vim_ignored = dup(null_fd);
Bram Moolenaar4694a172016-04-21 14:05:23 +02005606 stderr_works = FALSE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005607 }
5608 else if (use_out_for_err)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005609 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005610 else if (fd_err[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005611 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005612 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005613 vim_ignored = dup(fd_err[1]);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005614
Bram Moolenaar0f873732019-12-05 20:28:46 +01005615 // set up stdout for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005616 close(1);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005617 if (use_null_for_out && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005618 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005619 else if (fd_out[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005620 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005621 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005622 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005623
5624 if (fd_in[0] >= 0)
5625 close(fd_in[0]);
5626 if (fd_in[1] >= 0)
5627 close(fd_in[1]);
5628 if (fd_out[0] >= 0)
5629 close(fd_out[0]);
5630 if (fd_out[1] >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005631 close(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005632 if (fd_err[0] >= 0)
5633 close(fd_err[0]);
5634 if (fd_err[1] >= 0)
5635 close(fd_err[1]);
5636 if (pty_master_fd >= 0)
5637 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005638 close(pty_master_fd); // not used in the child
5639 close(pty_slave_fd); // was duped above
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005640 }
Bram Moolenaarea83bf02016-05-08 09:40:51 +02005641
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005642 if (null_fd >= 0)
5643 close(null_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005644
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005645 if (options->jo_cwd != NULL && mch_chdir((char *)options->jo_cwd) != 0)
5646 _exit(EXEC_FAILED);
5647
Bram Moolenaar0f873732019-12-05 20:28:46 +01005648 // See above for type of argv.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005649 execvp(argv[0], argv);
5650
Bram Moolenaar4694a172016-04-21 14:05:23 +02005651 if (stderr_works)
5652 perror("executing job failed");
Bram Moolenaarfae42832017-08-01 22:24:26 +02005653# ifdef EXITFREE
Bram Moolenaar0f873732019-12-05 20:28:46 +01005654 // calling free_all_mem() here causes problems. Ignore valgrind
5655 // reporting possibly leaked memory.
Bram Moolenaarfae42832017-08-01 22:24:26 +02005656# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005657 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar835dc632016-02-07 14:27:38 +01005658 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005659
Bram Moolenaar0f873732019-12-05 20:28:46 +01005660 // parent
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005661 UNBLOCK_SIGNALS(&curset);
5662
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005663 job->jv_pid = pid;
5664 job->jv_status = JOB_STARTED;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005665 job->jv_channel = channel; // ch_refcount was set above
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005666
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005667 if (pty_master_fd >= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005668 close(pty_slave_fd); // not used in the parent
5669 // close child stdin, stdout and stderr
Bram Moolenaar819524702018-02-27 19:10:00 +01005670 if (fd_in[0] >= 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005671 close(fd_in[0]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005672 if (fd_out[1] >= 0)
Bram Moolenaare98d1212016-03-08 15:37:41 +01005673 close(fd_out[1]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005674 if (fd_err[1] >= 0)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005675 close(fd_err[1]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005676 if (channel != NULL)
5677 {
Bram Moolenaar652de232019-04-04 20:13:09 +02005678 int in_fd = INVALID_FD;
5679 int out_fd = INVALID_FD;
5680 int err_fd = INVALID_FD;
5681
5682 if (!(use_file_for_in || use_null_for_in))
5683 in_fd = fd_in[1] >= 0 ? fd_in[1] : pty_master_fd;
5684
5685 if (!(use_file_for_out || use_null_for_out))
5686 out_fd = fd_out[0] >= 0 ? fd_out[0] : pty_master_fd;
5687
5688 // When using pty_master_fd only set it for stdout, do not duplicate
5689 // it for stderr, it only needs to be read once.
5690 if (!(use_out_for_err || use_file_for_err || use_null_for_err))
5691 {
5692 if (fd_err[0] >= 0)
5693 err_fd = fd_err[0];
5694 else if (out_fd != pty_master_fd)
5695 err_fd = pty_master_fd;
5696 }
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005697
5698 channel_set_pipes(channel, in_fd, out_fd, err_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005699 channel_set_job(channel, job, options);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005700 }
Bram Moolenaar979e8c52017-08-01 15:08:07 +02005701 else
5702 {
5703 if (fd_in[1] >= 0)
5704 close(fd_in[1]);
5705 if (fd_out[0] >= 0)
5706 close(fd_out[0]);
5707 if (fd_err[0] >= 0)
5708 close(fd_err[0]);
5709 if (pty_master_fd >= 0)
5710 close(pty_master_fd);
5711 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005712
Bram Moolenaar0f873732019-12-05 20:28:46 +01005713 // success!
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005714 return;
5715
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005716failed:
Bram Moolenaarde279892016-03-11 22:19:44 +01005717 channel_unref(channel);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005718 if (fd_in[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005719 close(fd_in[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005720 if (fd_in[1] >= 0)
5721 close(fd_in[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005722 if (fd_out[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005723 close(fd_out[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005724 if (fd_out[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005725 close(fd_out[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005726 if (fd_err[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005727 close(fd_err[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005728 if (fd_err[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005729 close(fd_err[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005730 if (pty_master_fd >= 0)
5731 close(pty_master_fd);
5732 if (pty_slave_fd >= 0)
5733 close(pty_slave_fd);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005734}
5735
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005736 static char_u *
5737get_signal_name(int sig)
5738{
5739 int i;
5740 char_u numbuf[NUMBUFLEN];
5741
5742 if (sig == SIGKILL)
5743 return vim_strsave((char_u *)"kill");
5744
5745 for (i = 0; signal_info[i].sig != -1; i++)
5746 if (sig == signal_info[i].sig)
5747 return strlow_save((char_u *)signal_info[i].name);
5748
5749 vim_snprintf((char *)numbuf, NUMBUFLEN, "%d", sig);
5750 return vim_strsave(numbuf);
5751}
5752
Bram Moolenaar835dc632016-02-07 14:27:38 +01005753 char *
5754mch_job_status(job_T *job)
5755{
5756# ifdef HAVE_UNION_WAIT
5757 union wait status;
5758# else
5759 int status = -1;
5760# endif
5761 pid_t wait_pid = 0;
5762
5763# ifdef __NeXT__
5764 wait_pid = wait4(job->jv_pid, &status, WNOHANG, (struct rusage *)0);
5765# else
5766 wait_pid = waitpid(job->jv_pid, &status, WNOHANG);
5767# endif
5768 if (wait_pid == -1)
5769 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005770 // process must have exited
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005771 if (job->jv_status < JOB_ENDED)
5772 ch_log(job->jv_channel, "Job no longer exists: %s",
5773 strerror(errno));
Bram Moolenaar97792de2016-10-15 18:36:49 +02005774 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005775 }
5776 if (wait_pid == 0)
5777 return "run";
5778 if (WIFEXITED(status))
5779 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005780 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar835dc632016-02-07 14:27:38 +01005781 job->jv_exitval = WEXITSTATUS(status);
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005782 if (job->jv_status < JOB_ENDED)
5783 ch_log(job->jv_channel, "Job exited with %d", job->jv_exitval);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005784 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005785 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005786 if (WIFSIGNALED(status))
5787 {
5788 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005789 job->jv_termsig = get_signal_name(WTERMSIG(status));
5790 if (job->jv_status < JOB_ENDED && job->jv_termsig != NULL)
5791 ch_log(job->jv_channel, "Job terminated by signal \"%s\"",
5792 job->jv_termsig);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005793 goto return_dead;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005794 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01005795 return "run";
Bram Moolenaar97792de2016-10-15 18:36:49 +02005796
5797return_dead:
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005798 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005799 job->jv_status = JOB_ENDED;
Bram Moolenaar97792de2016-10-15 18:36:49 +02005800 return "dead";
5801}
5802
5803 job_T *
5804mch_detect_ended_job(job_T *job_list)
5805{
5806# ifdef HAVE_UNION_WAIT
5807 union wait status;
5808# else
5809 int status = -1;
5810# endif
5811 pid_t wait_pid = 0;
5812 job_T *job;
5813
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005814# ifndef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01005815 // Do not do this when waiting for a shell command to finish, we would get
5816 // the exit value here (and discard it), the exit value obtained there
5817 // would then be wrong.
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005818 if (dont_check_job_ended > 0)
5819 return NULL;
5820# endif
5821
Bram Moolenaar97792de2016-10-15 18:36:49 +02005822# ifdef __NeXT__
5823 wait_pid = wait4(-1, &status, WNOHANG, (struct rusage *)0);
5824# else
5825 wait_pid = waitpid(-1, &status, WNOHANG);
5826# endif
5827 if (wait_pid <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005828 // no process ended
Bram Moolenaar97792de2016-10-15 18:36:49 +02005829 return NULL;
5830 for (job = job_list; job != NULL; job = job->jv_next)
5831 {
5832 if (job->jv_pid == wait_pid)
5833 {
5834 if (WIFEXITED(status))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005835 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar97792de2016-10-15 18:36:49 +02005836 job->jv_exitval = WEXITSTATUS(status);
5837 else if (WIFSIGNALED(status))
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005838 {
Bram Moolenaar97792de2016-10-15 18:36:49 +02005839 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005840 job->jv_termsig = get_signal_name(WTERMSIG(status));
5841 }
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005842 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005843 {
5844 ch_log(job->jv_channel, "Job ended");
5845 job->jv_status = JOB_ENDED;
5846 }
5847 return job;
5848 }
5849 }
5850 return NULL;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005851}
5852
Bram Moolenaar3a117e12016-10-30 21:57:52 +01005853/*
5854 * Send a (deadly) signal to "job".
5855 * Return FAIL if "how" is not a valid name.
5856 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01005857 int
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005858mch_signal_job(job_T *job, char_u *how)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005859{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005860 int sig = -1;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005861
Bram Moolenaar923d9262016-02-25 20:56:01 +01005862 if (*how == NUL || STRCMP(how, "term") == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005863 sig = SIGTERM;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005864 else if (STRCMP(how, "hup") == 0)
5865 sig = SIGHUP;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005866 else if (STRCMP(how, "quit") == 0)
5867 sig = SIGQUIT;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005868 else if (STRCMP(how, "int") == 0)
5869 sig = SIGINT;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005870 else if (STRCMP(how, "kill") == 0)
5871 sig = SIGKILL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02005872#ifdef SIGWINCH
5873 else if (STRCMP(how, "winch") == 0)
5874 sig = SIGWINCH;
5875#endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005876 else if (isdigit(*how))
5877 sig = atoi((char *)how);
5878 else
5879 return FAIL;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005880
Bram Moolenaar76ab4fd2018-12-08 14:39:05 +01005881 // Never kill ourselves!
5882 if (job->jv_pid != 0)
5883 {
5884 // TODO: have an option to only kill the process, not the group?
5885 kill(-job->jv_pid, sig);
5886 kill(job->jv_pid, sig);
5887 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005888
Bram Moolenaar835dc632016-02-07 14:27:38 +01005889 return OK;
5890}
Bram Moolenaar76467df2016-02-12 19:30:26 +01005891
5892/*
5893 * Clear the data related to "job".
5894 */
5895 void
5896mch_clear_job(job_T *job)
5897{
Bram Moolenaar0f873732019-12-05 20:28:46 +01005898 // call waitpid because child process may become zombie
Bram Moolenaar76467df2016-02-12 19:30:26 +01005899# ifdef __NeXT__
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005900 (void)wait4(job->jv_pid, NULL, WNOHANG, (struct rusage *)0);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005901# else
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005902 (void)waitpid(job->jv_pid, NULL, WNOHANG);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005903# endif
5904}
Bram Moolenaar835dc632016-02-07 14:27:38 +01005905#endif
5906
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005907#if defined(FEAT_TERMINAL) || defined(PROTO)
5908 int
5909mch_create_pty_channel(job_T *job, jobopt_T *options)
5910{
5911 int pty_master_fd = -1;
5912 int pty_slave_fd = -1;
5913 channel_T *channel;
5914
Bram Moolenaar59386482019-02-10 22:43:46 +01005915 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005916 close(pty_slave_fd);
5917
5918 channel = add_channel();
5919 if (channel == NULL)
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005920 {
5921 close(pty_master_fd);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005922 return FAIL;
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005923 }
Bram Moolenaarf3360612017-10-01 16:21:31 +02005924 if (job->jv_tty_out != NULL)
5925 ch_log(channel, "using pty %s on fd %d",
5926 job->jv_tty_out, pty_master_fd);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005927 job->jv_channel = channel; // ch_refcount was set by add_channel()
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005928 channel->ch_keep_open = TRUE;
5929
Bram Moolenaar0f873732019-12-05 20:28:46 +01005930 // Only set the pty_master_fd for stdout, do not duplicate it for stderr,
5931 // it only needs to be read once.
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005932 channel_set_pipes(channel, pty_master_fd, pty_master_fd, INVALID_FD);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005933 channel_set_job(channel, job, options);
5934 return OK;
5935}
5936#endif
5937
Bram Moolenaar071d4272004-06-13 20:20:40 +00005938/*
5939 * Check for CTRL-C typed by reading all available characters.
5940 * In cooked mode we should get SIGINT, no need to check.
5941 */
5942 void
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005943mch_breakcheck(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005944{
Bram Moolenaar26e86442020-05-17 14:06:16 +02005945 if ((mch_cur_tmode == TMODE_RAW || force)
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005946 && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005947 fill_input_buf(FALSE);
5948}
5949
5950/*
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005951 * Wait "msec" msec until a character is available from the mouse, keyboard,
5952 * from inbuf[].
5953 * "msec" == -1 will block forever.
5954 * Invokes timer callbacks when needed.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005955 * When "ignore_input" is TRUE even check for pending input when input is
5956 * already available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005957 * "interrupted" (if not NULL) is set to TRUE when no character is available
5958 * but something else needs to be done.
Bram Moolenaar40b1b542016-04-20 20:18:23 +02005959 * Returns TRUE when a character is available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005960 * When a GUI is being used, this will never get called -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00005961 */
5962 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005963WaitForChar(long msec, int *interrupted, int ignore_input)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005964{
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005965#ifdef FEAT_TIMERS
Bram Moolenaarc9e649a2017-12-18 18:14:47 +01005966 return ui_wait_for_chars_or_timer(
5967 msec, WaitForCharOrMouse, interrupted, ignore_input) == OK;
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005968#else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005969 return WaitForCharOrMouse(msec, interrupted, ignore_input);
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005970#endif
5971}
5972
5973/*
5974 * Wait "msec" msec until a character is available from the mouse or keyboard
5975 * or from inbuf[].
5976 * "msec" == -1 will block forever.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005977 * for "ignore_input" see WaitForCharOr().
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 Moolenaar943bb2b2016-03-19 14:11:18 +01005980 * When a GUI is being used, this will never get called -- webb
5981 */
5982 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02005983WaitForCharOrMouse(long msec, int *interrupted, int ignore_input)
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005984{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005985#ifdef FEAT_MOUSE_GPM
5986 int gpm_process_wanted;
5987#endif
5988#ifdef FEAT_XCLIPBOARD
5989 int rest;
5990#endif
5991 int avail;
5992
Bram Moolenaar0f873732019-12-05 20:28:46 +01005993 if (!ignore_input && input_available()) // something in inbuf[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00005994 return 1;
5995
5996#if defined(FEAT_MOUSE_DEC)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005997 // May need to query the mouse position.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005998 if (WantQueryMouse)
5999 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00006000 WantQueryMouse = FALSE;
Bram Moolenaar92fd5992019-05-02 23:00:22 +02006001 if (!no_query_mouse_for_testing)
6002 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006003 }
6004#endif
6005
6006 /*
6007 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
6008 * events. This is a bit complicated, because they might both be defined.
6009 */
6010#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
6011# ifdef FEAT_XCLIPBOARD
6012 rest = 0;
6013 if (do_xterm_trace())
6014 rest = msec;
6015# endif
6016 do
6017 {
6018# ifdef FEAT_XCLIPBOARD
6019 if (rest != 0)
6020 {
6021 msec = XT_TRACE_DELAY;
6022 if (rest >= 0 && rest < XT_TRACE_DELAY)
6023 msec = rest;
6024 if (rest >= 0)
6025 rest -= msec;
6026 }
6027# endif
Bram Moolenaar28e67e02019-08-15 23:05:49 +02006028# ifdef FEAT_SOUND_CANBERRA
6029 // Invoke any pending sound callbacks.
6030 if (has_sound_callback_in_queue())
6031 invoke_sound_callback();
6032# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006033# ifdef FEAT_MOUSE_GPM
6034 gpm_process_wanted = 0;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006035 avail = RealWaitForChar(read_cmd_fd, msec,
Bram Moolenaarcda77642016-06-04 13:32:35 +02006036 &gpm_process_wanted, interrupted);
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006037 if (!avail && !gpm_process_wanted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006038# else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006039 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006040 if (!avail)
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006041# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006042 {
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006043 if (!ignore_input && input_available())
Bram Moolenaar071d4272004-06-13 20:20:40 +00006044 return 1;
6045# ifdef FEAT_XCLIPBOARD
6046 if (rest == 0 || !do_xterm_trace())
6047# endif
6048 break;
6049 }
6050 }
6051 while (FALSE
6052# ifdef FEAT_MOUSE_GPM
6053 || (gpm_process_wanted && mch_gpm_process() == 0)
6054# endif
6055# ifdef FEAT_XCLIPBOARD
6056 || (!avail && rest != 0)
6057# endif
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006058 )
6059 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006060
6061#else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006062 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006063#endif
6064 return avail;
6065}
6066
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01006067#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00006068/*
6069 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006070 * "msec" == 0 will check for characters once.
6071 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072 * When a GUI is being used, this will not be used for input -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00006073 * Or when a Linux GPM mouse event is waiting.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006074 * Or when a clientserver message is on the queue.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006075 * "interrupted" (if not NULL) is set to TRUE when no character is available
6076 * but something else needs to be done.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006077 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006078#if defined(__BEOS__)
6079 int
6080#else
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006081 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00006082#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006083RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006084{
6085 int ret;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006086 int result;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006087#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006088 static int busy = FALSE;
6089
Bram Moolenaar0f873732019-12-05 20:28:46 +01006090 // May retry getting characters after an event was handled.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006091# define MAY_LOOP
6092
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006093# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006094 // Remember at what time we started, so that we know how much longer we
6095 // should wait after being interrupted.
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01006096 long start_msec = msec;
6097 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006098
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02006099 if (msec > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006100 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006101# endif
6102
Bram Moolenaar0f873732019-12-05 20:28:46 +01006103 // Handle being called recursively. This may happen for the session
6104 // manager stuff, it may save the file, which does a breakcheck.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006105 if (busy)
6106 return 0;
6107#endif
6108
6109#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00006110 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006111#endif
6112 {
6113#ifdef MAY_LOOP
Bram Moolenaar0f873732019-12-05 20:28:46 +01006114 int finished = TRUE; // default is to 'loop' just once
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006115# ifdef FEAT_MZSCHEME
6116 int mzquantum_used = FALSE;
6117# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006118#endif
6119#ifndef HAVE_SELECT
Bram Moolenaar0f873732019-12-05 20:28:46 +01006120 // each channel may use in, out and err
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006121 struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006122 int nfd;
6123# ifdef FEAT_XCLIPBOARD
6124 int xterm_idx = -1;
6125# endif
6126# ifdef FEAT_MOUSE_GPM
6127 int gpm_idx = -1;
6128# endif
6129# ifdef USE_XSMP
6130 int xsmp_idx = -1;
6131# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006132 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006133
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006134# ifdef FEAT_MZSCHEME
6135 mzvim_check_threads();
6136 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6137 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006138 towait = (int)p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006139 mzquantum_used = TRUE;
6140 }
6141# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006142 fds[0].fd = fd;
6143 fds[0].events = POLLIN;
6144 nfd = 1;
6145
Bram Moolenaar071d4272004-06-13 20:20:40 +00006146# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006147 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006148 if (xterm_Shell != (Widget)0)
6149 {
6150 xterm_idx = nfd;
6151 fds[nfd].fd = ConnectionNumber(xterm_dpy);
6152 fds[nfd].events = POLLIN;
6153 nfd++;
6154 }
6155# endif
6156# ifdef FEAT_MOUSE_GPM
6157 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6158 {
6159 gpm_idx = nfd;
6160 fds[nfd].fd = gpm_fd;
6161 fds[nfd].events = POLLIN;
6162 nfd++;
6163 }
6164# endif
6165# ifdef USE_XSMP
6166 if (xsmp_icefd != -1)
6167 {
6168 xsmp_idx = nfd;
6169 fds[nfd].fd = xsmp_icefd;
6170 fds[nfd].events = POLLIN;
6171 nfd++;
6172 }
6173# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006174#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006175 nfd = channel_poll_setup(nfd, &fds, &towait);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006176#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006177 if (interrupted != NULL)
6178 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006179
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006180 ret = poll(fds, nfd, towait);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006181
6182 result = ret > 0 && (fds[0].revents & POLLIN);
Bram Moolenaarcda77642016-06-04 13:32:35 +02006183 if (result == 0 && interrupted != NULL && ret > 0)
6184 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006185
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006186# ifdef FEAT_MZSCHEME
6187 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006188 // MzThreads scheduling is required and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006189 finished = FALSE;
6190# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006191
Bram Moolenaar071d4272004-06-13 20:20:40 +00006192# ifdef FEAT_XCLIPBOARD
6193 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
6194 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006195 xterm_update(); // Maybe we should hand out clipboard
Bram Moolenaar071d4272004-06-13 20:20:40 +00006196 if (--ret == 0 && !input_available())
Bram Moolenaar0f873732019-12-05 20:28:46 +01006197 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006198 finished = FALSE;
6199 }
6200# endif
6201# ifdef FEAT_MOUSE_GPM
6202 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006203 *check_for_gpm = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006204# endif
6205# ifdef USE_XSMP
6206 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
6207 {
6208 if (fds[xsmp_idx].revents & POLLIN)
6209 {
6210 busy = TRUE;
6211 xsmp_handle_requests();
6212 busy = FALSE;
6213 }
6214 else if (fds[xsmp_idx].revents & POLLHUP)
6215 {
6216 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006217 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006218 xsmp_close();
6219 }
6220 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006221 finished = FALSE; // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006222 }
6223# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006224#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006225 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006226 if (ret >= 0)
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006227 channel_poll_check(ret, &fds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006228#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006229
Bram Moolenaar0f873732019-12-05 20:28:46 +01006230#else // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006231
6232 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006233 struct timeval *tvp;
Bram Moolenaar61fb8d82018-11-12 21:45:08 +01006234 // These are static because they can take 8 Kbyte each and cause the
6235 // signal stack to run out with -O3.
6236 static fd_set rfds, wfds, efds;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006237 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006238 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006239
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006240# ifdef FEAT_MZSCHEME
6241 mzvim_check_threads();
6242 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6243 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006244 towait = p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006245 mzquantum_used = TRUE;
6246 }
6247# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006248
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006249 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006250 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006251 tv.tv_sec = towait / 1000;
6252 tv.tv_usec = (towait % 1000) * (1000000/1000);
6253 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006254 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006255 else
6256 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006257
6258 /*
6259 * Select on ready for reading and exceptional condition (end of file).
6260 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006261select_eintr:
6262 FD_ZERO(&rfds);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006263 FD_ZERO(&wfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006264 FD_ZERO(&efds);
6265 FD_SET(fd, &rfds);
6266# if !defined(__QNX__) && !defined(__CYGWIN32__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006267 // For QNX select() always returns 1 if this is set. Why?
Bram Moolenaar071d4272004-06-13 20:20:40 +00006268 FD_SET(fd, &efds);
6269# endif
6270 maxfd = fd;
6271
Bram Moolenaar071d4272004-06-13 20:20:40 +00006272# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006273 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006274 if (xterm_Shell != (Widget)0)
6275 {
6276 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
6277 if (maxfd < ConnectionNumber(xterm_dpy))
6278 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006279
Bram Moolenaar0f873732019-12-05 20:28:46 +01006280 // An event may have already been read but not handled. In
6281 // particularly, XFlush may cause this.
Bram Moolenaardd82d692012-08-15 17:26:57 +02006282 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006283 }
6284# endif
6285# ifdef FEAT_MOUSE_GPM
6286 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6287 {
6288 FD_SET(gpm_fd, &rfds);
6289 FD_SET(gpm_fd, &efds);
6290 if (maxfd < gpm_fd)
6291 maxfd = gpm_fd;
6292 }
6293# endif
6294# ifdef USE_XSMP
6295 if (xsmp_icefd != -1)
6296 {
6297 FD_SET(xsmp_icefd, &rfds);
6298 FD_SET(xsmp_icefd, &efds);
6299 if (maxfd < xsmp_icefd)
6300 maxfd = xsmp_icefd;
6301 }
6302# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006303# ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006304 maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006305# endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006306 if (interrupted != NULL)
6307 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006308
Bram Moolenaar643b6142018-09-12 20:29:09 +02006309 ret = select(maxfd + 1, SELECT_TYPE_ARG234 &rfds,
6310 SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 &efds, tvp);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006311 result = ret > 0 && FD_ISSET(fd, &rfds);
6312 if (result)
6313 --ret;
Bram Moolenaarcda77642016-06-04 13:32:35 +02006314 else if (interrupted != NULL && ret > 0)
6315 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006316
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006317# ifdef EINTR
6318 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006319 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006320 // Check whether window has been resized, EINTR may be caused by
6321 // SIGWINCH.
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006322 if (do_resize)
6323 handle_resize();
6324
Bram Moolenaar0f873732019-12-05 20:28:46 +01006325 // Interrupted by a signal, need to try again. We ignore msec
6326 // here, because we do want to check even after a timeout if
6327 // characters are available. Needed for reading output of an
6328 // external command after the process has finished.
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006329 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006330 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006331# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00006332# ifdef __TANDEM
6333 if (ret == -1 && errno == ENOTSUP)
6334 {
6335 FD_ZERO(&rfds);
6336 FD_ZERO(&efds);
6337 ret = 0;
6338 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006339# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006340# ifdef FEAT_MZSCHEME
6341 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006342 // loop if MzThreads must be scheduled and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006343 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006344# endif
6345
Bram Moolenaar071d4272004-06-13 20:20:40 +00006346# ifdef FEAT_XCLIPBOARD
6347 if (ret > 0 && xterm_Shell != (Widget)0
6348 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
6349 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006350 xterm_update(); // Maybe we should hand out clipboard
6351 // continue looping when we only got the X event and the input
6352 // buffer is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00006353 if (--ret == 0 && !input_available())
6354 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006355 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006356 finished = FALSE;
6357 }
6358 }
6359# endif
6360# ifdef FEAT_MOUSE_GPM
6361 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
6362 {
6363 if (FD_ISSET(gpm_fd, &efds))
6364 gpm_close();
6365 else if (FD_ISSET(gpm_fd, &rfds))
6366 *check_for_gpm = 1;
6367 }
6368# endif
6369# ifdef USE_XSMP
6370 if (ret > 0 && xsmp_icefd != -1)
6371 {
6372 if (FD_ISSET(xsmp_icefd, &efds))
6373 {
6374 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006375 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006376 xsmp_close();
6377 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006378 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006379 }
6380 else if (FD_ISSET(xsmp_icefd, &rfds))
6381 {
6382 busy = TRUE;
6383 xsmp_handle_requests();
6384 busy = FALSE;
6385 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006386 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006387 }
6388 }
6389# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006390#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar0f873732019-12-05 20:28:46 +01006391 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006392 if (ret >= 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006393 ret = channel_select_check(ret, &rfds, &wfds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006394#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006395
Bram Moolenaar0f873732019-12-05 20:28:46 +01006396#endif // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006397
6398#ifdef MAY_LOOP
6399 if (finished || msec == 0)
6400 break;
6401
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006402# ifdef FEAT_CLIENTSERVER
6403 if (server_waiting())
6404 break;
6405# endif
6406
Bram Moolenaar0f873732019-12-05 20:28:46 +01006407 // We're going to loop around again, find out for how long
Bram Moolenaar071d4272004-06-13 20:20:40 +00006408 if (msec > 0)
6409 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006410# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006411 // Compute remaining wait time.
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006412 msec = start_msec - ELAPSED_FUNC(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006413# else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006414 // Guess we got interrupted halfway.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006415 msec = msec / 2;
6416# endif
6417 if (msec <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006418 break; // waited long enough
Bram Moolenaar071d4272004-06-13 20:20:40 +00006419 }
6420#endif
6421 }
6422
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006423 return result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006424}
6425
Bram Moolenaar071d4272004-06-13 20:20:40 +00006426/*
Bram Moolenaar02743632005-07-25 20:42:36 +00006427 * Expand a path into all matching files and/or directories. Handles "*",
6428 * "?", "[a-z]", "**", etc.
6429 * "path" has backslashes before chars that are not to be expanded.
6430 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006431 */
6432 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006433mch_expandpath(
6434 garray_T *gap,
6435 char_u *path,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006436 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006437{
Bram Moolenaar02743632005-07-25 20:42:36 +00006438 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006439}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006440
6441/*
6442 * mch_expand_wildcards() - this code does wild-card pattern matching using
6443 * the shell
6444 *
6445 * return OK for success, FAIL for error (you may lose some memory) and put
6446 * an error message in *file.
6447 *
6448 * num_pat is number of input patterns
6449 * pat is array of pointers to input patterns
6450 * num_file is pointer to number of matched file names
6451 * file is pointer to array of pointers to matched file names
6452 */
6453
6454#ifndef SEEK_SET
6455# define SEEK_SET 0
6456#endif
6457#ifndef SEEK_END
6458# define SEEK_END 2
6459#endif
6460
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006461#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00006462
Bram Moolenaar071d4272004-06-13 20:20:40 +00006463 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006464mch_expand_wildcards(
6465 int num_pat,
6466 char_u **pat,
6467 int *num_file,
6468 char_u ***file,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006469 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006470{
6471 int i;
6472 size_t len;
Bram Moolenaar85325f82017-03-30 21:18:45 +02006473 long llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006474 char_u *p;
6475 int dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006476
Bram Moolenaarc7247912008-01-13 12:54:11 +00006477 /*
6478 * This is the non-OS/2 implementation (really Unix).
6479 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006480 int j;
6481 char_u *tempname;
6482 char_u *command;
6483 FILE *fd;
6484 char_u *buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006485#define STYLE_ECHO 0 // use "echo", the default
6486#define STYLE_GLOB 1 // use "glob", for csh
6487#define STYLE_VIMGLOB 2 // use "vimglob", for Posix sh
6488#define STYLE_PRINT 3 // use "print -N", for zsh
6489#define STYLE_BT 4 // `cmd` expansion, execute the pattern
6490 // directly
Bram Moolenaar071d4272004-06-13 20:20:40 +00006491 int shell_style = STYLE_ECHO;
6492 int check_spaces;
6493 static int did_find_nul = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006494 int ampersand = FALSE;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006495 // vimglob() function to define for Posix shell
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006496 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006497
Bram Moolenaar0f873732019-12-05 20:28:46 +01006498 *num_file = 0; // default: no files found
Bram Moolenaar071d4272004-06-13 20:20:40 +00006499 *file = NULL;
6500
6501 /*
6502 * If there are no wildcards, just copy the names to allocated memory.
6503 * Saves a lot of time, because we don't have to start a new shell.
6504 */
6505 if (!have_wildcard(num_pat, pat))
6506 return save_patterns(num_pat, pat, num_file, file);
6507
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006508# ifdef HAVE_SANDBOX
Bram Moolenaar0f873732019-12-05 20:28:46 +01006509 // Don't allow any shell command in the sandbox.
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006510 if (sandbox != 0 && check_secure())
6511 return FAIL;
6512# endif
6513
Bram Moolenaar071d4272004-06-13 20:20:40 +00006514 /*
6515 * Don't allow the use of backticks in secure and restricted mode.
6516 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006517 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006518 for (i = 0; i < num_pat; ++i)
6519 if (vim_strchr(pat[i], '`') != NULL
6520 && (check_restricted() || check_secure()))
6521 return FAIL;
6522
6523 /*
6524 * get a name for the temp file
6525 */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02006526 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006527 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006528 emsg(_(e_notmp));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006529 return FAIL;
6530 }
6531
6532 /*
6533 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00006534 * file.
6535 * STYLE_BT: NL separated
6536 * If expanding `cmd` execute it directly.
6537 * STYLE_GLOB: NUL separated
6538 * If we use *csh, "glob" will work better than "echo".
6539 * STYLE_PRINT: NL or NUL separated
6540 * If we use *zsh, "print -N" will work better than "glob".
6541 * STYLE_VIMGLOB: NL separated
6542 * If we use *sh*, we define "vimglob()".
6543 * STYLE_ECHO: space separated.
6544 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006545 */
6546 if (num_pat == 1 && *pat[0] == '`'
6547 && (len = STRLEN(pat[0])) > 2
6548 && *(pat[0] + len - 1) == '`')
6549 shell_style = STYLE_BT;
6550 else if ((len = STRLEN(p_sh)) >= 3)
6551 {
6552 if (STRCMP(p_sh + len - 3, "csh") == 0)
6553 shell_style = STYLE_GLOB;
6554 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
6555 shell_style = STYLE_PRINT;
6556 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006557 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
6558 "sh") != NULL)
6559 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006560
Bram Moolenaar0f873732019-12-05 20:28:46 +01006561 // Compute the length of the command. We need 2 extra bytes: for the
6562 // optional '&' and for the NUL.
6563 // Worst case: "unset nonomatch; print -N >" plus two is 29
Bram Moolenaar071d4272004-06-13 20:20:40 +00006564 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006565 if (shell_style == STYLE_VIMGLOB)
6566 len += STRLEN(sh_vimglob_func);
6567
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006568 for (i = 0; i < num_pat; ++i)
6569 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006570 // Count the length of the patterns in the same way as they are put in
6571 // "command" below.
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006572#ifdef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01006573 len += STRLEN(pat[i]) + 3; // add space and two quotes
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006574#else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006575 ++len; // add space
Bram Moolenaar316059c2006-01-14 21:18:42 +00006576 for (j = 0; pat[i][j] != NUL; ++j)
6577 {
6578 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006579 ++len; // may add a backslash
Bram Moolenaar316059c2006-01-14 21:18:42 +00006580 ++len;
6581 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006582#endif
6583 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006584 command = alloc(len);
6585 if (command == NULL)
6586 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006587 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006588 vim_free(tempname);
6589 return FAIL;
6590 }
6591
6592 /*
6593 * Build the shell command:
6594 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
6595 * recognizes this).
6596 * - Add the shell command to print the expanded names.
6597 * - Add the temp file name.
6598 * - Add the file name patterns.
6599 */
6600 if (shell_style == STYLE_BT)
6601 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006602 // change `command; command& ` to (command; command )
Bram Moolenaar316059c2006-01-14 21:18:42 +00006603 STRCPY(command, "(");
Bram Moolenaar0f873732019-12-05 20:28:46 +01006604 STRCAT(command, pat[0] + 1); // exclude first backtick
Bram Moolenaar071d4272004-06-13 20:20:40 +00006605 p = command + STRLEN(command) - 1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006606 *p-- = ')'; // remove last backtick
Bram Moolenaar1c465442017-03-12 20:10:05 +01006607 while (p > command && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006608 --p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006609 if (*p == '&') // remove trailing '&'
Bram Moolenaar071d4272004-06-13 20:20:40 +00006610 {
Bram Moolenaarbdace832019-03-02 10:13:42 +01006611 ampersand = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006612 *p = ' ';
6613 }
6614 STRCAT(command, ">");
6615 }
6616 else
6617 {
6618 if (flags & EW_NOTFOUND)
6619 STRCPY(command, "set nonomatch; ");
6620 else
6621 STRCPY(command, "unset nonomatch; ");
6622 if (shell_style == STYLE_GLOB)
6623 STRCAT(command, "glob >");
6624 else if (shell_style == STYLE_PRINT)
6625 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00006626 else if (shell_style == STYLE_VIMGLOB)
6627 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006628 else
6629 STRCAT(command, "echo >");
6630 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006631
Bram Moolenaar071d4272004-06-13 20:20:40 +00006632 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00006633
Bram Moolenaar071d4272004-06-13 20:20:40 +00006634 if (shell_style != STYLE_BT)
6635 for (i = 0; i < num_pat; ++i)
6636 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006637 // When using system() always add extra quotes, because the shell
6638 // is started twice. Otherwise put a backslash before special
6639 // characters, except inside ``.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006640#ifdef USE_SYSTEM
6641 STRCAT(command, " \"");
6642 STRCAT(command, pat[i]);
6643 STRCAT(command, "\"");
6644#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00006645 int intick = FALSE;
6646
Bram Moolenaar071d4272004-06-13 20:20:40 +00006647 p = command + STRLEN(command);
6648 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00006649 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00006650 {
6651 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00006652 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006653 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
6654 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006655 // Remove a backslash, take char literally. But keep
6656 // backslash inside backticks, before a special character
6657 // and before a backtick.
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006658 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00006659 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
6660 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006661 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006662 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006663 }
Bram Moolenaare4df1642014-08-29 12:58:44 +02006664 else if (!intick
6665 && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
6666 && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006667 // Put a backslash before a special character, but not
6668 // when inside ``. And not for $var when EW_KEEPDOLLAR is
6669 // set.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006670 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006671
Bram Moolenaar0f873732019-12-05 20:28:46 +01006672 // Copy one character.
Bram Moolenaar280f1262006-01-30 00:14:18 +00006673 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00006674 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006675 *p = NUL;
6676#endif
6677 }
6678 if (flags & EW_SILENT)
6679 show_shell_mess = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006680 if (ampersand)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006681 STRCAT(command, "&"); // put the '&' after the redirection
Bram Moolenaar071d4272004-06-13 20:20:40 +00006682
6683 /*
6684 * Using zsh -G: If a pattern has no matches, it is just deleted from
6685 * the argument list, otherwise zsh gives an error message and doesn't
6686 * expand any other pattern.
6687 */
6688 if (shell_style == STYLE_PRINT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006689 extra_shell_arg = (char_u *)"-G"; // Use zsh NULL_GLOB option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006690
6691 /*
6692 * If we use -f then shell variables set in .cshrc won't get expanded.
6693 * vi can do it, so we will too, but it is only necessary if there is a "$"
6694 * in one of the patterns, otherwise we can still use the fast option.
6695 */
6696 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
Bram Moolenaar0f873732019-12-05 20:28:46 +01006697 extra_shell_arg = (char_u *)"-f"; // Use csh fast option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006698
6699 /*
6700 * execute the shell command
6701 */
6702 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
6703
Bram Moolenaar0f873732019-12-05 20:28:46 +01006704 // When running in the background, give it some time to create the temp
6705 // file, but don't wait for it to finish.
Bram Moolenaarbdace832019-03-02 10:13:42 +01006706 if (ampersand)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006707 mch_delay(10L, TRUE);
6708
Bram Moolenaar0f873732019-12-05 20:28:46 +01006709 extra_shell_arg = NULL; // cleanup
Bram Moolenaar071d4272004-06-13 20:20:40 +00006710 show_shell_mess = TRUE;
6711 vim_free(command);
6712
Bram Moolenaar0f873732019-12-05 20:28:46 +01006713 if (i != 0) // mch_call_shell() failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00006714 {
6715 mch_remove(tempname);
6716 vim_free(tempname);
6717 /*
6718 * With interactive completion, the error message is not printed.
6719 * However with USE_SYSTEM, I don't know how to turn off error messages
6720 * from the shell, so screen may still get messed up -- webb.
6721 */
6722#ifndef USE_SYSTEM
6723 if (!(flags & EW_SILENT))
6724#endif
6725 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006726 redraw_later_clear(); // probably messed up screen
6727 msg_putchar('\n'); // clear bottom line quickly
6728 cmdline_row = Rows - 1; // continue on last line
Bram Moolenaar071d4272004-06-13 20:20:40 +00006729#ifdef USE_SYSTEM
6730 if (!(flags & EW_SILENT))
6731#endif
6732 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006733 msg(_(e_wildexpand));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006734 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006735 }
6736 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006737 // If a `cmd` expansion failed, don't list `cmd` as a match, even when
6738 // EW_NOTFOUND is given
Bram Moolenaar071d4272004-06-13 20:20:40 +00006739 if (shell_style == STYLE_BT)
6740 return FAIL;
6741 goto notfound;
6742 }
6743
6744 /*
6745 * read the names from the file into memory
6746 */
6747 fd = fopen((char *)tempname, READBIN);
6748 if (fd == NULL)
6749 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006750 // Something went wrong, perhaps a file name with a special char.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006751 if (!(flags & EW_SILENT))
6752 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006753 msg(_(e_wildexpand));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006754 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006755 }
6756 vim_free(tempname);
6757 goto notfound;
6758 }
6759 fseek(fd, 0L, SEEK_END);
Bram Moolenaar0f873732019-12-05 20:28:46 +01006760 llen = ftell(fd); // get size of temp file
Bram Moolenaar071d4272004-06-13 20:20:40 +00006761 fseek(fd, 0L, SEEK_SET);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006762 if (llen < 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006763 // just in case ftell() would fail
Bram Moolenaar85325f82017-03-30 21:18:45 +02006764 buffer = NULL;
6765 else
6766 buffer = alloc(llen + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006767 if (buffer == NULL)
6768 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006769 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006770 mch_remove(tempname);
6771 vim_free(tempname);
6772 fclose(fd);
6773 return FAIL;
6774 }
Bram Moolenaar85325f82017-03-30 21:18:45 +02006775 len = llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006776 i = fread((char *)buffer, 1, len, fd);
6777 fclose(fd);
6778 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00006779 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006780 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006781 // unexpected read error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006782 semsg(_(e_notread), tempname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006783 vim_free(tempname);
6784 vim_free(buffer);
6785 return FAIL;
6786 }
6787 vim_free(tempname);
6788
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006789# ifdef __CYGWIN__
Bram Moolenaar0f873732019-12-05 20:28:46 +01006790 // Translate <CR><NL> into <NL>. Caution, buffer may contain NUL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006791 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02006792 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006793 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
6794 *p++ = buffer[i];
6795 len = p - buffer;
6796# endif
6797
6798
Bram Moolenaar0f873732019-12-05 20:28:46 +01006799 // file names are separated with Space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006800 if (shell_style == STYLE_ECHO)
6801 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006802 buffer[len] = '\n'; // make sure the buffer ends in NL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006803 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006804 for (i = 0; *p != '\n'; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006805 {
6806 while (*p != ' ' && *p != '\n')
6807 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006808 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006809 }
6810 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006811 // file names are separated with NL
Bram Moolenaarc7247912008-01-13 12:54:11 +00006812 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006813 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006814 buffer[len] = NUL; // make sure the buffer ends in NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006815 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006816 for (i = 0; *p != NUL; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006817 {
6818 while (*p != '\n' && *p != NUL)
6819 ++p;
6820 if (*p != NUL)
6821 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006822 p = skipwhite(p); // skip leading white space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006823 }
6824 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006825 // file names are separated with NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006826 else
6827 {
6828 /*
6829 * Some versions of zsh use spaces instead of NULs to separate
6830 * results. Only do this when there is no NUL before the end of the
6831 * buffer, otherwise we would never be able to use file names with
6832 * embedded spaces when zsh does use NULs.
6833 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6834 * don't check for spaces again.
6835 */
6836 check_spaces = FALSE;
6837 if (shell_style == STYLE_PRINT && !did_find_nul)
6838 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006839 // If there is a NUL, set did_find_nul, else set check_spaces
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006840 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006841 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006842 did_find_nul = TRUE;
6843 else
6844 check_spaces = TRUE;
6845 }
6846
6847 /*
6848 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6849 * already is one, for STYLE_GLOB it needs to be added.
6850 */
6851 if (len && buffer[len - 1] == NUL)
6852 --len;
6853 else
6854 buffer[len] = NUL;
6855 i = 0;
6856 for (p = buffer; p < buffer + len; ++p)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006857 if (*p == NUL || (*p == ' ' && check_spaces)) // count entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006858 {
6859 ++i;
6860 *p = NUL;
6861 }
6862 if (len)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006863 ++i; // count last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006864 }
6865 if (i == 0)
6866 {
6867 /*
6868 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6869 * /bin/sh will happily expand it to nothing rather than returning an
6870 * error; and hey, it's good to check anyway -- webb.
6871 */
6872 vim_free(buffer);
6873 goto notfound;
6874 }
6875 *num_file = i;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006876 *file = ALLOC_MULT(char_u *, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006877 if (*file == NULL)
6878 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006879 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006880 vim_free(buffer);
6881 return FAIL;
6882 }
6883
6884 /*
6885 * Isolate the individual file names.
6886 */
6887 p = buffer;
6888 for (i = 0; i < *num_file; ++i)
6889 {
6890 (*file)[i] = p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006891 // Space or NL separates
Bram Moolenaarc7247912008-01-13 12:54:11 +00006892 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6893 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006894 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006895 while (!(shell_style == STYLE_ECHO && *p == ' ')
6896 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006897 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006898 if (p == buffer + len) // last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006899 *p = NUL;
6900 else
6901 {
6902 *p++ = NUL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006903 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006904 }
6905 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006906 else // NUL separates
Bram Moolenaar071d4272004-06-13 20:20:40 +00006907 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006908 while (*p && p < buffer + len) // skip entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006909 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006910 ++p; // skip NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006911 }
6912 }
6913
6914 /*
6915 * Move the file names to allocated memory.
6916 */
6917 for (j = 0, i = 0; i < *num_file; ++i)
6918 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006919 // Require the files to exist. Helps when using /bin/sh
Bram Moolenaar071d4272004-06-13 20:20:40 +00006920 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6921 continue;
6922
Bram Moolenaar0f873732019-12-05 20:28:46 +01006923 // check if this entry should be included
Bram Moolenaar071d4272004-06-13 20:20:40 +00006924 dir = (mch_isdir((*file)[i]));
6925 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6926 continue;
6927
Bram Moolenaar0f873732019-12-05 20:28:46 +01006928 // Skip files that are not executable if we check for that.
Bram Moolenaarb5971142015-03-21 17:32:19 +01006929 if (!dir && (flags & EW_EXEC)
6930 && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00006931 continue;
6932
Bram Moolenaar964b3742019-05-24 18:54:09 +02006933 p = alloc(STRLEN((*file)[i]) + 1 + dir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006934 if (p)
6935 {
6936 STRCPY(p, (*file)[i]);
6937 if (dir)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006938 add_pathsep(p); // add '/' to a directory name
Bram Moolenaar071d4272004-06-13 20:20:40 +00006939 (*file)[j++] = p;
6940 }
6941 }
6942 vim_free(buffer);
6943 *num_file = j;
6944
Bram Moolenaar0f873732019-12-05 20:28:46 +01006945 if (*num_file == 0) // rejected all entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006946 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01006947 VIM_CLEAR(*file);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006948 goto notfound;
6949 }
6950
6951 return OK;
6952
6953notfound:
6954 if (flags & EW_NOTFOUND)
6955 return save_patterns(num_pat, pat, num_file, file);
6956 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006957}
6958
Bram Moolenaar0f873732019-12-05 20:28:46 +01006959#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00006960
Bram Moolenaar071d4272004-06-13 20:20:40 +00006961 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006962save_patterns(
6963 int num_pat,
6964 char_u **pat,
6965 int *num_file,
6966 char_u ***file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006967{
6968 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006969 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006970
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006971 *file = ALLOC_MULT(char_u *, num_pat);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006972 if (*file == NULL)
6973 return FAIL;
6974 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006975 {
6976 s = vim_strsave(pat[i]);
6977 if (s != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006978 // Be compatible with expand_filename(): halve the number of
6979 // backslashes.
Bram Moolenaard8b02732005-01-14 21:48:43 +00006980 backslash_halve(s);
6981 (*file)[i] = s;
6982 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006983 *num_file = num_pat;
6984 return OK;
6985}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006986
Bram Moolenaar071d4272004-06-13 20:20:40 +00006987/*
6988 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
6989 * expand.
6990 */
6991 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006992mch_has_exp_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006993{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01006994 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006995 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006996 if (*p == '\\' && p[1] != NUL)
6997 ++p;
6998 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006999 if (vim_strchr((char_u *)
7000#ifdef VMS
7001 "*?%"
7002#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007003 "*?[{'"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007004#endif
7005 , *p) != NULL)
7006 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007007 }
7008 return FALSE;
7009}
7010
7011/*
7012 * Return TRUE if the string "p" contains a wildcard.
7013 * Don't recognize '~' at the end as a wildcard.
7014 */
7015 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007016mch_has_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007017{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007018 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007019 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007020 if (*p == '\\' && p[1] != NUL)
7021 ++p;
7022 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007023 if (vim_strchr((char_u *)
7024#ifdef VMS
7025 "*?%$"
7026#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007027 "*?[{`'$"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007028#endif
7029 , *p) != NULL
7030 || (*p == '~' && p[1] != NUL))
7031 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007032 }
7033 return FALSE;
7034}
7035
Bram Moolenaar071d4272004-06-13 20:20:40 +00007036 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007037have_wildcard(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007038{
7039 int i;
7040
7041 for (i = 0; i < num; i++)
7042 if (mch_has_wildcard(file[i]))
7043 return 1;
7044 return 0;
7045}
7046
7047 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007048have_dollars(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007049{
7050 int i;
7051
7052 for (i = 0; i < num; i++)
7053 if (vim_strchr(file[i], '$') != NULL)
7054 return TRUE;
7055 return FALSE;
7056}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007057
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007058#if !defined(HAVE_RENAME) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007059/*
7060 * Scaled-down version of rename(), which is missing in Xenix.
7061 * This version can only move regular files and will fail if the
7062 * destination exists.
7063 */
7064 int
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007065mch_rename(const char *src, const char *dest)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007066{
7067 struct stat st;
7068
Bram Moolenaar0f873732019-12-05 20:28:46 +01007069 if (stat(dest, &st) >= 0) // fail if destination exists
Bram Moolenaar071d4272004-06-13 20:20:40 +00007070 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007071 if (link(src, dest) != 0) // link file to new name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007072 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007073 if (mch_remove(src) == 0) // delete link to old name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007074 return 0;
7075 return -1;
7076}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007077#endif // !HAVE_RENAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00007078
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007079#if defined(FEAT_MOUSE_GPM) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007080/*
7081 * Initializes connection with gpm (if it isn't already opened)
7082 * Return 1 if succeeded (or connection already opened), 0 if failed
7083 */
7084 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007085gpm_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007086{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007087 static Gpm_Connect gpm_connect; // Must it be kept till closing ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007088
7089 if (!gpm_flag)
7090 {
7091 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
7092 gpm_connect.defaultMask = ~GPM_HARD;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007093 // Default handling for mouse move
7094 gpm_connect.minMod = 0; // Handle any modifier keys
Bram Moolenaar071d4272004-06-13 20:20:40 +00007095 gpm_connect.maxMod = 0xffff;
7096 if (Gpm_Open(&gpm_connect, 0) > 0)
7097 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007098 // gpm library tries to handling TSTP causes
7099 // problems. Anyways, we close connection to Gpm whenever
7100 // we are going to suspend or starting an external process
7101 // so we shouldn't have problem with this
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007102# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007103 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007104# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007105 return 1; // succeed
Bram Moolenaar071d4272004-06-13 20:20:40 +00007106 }
7107 if (gpm_fd == -2)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007108 Gpm_Close(); // We don't want to talk to xterm via gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007109 return 0;
7110 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007111 return 1; // already open
Bram Moolenaar071d4272004-06-13 20:20:40 +00007112}
7113
7114/*
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007115 * Returns TRUE if the GPM mouse is enabled.
7116 */
7117 int
7118gpm_enabled(void)
7119{
7120 return gpm_flag && gpm_fd >= 0;
7121}
7122
7123/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007124 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007125 */
7126 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007127gpm_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007128{
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007129 if (gpm_enabled())
Bram Moolenaar071d4272004-06-13 20:20:40 +00007130 Gpm_Close();
7131}
7132
Bram Moolenaarbedf0912019-05-04 16:58:45 +02007133/*
7134 * Reads gpm event and adds special keys to input buf. Returns length of
Bram Moolenaar071d4272004-06-13 20:20:40 +00007135 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02007136 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00007137 */
7138 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007139mch_gpm_process(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007140{
7141 int button;
7142 static Gpm_Event gpm_event;
7143 char_u string[6];
7144 int_u vim_modifiers;
7145 int row,col;
7146 unsigned char buttons_mask;
7147 unsigned char gpm_modifiers;
7148 static unsigned char old_buttons = 0;
7149
7150 Gpm_GetEvent(&gpm_event);
7151
7152#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007153 // Don't put events in the input queue now.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007154 if (hold_gui_events)
7155 return 0;
7156#endif
7157
7158 row = gpm_event.y - 1;
7159 col = gpm_event.x - 1;
7160
Bram Moolenaar0f873732019-12-05 20:28:46 +01007161 string[0] = ESC; // Our termcode
Bram Moolenaar071d4272004-06-13 20:20:40 +00007162 string[1] = 'M';
7163 string[2] = 'G';
7164 switch (GPM_BARE_EVENTS(gpm_event.type))
7165 {
7166 case GPM_DRAG:
7167 string[3] = MOUSE_DRAG;
7168 break;
7169 case GPM_DOWN:
7170 buttons_mask = gpm_event.buttons & ~old_buttons;
7171 old_buttons = gpm_event.buttons;
7172 switch (buttons_mask)
7173 {
7174 case GPM_B_LEFT:
7175 button = MOUSE_LEFT;
7176 break;
7177 case GPM_B_MIDDLE:
7178 button = MOUSE_MIDDLE;
7179 break;
7180 case GPM_B_RIGHT:
7181 button = MOUSE_RIGHT;
7182 break;
7183 default:
7184 return 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007185 // Don't know what to do. Can more than one button be
7186 // reported in one event?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007187 }
7188 string[3] = (char_u)(button | 0x20);
7189 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
7190 break;
7191 case GPM_UP:
7192 string[3] = MOUSE_RELEASE;
7193 old_buttons &= ~gpm_event.buttons;
7194 break;
7195 default:
7196 return 0;
7197 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007198 // This code is based on gui_x11_mouse_cb in gui_x11.c
Bram Moolenaar071d4272004-06-13 20:20:40 +00007199 gpm_modifiers = gpm_event.modifiers;
7200 vim_modifiers = 0x0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007201 // I ignore capslock stats. Aren't we all just hate capslock mixing with
7202 // Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
7203 // K_CAPSSHIFT is defined 8, so it probably isn't even reported
Bram Moolenaar071d4272004-06-13 20:20:40 +00007204 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
7205 vim_modifiers |= MOUSE_SHIFT;
7206
7207 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
7208 vim_modifiers |= MOUSE_CTRL;
7209 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
7210 vim_modifiers |= MOUSE_ALT;
7211 string[3] |= vim_modifiers;
7212 string[4] = (char_u)(col + ' ' + 1);
7213 string[5] = (char_u)(row + ' ' + 1);
7214 add_to_input_buf(string, 6);
7215 return 6;
7216}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007217#endif // FEAT_MOUSE_GPM
Bram Moolenaar071d4272004-06-13 20:20:40 +00007218
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007219#ifdef FEAT_SYSMOUSE
7220/*
7221 * Initialize connection with sysmouse.
7222 * Let virtual console inform us with SIGUSR2 for pending sysmouse
7223 * output, any sysmouse output than will be processed via sig_sysmouse().
7224 * Return OK if succeeded, FAIL if failed.
7225 */
7226 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007227sysmouse_open(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007228{
7229 struct mouse_info mouse;
7230
7231 mouse.operation = MOUSE_MODE;
7232 mouse.u.mode.mode = 0;
7233 mouse.u.mode.signal = SIGUSR2;
7234 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
7235 {
7236 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
7237 mouse.operation = MOUSE_SHOW;
7238 ioctl(1, CONS_MOUSECTL, &mouse);
7239 return OK;
7240 }
7241 return FAIL;
7242}
7243
7244/*
7245 * Stop processing SIGUSR2 signals, and also make sure that
7246 * virtual console do not send us any sysmouse related signal.
7247 */
7248 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007249sysmouse_close(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007250{
7251 struct mouse_info mouse;
7252
7253 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
7254 mouse.operation = MOUSE_MODE;
7255 mouse.u.mode.mode = 0;
7256 mouse.u.mode.signal = 0;
7257 ioctl(1, CONS_MOUSECTL, &mouse);
7258}
7259
7260/*
7261 * Gets info from sysmouse and adds special keys to input buf.
7262 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007263 static RETSIGTYPE
7264sig_sysmouse SIGDEFARG(sigarg)
7265{
7266 struct mouse_info mouse;
7267 struct video_info video;
7268 char_u string[6];
7269 int row, col;
7270 int button;
7271 int buttons;
7272 static int oldbuttons = 0;
7273
7274#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007275 // Don't put events in the input queue now.
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007276 if (hold_gui_events)
7277 return;
7278#endif
7279
7280 mouse.operation = MOUSE_GETINFO;
7281 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
7282 && ioctl(1, FBIO_MODEINFO, &video) != -1
7283 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
7284 && video.vi_cheight > 0 && video.vi_cwidth > 0)
7285 {
7286 row = mouse.u.data.y / video.vi_cheight;
7287 col = mouse.u.data.x / video.vi_cwidth;
7288 buttons = mouse.u.data.buttons;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007289 string[0] = ESC; // Our termcode
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007290 string[1] = 'M';
7291 string[2] = 'S';
7292 if (oldbuttons == buttons && buttons != 0)
7293 {
7294 button = MOUSE_DRAG;
7295 }
7296 else
7297 {
7298 switch (buttons)
7299 {
7300 case 0:
7301 button = MOUSE_RELEASE;
7302 break;
7303 case 1:
7304 button = MOUSE_LEFT;
7305 break;
7306 case 2:
7307 button = MOUSE_MIDDLE;
7308 break;
7309 case 4:
7310 button = MOUSE_RIGHT;
7311 break;
7312 default:
7313 return;
7314 }
7315 oldbuttons = buttons;
7316 }
7317 string[3] = (char_u)(button);
7318 string[4] = (char_u)(col + ' ' + 1);
7319 string[5] = (char_u)(row + ' ' + 1);
7320 add_to_input_buf(string, 6);
7321 }
7322 return;
7323}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007324#endif // FEAT_SYSMOUSE
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007325
Bram Moolenaar071d4272004-06-13 20:20:40 +00007326#if defined(FEAT_LIBCALL) || defined(PROTO)
Bram Moolenaard99df422016-01-29 23:20:40 +01007327typedef char_u * (*STRPROCSTR)(char_u *);
7328typedef char_u * (*INTPROCSTR)(int);
7329typedef int (*STRPROCINT)(char_u *);
7330typedef int (*INTPROCINT)(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007331
7332/*
7333 * Call a DLL routine which takes either a string or int param
7334 * and returns an allocated string.
7335 */
7336 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007337mch_libcall(
7338 char_u *libname,
7339 char_u *funcname,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007340 char_u *argstring, // NULL when using a argint
Bram Moolenaar05540972016-01-30 20:31:25 +01007341 int argint,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007342 char_u **string_result, // NULL when using number_result
Bram Moolenaar05540972016-01-30 20:31:25 +01007343 int *number_result)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007344{
7345# if defined(USE_DLOPEN)
7346 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007347 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007348# else
7349 shl_t hinstLib;
7350# endif
7351 STRPROCSTR ProcAdd;
7352 INTPROCSTR ProcAddI;
7353 char_u *retval_str = NULL;
7354 int retval_int = 0;
7355 int success = FALSE;
7356
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007357 /*
7358 * Get a handle to the DLL module.
7359 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007360# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007361 // First clear any error, it's not cleared by the dlopen() call.
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007362 (void)dlerror();
7363
Bram Moolenaar071d4272004-06-13 20:20:40 +00007364 hinstLib = dlopen((char *)libname, RTLD_LAZY
7365# ifdef RTLD_LOCAL
7366 | RTLD_LOCAL
7367# endif
7368 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007369 if (hinstLib == NULL)
7370 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007371 // "dlerr" must be used before dlclose()
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007372 dlerr = (char *)dlerror();
7373 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007374 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007375 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007376# else
7377 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
7378# endif
7379
Bram Moolenaar0f873732019-12-05 20:28:46 +01007380 // If the handle is valid, try to get the function address.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007381 if (hinstLib != NULL)
7382 {
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007383# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007384 /*
7385 * Catch a crash when calling the library function. For example when
7386 * using a number where a string pointer is expected.
7387 */
7388 mch_startjmp();
7389 if (SETJMP(lc_jump_env) != 0)
7390 {
7391 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007392# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007393 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007394# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007395 mch_didjmp();
7396 }
7397 else
7398# endif
7399 {
7400 retval_str = NULL;
7401 retval_int = 0;
7402
7403 if (argstring != NULL)
7404 {
7405# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007406 *(void **)(&ProcAdd) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007407 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007408# else
7409 if (shl_findsym(&hinstLib, (const char *)funcname,
7410 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
7411 ProcAdd = NULL;
7412# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007413 if ((success = (ProcAdd != NULL
7414# if defined(USE_DLOPEN)
7415 && dlerr == NULL
7416# endif
7417 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007418 {
7419 if (string_result == NULL)
7420 retval_int = ((STRPROCINT)ProcAdd)(argstring);
7421 else
7422 retval_str = (ProcAdd)(argstring);
7423 }
7424 }
7425 else
7426 {
7427# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007428 *(void **)(&ProcAddI) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007429 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007430# else
7431 if (shl_findsym(&hinstLib, (const char *)funcname,
7432 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
7433 ProcAddI = NULL;
7434# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007435 if ((success = (ProcAddI != NULL
7436# if defined(USE_DLOPEN)
7437 && dlerr == NULL
7438# endif
7439 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007440 {
7441 if (string_result == NULL)
7442 retval_int = ((INTPROCINT)ProcAddI)(argint);
7443 else
7444 retval_str = (ProcAddI)(argint);
7445 }
7446 }
7447
Bram Moolenaar0f873732019-12-05 20:28:46 +01007448 // Save the string before we free the library.
7449 // Assume that a "1" or "-1" result is an illegal pointer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007450 if (string_result == NULL)
7451 *number_result = retval_int;
7452 else if (retval_str != NULL
7453 && retval_str != (char_u *)1
7454 && retval_str != (char_u *)-1)
7455 *string_result = vim_strsave(retval_str);
7456 }
7457
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007458# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007459 mch_endjmp();
7460# ifdef SIGHASARG
7461 if (lc_signal != 0)
7462 {
7463 int i;
7464
Bram Moolenaar0f873732019-12-05 20:28:46 +01007465 // try to find the name of this signal
Bram Moolenaar071d4272004-06-13 20:20:40 +00007466 for (i = 0; signal_info[i].sig != -1; i++)
7467 if (lc_signal == signal_info[i].sig)
7468 break;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007469 semsg("E368: got SIG%s in libcall()", signal_info[i].name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007470 }
7471# endif
7472# endif
7473
Bram Moolenaar071d4272004-06-13 20:20:40 +00007474# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007475 // "dlerr" must be used before dlclose()
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007476 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007477 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007478
Bram Moolenaar0f873732019-12-05 20:28:46 +01007479 // Free the DLL module.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007480 (void)dlclose(hinstLib);
7481# else
7482 (void)shl_unload(hinstLib);
7483# endif
7484 }
7485
7486 if (!success)
7487 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007488 semsg(_(e_libcall), funcname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007489 return FAIL;
7490 }
7491
7492 return OK;
7493}
7494#endif
7495
7496#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007497static int xterm_trace = -1; // default: disabled
Bram Moolenaar071d4272004-06-13 20:20:40 +00007498static int xterm_button;
7499
7500/*
7501 * Setup a dummy window for X selections in a terminal.
7502 */
7503 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007504setup_term_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007505{
7506 int z = 0;
7507 char *strp = "";
7508 Widget AppShell;
7509
7510 if (!x_connect_to_server())
7511 return;
7512
7513 open_app_context();
7514 if (app_context != NULL && xterm_Shell == (Widget)0)
7515 {
7516 int (*oldhandler)();
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007517# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007518 int (*oldIOhandler)();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007519# endif
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007520# ifdef ELAPSED_FUNC
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01007521 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007522
7523 if (p_verbose > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007524 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007525# endif
7526
Bram Moolenaar0f873732019-12-05 20:28:46 +01007527 // Ignore X errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007528 oldhandler = XSetErrorHandler(x_error_check);
7529
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007530# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007531 // Ignore X IO errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007532 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
7533 mch_startjmp();
7534 if (SETJMP(lc_jump_env) != 0)
7535 {
7536 mch_didjmp();
7537 xterm_dpy = NULL;
7538 }
7539 else
Bram Moolenaaredce7422019-01-20 18:39:30 +01007540# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007541 {
7542 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
7543 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007544 if (xterm_dpy != NULL)
7545 xterm_dpy_retry_count = 0;
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007546# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007547 mch_endjmp();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007548# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007549 }
7550
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007551# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007552 // Now handle X IO errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007553 (void)XSetIOErrorHandler(oldIOhandler);
Bram Moolenaaredce7422019-01-20 18:39:30 +01007554# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007555 // Now handle X errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007556 (void)XSetErrorHandler(oldhandler);
7557
7558 if (xterm_dpy == NULL)
7559 {
7560 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01007561 verb_msg(_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007562 return;
7563 }
7564
Bram Moolenaar0f873732019-12-05 20:28:46 +01007565 // Catch terminating error of the X server connection.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007566 (void)XSetIOErrorHandler(x_IOerror_handler);
7567
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007568# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007569 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007570 {
7571 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007572 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007573 verbose_leave();
7574 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007575# endif
7576
Bram Moolenaar0f873732019-12-05 20:28:46 +01007577 // Create a Shell to make converters work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007578 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
7579 applicationShellWidgetClass, xterm_dpy,
7580 NULL);
7581 if (AppShell == (Widget)0)
7582 return;
7583 xterm_Shell = XtVaCreatePopupShell("VIM",
7584 topLevelShellWidgetClass, AppShell,
7585 XtNmappedWhenManaged, 0,
7586 XtNwidth, 1,
7587 XtNheight, 1,
7588 NULL);
7589 if (xterm_Shell == (Widget)0)
7590 return;
7591
7592 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02007593 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007594 if (x11_display == NULL)
7595 x11_display = xterm_dpy;
7596
7597 XtRealizeWidget(xterm_Shell);
7598 XSync(xterm_dpy, False);
7599 xterm_update();
7600 }
7601 if (xterm_Shell != (Widget)0)
7602 {
7603 clip_init(TRUE);
7604 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
7605 x11_window = (Window)atol(strp);
Bram Moolenaar0f873732019-12-05 20:28:46 +01007606 // Check if $WINDOWID is valid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007607 if (test_x11_window(xterm_dpy) == FAIL)
7608 x11_window = 0;
7609 if (x11_window != 0)
7610 xterm_trace = 0;
7611 }
7612}
7613
7614 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007615start_xterm_trace(int button)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007616{
7617 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
7618 return;
7619 xterm_trace = 1;
7620 xterm_button = button;
7621 do_xterm_trace();
7622}
7623
7624
7625 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007626stop_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007627{
7628 if (xterm_trace < 0)
7629 return;
7630 xterm_trace = 0;
7631}
7632
7633/*
7634 * Query the xterm pointer and generate mouse termcodes if necessary
7635 * return TRUE if dragging is active, else FALSE
7636 */
7637 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007638do_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007639{
7640 Window root, child;
7641 int root_x, root_y;
7642 int win_x, win_y;
7643 int row, col;
7644 int_u mask_return;
7645 char_u buf[50];
7646 char_u *strp;
7647 long got_hints;
7648 static char_u *mouse_code;
7649 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
7650 static int prev_row = 0, prev_col = 0;
7651 static XSizeHints xterm_hints;
7652
7653 if (xterm_trace <= 0)
7654 return FALSE;
7655
7656 if (xterm_trace == 1)
7657 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007658 // Get the hints just before tracking starts. The font size might
7659 // have changed recently.
Bram Moolenaara6c2c912008-01-13 15:31:00 +00007660 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
7661 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007662 || xterm_hints.width_inc <= 1
7663 || xterm_hints.height_inc <= 1)
7664 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007665 xterm_trace = -1; // Not enough data -- disable tracing
Bram Moolenaar071d4272004-06-13 20:20:40 +00007666 return FALSE;
7667 }
7668
Bram Moolenaar0f873732019-12-05 20:28:46 +01007669 // Rely on the same mouse code for the duration of this
Bram Moolenaar071d4272004-06-13 20:20:40 +00007670 mouse_code = find_termcode(mouse_name);
7671 prev_row = mouse_row;
Bram Moolenaarcde88542015-08-11 19:14:00 +02007672 prev_col = mouse_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007673 xterm_trace = 2;
7674
Bram Moolenaar0f873732019-12-05 20:28:46 +01007675 // Find the offset of the chars, there might be a scrollbar on the
7676 // left of the window and/or a menu on the top (eterm etc.)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007677 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7678 &win_x, &win_y, &mask_return);
7679 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
7680 - (xterm_hints.height_inc / 2);
7681 if (xterm_hints.y <= xterm_hints.height_inc / 2)
7682 xterm_hints.y = 2;
7683 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
7684 - (xterm_hints.width_inc / 2);
7685 if (xterm_hints.x <= xterm_hints.width_inc / 2)
7686 xterm_hints.x = 2;
7687 return TRUE;
7688 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02007689 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007690 {
7691 xterm_trace = 0;
7692 return FALSE;
7693 }
7694
7695 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7696 &win_x, &win_y, &mask_return);
7697
7698 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
7699 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
7700 if (row == prev_row && col == prev_col)
7701 return TRUE;
7702
7703 STRCPY(buf, mouse_code);
7704 strp = buf + STRLEN(buf);
7705 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
7706 *strp++ = (char_u)(col + ' ' + 1);
7707 *strp++ = (char_u)(row + ' ' + 1);
7708 *strp = 0;
7709 add_to_input_buf(buf, STRLEN(buf));
7710
7711 prev_row = row;
7712 prev_col = col;
7713 return TRUE;
7714}
7715
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02007716# if defined(FEAT_GUI) || defined(FEAT_XCLIPBOARD) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007717/*
7718 * Destroy the display, window and app_context. Required for GTK.
7719 */
7720 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007721clear_xterm_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007722{
7723 if (xterm_Shell != (Widget)0)
7724 {
7725 XtDestroyWidget(xterm_Shell);
7726 xterm_Shell = (Widget)0;
7727 }
7728 if (xterm_dpy != NULL)
7729 {
Bram Moolenaare8208012008-06-20 09:59:25 +00007730# if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01007731 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007732 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00007733# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007734 if (x11_display == xterm_dpy)
7735 x11_display = NULL;
7736 xterm_dpy = NULL;
7737 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007738# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007739 if (app_context != (XtAppContext)NULL)
7740 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007741 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007742 XtDestroyApplicationContext(app_context);
7743 app_context = (XtAppContext)NULL;
7744 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007745# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007746}
7747# endif
7748
7749/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007750 * Catch up with GUI or X events.
7751 */
7752 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007753clip_update(void)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007754{
7755# ifdef FEAT_GUI
7756 if (gui.in_use)
7757 gui_mch_update();
7758 else
7759# endif
7760 if (xterm_Shell != (Widget)0)
7761 xterm_update();
7762}
7763
7764/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007765 * Catch up with any queued X events. This may put keyboard input into the
7766 * input buffer, call resize call-backs, trigger timers etc. If there is
7767 * nothing in the X event queue (& no timers pending), then we return
7768 * immediately.
7769 */
7770 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007771xterm_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007772{
7773 XEvent event;
7774
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007775 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007776 {
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007777 XtInputMask mask = XtAppPending(app_context);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007778
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007779 if (mask == 0 || vim_is_input_buf_full())
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007780 break;
7781
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007782 if (mask & XtIMXEvent)
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007783 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007784 // There is an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007785 XtAppNextEvent(app_context, &event);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007786#ifdef FEAT_CLIENTSERVER
7787 {
7788 XPropertyEvent *e = (XPropertyEvent *)&event;
7789
7790 if (e->type == PropertyNotify && e->window == commWindow
Bram Moolenaar071d4272004-06-13 20:20:40 +00007791 && e->atom == commProperty && e->state == PropertyNewValue)
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007792 serverEventProc(xterm_dpy, &event, 0);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007793 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007794#endif
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007795 XtDispatchEvent(&event);
7796 }
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007797 else
7798 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007799 // There is something else than an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007800 XtAppProcessEvent(app_context, mask);
7801 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007802 }
7803}
7804
7805 int
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007806clip_xterm_own_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007807{
7808 if (xterm_Shell != (Widget)0)
7809 return clip_x11_own_selection(xterm_Shell, cbd);
7810 return FAIL;
7811}
7812
7813 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007814clip_xterm_lose_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007815{
7816 if (xterm_Shell != (Widget)0)
7817 clip_x11_lose_selection(xterm_Shell, cbd);
7818}
7819
7820 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007821clip_xterm_request_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007822{
7823 if (xterm_Shell != (Widget)0)
7824 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7825}
7826
7827 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007828clip_xterm_set_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007829{
7830 clip_x11_set_selection(cbd);
7831}
7832#endif
7833
7834
7835#if defined(USE_XSMP) || defined(PROTO)
7836/*
7837 * Code for X Session Management Protocol.
7838 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007839
7840# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007841/*
7842 * This is our chance to ask the user if they want to save,
7843 * or abort the logout
7844 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007845 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007846xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007847{
7848 cmdmod_T save_cmdmod;
7849 int cancel_shutdown = False;
7850
7851 save_cmdmod = cmdmod;
7852 cmdmod.confirm = TRUE;
Bram Moolenaar027387f2016-01-02 22:25:52 +01007853 if (check_changed_any(FALSE, FALSE))
Bram Moolenaar0f873732019-12-05 20:28:46 +01007854 // Mustn't logout
Bram Moolenaar071d4272004-06-13 20:20:40 +00007855 cancel_shutdown = True;
7856 cmdmod = save_cmdmod;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007857 setcursor(); // position cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00007858 out_flush();
7859
Bram Moolenaar0f873732019-12-05 20:28:46 +01007860 // Done interaction
Bram Moolenaar071d4272004-06-13 20:20:40 +00007861 SmcInteractDone(smc_conn, cancel_shutdown);
7862
Bram Moolenaar0f873732019-12-05 20:28:46 +01007863 // Finish off
7864 // Only end save-yourself here if we're not cancelling shutdown;
7865 // we'll get a cancelled callback later in which we'll end it.
7866 // Hopefully get around glitchy SMs (like GNOME-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007867 if (!cancel_shutdown)
7868 {
7869 xsmp.save_yourself = False;
7870 SmcSaveYourselfDone(smc_conn, True);
7871 }
7872}
7873# endif
7874
7875/*
7876 * Callback that starts save-yourself.
7877 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007878 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007879xsmp_handle_save_yourself(
7880 SmcConn smc_conn,
7881 SmPointer client_data UNUSED,
7882 int save_type UNUSED,
7883 Bool shutdown,
7884 int interact_style UNUSED,
7885 Bool fast UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007886{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007887 // Handle already being in saveyourself
Bram Moolenaar071d4272004-06-13 20:20:40 +00007888 if (xsmp.save_yourself)
7889 SmcSaveYourselfDone(smc_conn, True);
7890 xsmp.save_yourself = True;
7891 xsmp.shutdown = shutdown;
7892
Bram Moolenaar0f873732019-12-05 20:28:46 +01007893 // First up, preserve all files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007894 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01007895 ml_sync_all(FALSE, FALSE); // preserve all swap files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007896
7897 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01007898 verb_msg(_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007899
7900# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007901 // Now see if we can ask about unsaved files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007902 if (shutdown && !fast && gui.in_use)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007903 // Need to interact with user, but need SM's permission
Bram Moolenaar071d4272004-06-13 20:20:40 +00007904 SmcInteractRequest(smc_conn, SmDialogError,
7905 xsmp_handle_interaction, client_data);
7906 else
7907# endif
7908 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007909 // Can stop the cycle here
Bram Moolenaar071d4272004-06-13 20:20:40 +00007910 SmcSaveYourselfDone(smc_conn, True);
7911 xsmp.save_yourself = False;
7912 }
7913}
7914
7915
7916/*
7917 * Callback to warn us of imminent death.
7918 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007919 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007920xsmp_die(SmcConn smc_conn UNUSED, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007921{
7922 xsmp_close();
7923
Bram Moolenaar0f873732019-12-05 20:28:46 +01007924 // quit quickly leaving swapfiles for modified buffers behind
Bram Moolenaar071d4272004-06-13 20:20:40 +00007925 getout_preserve_modified(0);
7926}
7927
7928
7929/*
7930 * Callback to tell us that save-yourself has completed.
7931 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007932 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007933xsmp_save_complete(
7934 SmcConn smc_conn UNUSED,
7935 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007936{
7937 xsmp.save_yourself = False;
7938}
7939
7940
7941/*
7942 * Callback to tell us that an instigated shutdown was cancelled
7943 * (maybe even by us)
7944 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007945 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007946xsmp_shutdown_cancelled(
7947 SmcConn smc_conn,
7948 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007949{
7950 if (xsmp.save_yourself)
7951 SmcSaveYourselfDone(smc_conn, True);
7952 xsmp.save_yourself = False;
7953 xsmp.shutdown = False;
7954}
7955
7956
7957/*
7958 * Callback to tell us that a new ICE connection has been established.
7959 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007960 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007961xsmp_ice_connection(
7962 IceConn iceConn,
7963 IcePointer clientData UNUSED,
7964 Bool opening,
7965 IcePointer *watchData UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007966{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007967 // Intercept creation of ICE connection fd
Bram Moolenaar071d4272004-06-13 20:20:40 +00007968 if (opening)
7969 {
7970 xsmp_icefd = IceConnectionNumber(iceConn);
7971 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7972 }
7973}
7974
7975
Bram Moolenaar0f873732019-12-05 20:28:46 +01007976// Handle any ICE processing that's required; return FAIL if SM lost
Bram Moolenaar071d4272004-06-13 20:20:40 +00007977 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007978xsmp_handle_requests(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007979{
7980 Bool rep;
7981
7982 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7983 == IceProcessMessagesIOError)
7984 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007985 // Lost ICE
Bram Moolenaar071d4272004-06-13 20:20:40 +00007986 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01007987 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007988 xsmp_close();
7989 return FAIL;
7990 }
7991 else
7992 return OK;
7993}
7994
7995static int dummy;
7996
Bram Moolenaar0f873732019-12-05 20:28:46 +01007997// Set up X Session Management Protocol
Bram Moolenaar071d4272004-06-13 20:20:40 +00007998 void
7999xsmp_init(void)
8000{
8001 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00008002 SmcCallbacks smcallbacks;
8003#if 0
8004 SmPropValue smname;
8005 SmProp smnameprop;
8006 SmProp *smprops[1];
8007#endif
8008
8009 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008010 verb_msg(_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008011
8012 xsmp.save_yourself = xsmp.shutdown = False;
8013
Bram Moolenaar0f873732019-12-05 20:28:46 +01008014 // Set up SM callbacks - must have all, even if they're not used
Bram Moolenaar071d4272004-06-13 20:20:40 +00008015 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
8016 smcallbacks.save_yourself.client_data = NULL;
8017 smcallbacks.die.callback = xsmp_die;
8018 smcallbacks.die.client_data = NULL;
8019 smcallbacks.save_complete.callback = xsmp_save_complete;
8020 smcallbacks.save_complete.client_data = NULL;
8021 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
8022 smcallbacks.shutdown_cancelled.client_data = NULL;
8023
Bram Moolenaar0f873732019-12-05 20:28:46 +01008024 // Set up a watch on ICE connection creations. The "dummy" argument is
8025 // apparently required for FreeBSD (we get a BUS error when using NULL).
Bram Moolenaar071d4272004-06-13 20:20:40 +00008026 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
8027 {
8028 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008029 verb_msg(_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008030 return;
8031 }
8032
Bram Moolenaar0f873732019-12-05 20:28:46 +01008033 // Create an SM connection
Bram Moolenaar071d4272004-06-13 20:20:40 +00008034 xsmp.smcconn = SmcOpenConnection(
8035 NULL,
8036 NULL,
8037 SmProtoMajor,
8038 SmProtoMinor,
8039 SmcSaveYourselfProcMask | SmcDieProcMask
8040 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
8041 &smcallbacks,
8042 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00008043 &xsmp.clientid,
Bram Moolenaar4841a7c2018-09-22 14:08:49 +02008044 sizeof(errorstring) - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00008045 errorstring);
8046 if (xsmp.smcconn == NULL)
8047 {
8048 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00008049
Bram Moolenaar071d4272004-06-13 20:20:40 +00008050 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008051 {
8052 vim_snprintf(errorreport, sizeof(errorreport),
8053 _("XSMP SmcOpenConnection failed: %s"), errorstring);
Bram Moolenaar32526b32019-01-19 17:43:09 +01008054 verb_msg(errorreport);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008055 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008056 return;
8057 }
8058 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
8059
8060#if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01008061 // ID ourselves
Bram Moolenaar071d4272004-06-13 20:20:40 +00008062 smname.value = "vim";
8063 smname.length = 3;
8064 smnameprop.name = "SmProgram";
8065 smnameprop.type = "SmARRAY8";
8066 smnameprop.num_vals = 1;
8067 smnameprop.vals = &smname;
8068
8069 smprops[0] = &smnameprop;
8070 SmcSetProperties(xsmp.smcconn, 1, smprops);
8071#endif
8072}
8073
8074
Bram Moolenaar0f873732019-12-05 20:28:46 +01008075// Shut down XSMP comms.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008076 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008077xsmp_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008078{
8079 if (xsmp_icefd != -1)
8080 {
8081 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00008082 if (xsmp.clientid != NULL)
8083 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00008084 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008085 xsmp_icefd = -1;
8086 }
8087}
Bram Moolenaar0f873732019-12-05 20:28:46 +01008088#endif // USE_XSMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00008089
8090
8091#ifdef EBCDIC
Bram Moolenaar0f873732019-12-05 20:28:46 +01008092// Translate character to its CTRL- value
Bram Moolenaar071d4272004-06-13 20:20:40 +00008093char CtrlTable[] =
8094{
8095/* 00 - 5E */
8096 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8097 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8098 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8099 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8102/* ^ */ 0x1E,
8103/* - */ 0x1F,
8104/* 61 - 6C */
8105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8106/* _ */ 0x1F,
8107/* 6E - 80 */
8108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8109/* a */ 0x01,
8110/* b */ 0x02,
8111/* c */ 0x03,
8112/* d */ 0x37,
8113/* e */ 0x2D,
8114/* f */ 0x2E,
8115/* g */ 0x2F,
8116/* h */ 0x16,
8117/* i */ 0x05,
8118/* 8A - 90 */
8119 0, 0, 0, 0, 0, 0, 0,
8120/* j */ 0x15,
8121/* k */ 0x0B,
8122/* l */ 0x0C,
8123/* m */ 0x0D,
8124/* n */ 0x0E,
8125/* o */ 0x0F,
8126/* p */ 0x10,
8127/* q */ 0x11,
8128/* r */ 0x12,
8129/* 9A - A1 */
8130 0, 0, 0, 0, 0, 0, 0, 0,
8131/* s */ 0x13,
8132/* t */ 0x3C,
8133/* u */ 0x3D,
8134/* v */ 0x32,
8135/* w */ 0x26,
8136/* x */ 0x18,
8137/* y */ 0x19,
8138/* z */ 0x3F,
8139/* AA - AC */
8140 0, 0, 0,
8141/* [ */ 0x27,
8142/* AE - BC */
8143 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8144/* ] */ 0x1D,
8145/* BE - C0 */ 0, 0, 0,
8146/* A */ 0x01,
8147/* B */ 0x02,
8148/* C */ 0x03,
8149/* D */ 0x37,
8150/* E */ 0x2D,
8151/* F */ 0x2E,
8152/* G */ 0x2F,
8153/* H */ 0x16,
8154/* I */ 0x05,
8155/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
8156/* J */ 0x15,
8157/* K */ 0x0B,
8158/* L */ 0x0C,
8159/* M */ 0x0D,
8160/* N */ 0x0E,
8161/* O */ 0x0F,
8162/* P */ 0x10,
8163/* Q */ 0x11,
8164/* R */ 0x12,
8165/* DA - DF */ 0, 0, 0, 0, 0, 0,
8166/* \ */ 0x1C,
8167/* E1 */ 0,
8168/* S */ 0x13,
8169/* T */ 0x3C,
8170/* U */ 0x3D,
8171/* V */ 0x32,
8172/* W */ 0x26,
8173/* X */ 0x18,
8174/* Y */ 0x19,
8175/* Z */ 0x3F,
8176/* EA - FF*/ 0, 0, 0, 0, 0, 0,
8177 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8178};
8179
8180char MetaCharTable[]=
Bram Moolenaar0f873732019-12-05 20:28:46 +01008181{// 0 1 2 3 4 5 6 7 8 9 A B C D E F
Bram Moolenaar071d4272004-06-13 20:20:40 +00008182 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
8183 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
8184 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
8185 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
8186};
8187
8188
Bram Moolenaar0f873732019-12-05 20:28:46 +01008189// TODO: Use characters NOT numbers!!!
Bram Moolenaar071d4272004-06-13 20:20:40 +00008190char CtrlCharTable[]=
Bram Moolenaar0f873732019-12-05 20:28:46 +01008191{// 0 1 2 3 4 5 6 7 8 9 A B C D E F
Bram Moolenaar071d4272004-06-13 20:20:40 +00008192 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
8193 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
8194 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
8195 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
8196};
8197
8198
8199#endif