blob: d36eb46a2c474a20d00f3debbb92996d9104e6ea [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * OS/2 port by Paul Slootman
5 * VMS merge by Zoltan Arpadffy
6 *
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 * See README.txt for an overview of the Vim source code.
10 */
11
12/*
13 * os_unix.c -- code for all flavors of Unix (BSD, SYSV, SVR4, POSIX, ...)
14 * Also for OS/2, using the excellent EMX package!!!
Bram Moolenaar041c7102020-05-30 18:14:57 +020015 * Also for Atari MiNT.
Bram Moolenaar071d4272004-06-13 20:20:40 +000016 *
17 * A lot of this file was originally written by Juergen Weigert and later
18 * changed beyond recognition.
19 */
20
Bram Moolenaar071d4272004-06-13 20:20:40 +000021#include "vim.h"
22
Bram Moolenaar325b7a22004-07-05 15:58:32 +000023#ifdef FEAT_MZSCHEME
24# include "if_mzsch.h"
25#endif
26
Bram Moolenaar0f873732019-12-05 20:28:46 +010027#include "os_unixx.h" // unix includes for os_unix.c only
Bram Moolenaar071d4272004-06-13 20:20:40 +000028
29#ifdef USE_XSMP
30# include <X11/SM/SMlib.h>
31#endif
32
Bram Moolenaar588ebeb2008-05-07 17:09:24 +000033#ifdef HAVE_SELINUX
34# include <selinux/selinux.h>
35static int selinux_enabled = -1;
36#endif
37
Bram Moolenaar5bd32f42014-04-02 14:05:38 +020038#ifdef HAVE_SMACK
39# include <attr/xattr.h>
40# include <linux/xattr.h>
41# ifndef SMACK_LABEL_LEN
42# define SMACK_LABEL_LEN 1024
43# endif
44#endif
45
Bram Moolenaara2442432007-04-26 14:26:37 +000046#ifdef __CYGWIN__
K.Takata972db232022-02-04 10:45:38 +000047# include <cygwin/version.h>
48# include <sys/cygwin.h> // for cygwin_conv_to_posix_path() and/or
Bram Moolenaar0f873732019-12-05 20:28:46 +010049 // for cygwin_conv_path()
K.Takata972db232022-02-04 10:45:38 +000050# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
51# define WIN32_LEAN_AND_MEAN
52# include <windows.h>
53# include "winclip.pro"
Bram Moolenaara2442432007-04-26 14:26:37 +000054# endif
55#endif
56
Bram Moolenaar071d4272004-06-13 20:20:40 +000057#ifdef FEAT_MOUSE_GPM
Bram Moolenaar33fc4a62022-02-23 18:07:38 +000058
Bram Moolenaar071d4272004-06-13 20:20:40 +000059# include <gpm.h>
Bram Moolenaar33fc4a62022-02-23 18:07:38 +000060
61# ifdef DYNAMIC_GPM
62# define Gpm_Open (*dll_Gpm_Open)
63# define Gpm_Close (*dll_Gpm_Close)
64# define Gpm_GetEvent (*dll_Gpm_GetEvent)
65# define gpm_flag (dll_gpm_flag != NULL ? *dll_gpm_flag : 0)
66# define gpm_fd (dll_gpm_fd != NULL ? *dll_gpm_fd : -1)
67
68static int (*dll_Gpm_Open) (Gpm_Connect *, int);
69static int (*dll_Gpm_Close) (void);
70static int (*dll_Gpm_GetEvent) (Gpm_Event *);
71static int *dll_gpm_flag;
72static int *dll_gpm_fd;
73
74static void *libgpm_hinst;
75# endif
76
Bram Moolenaar0f873732019-12-05 20:28:46 +010077// <linux/keyboard.h> contains defines conflicting with "keymap.h",
78// I just copied relevant defines here. A cleaner solution would be to put gpm
79// code into separate file and include there linux/keyboard.h
80// #include <linux/keyboard.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000081# define KG_SHIFT 0
82# define KG_CTRL 2
83# define KG_ALT 3
84# define KG_ALTGR 1
85# define KG_SHIFTL 4
86# define KG_SHIFTR 5
87# define KG_CTRLL 6
88# define KG_CTRLR 7
89# define KG_CAPSSHIFT 8
90
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010091static void gpm_close(void);
92static int gpm_open(void);
93static int mch_gpm_process(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000094#endif
95
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000096#ifdef FEAT_SYSMOUSE
97# include <sys/consio.h>
98# include <sys/fbio.h>
99
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100100static int sysmouse_open(void);
101static void sysmouse_close(void);
Bram Moolenaard99df422016-01-29 23:20:40 +0100102static RETSIGTYPE sig_sysmouse SIGPROTOARG;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000103#endif
104
Bram Moolenaar071d4272004-06-13 20:20:40 +0000105/*
106 * end of autoconf section. To be extended...
107 */
108
Bram Moolenaar0f873732019-12-05 20:28:46 +0100109// Are the following #ifdefs still required? And why? Is that for X11?
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110
111#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
112# ifdef SIGWINCH
113# undef SIGWINCH
114# endif
115# ifdef TIOCGWINSZ
116# undef TIOCGWINSZ
117# endif
118#endif
119
Bram Moolenaar0f873732019-12-05 20:28:46 +0100120#if defined(SIGWINDOW) && !defined(SIGWINCH) // hpux 9.01 has it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000121# define SIGWINCH SIGWINDOW
122#endif
123
124#ifdef FEAT_X11
125# include <X11/Xlib.h>
126# include <X11/Xutil.h>
127# include <X11/Xatom.h>
128# ifdef FEAT_XCLIPBOARD
129# include <X11/Intrinsic.h>
130# include <X11/Shell.h>
131# include <X11/StringDefs.h>
132static Widget xterm_Shell = (Widget)0;
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100133static void clip_update(void);
134static void xterm_update(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000135# endif
136
Bram Moolenaar071d4272004-06-13 20:20:40 +0000137Window x11_window = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138Display *x11_display = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139#endif
140
Bram Moolenaar5c3128e2020-05-11 20:54:42 +0200141static int ignore_sigtstp = FALSE;
142
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100143static int get_x11_title(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144
145static char_u *oldtitle = NULL;
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200146static volatile sig_atomic_t oldtitle_outdated = FALSE;
Bram Moolenaardac13472019-09-16 21:06:21 +0200147static int unix_did_set_title = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148static char_u *oldicon = NULL;
149static int did_set_icon = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100151static void may_core_dump(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152
Bram Moolenaar205b8862011-09-07 15:04:31 +0200153#ifdef HAVE_UNION_WAIT
154typedef union wait waitstatus;
155#else
156typedef int waitstatus;
157#endif
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200158static int WaitForChar(long msec, int *interrupted, int ignore_input);
159static int WaitForCharOrMouse(long msec, int *interrupted, int ignore_input);
Bram Moolenaar041c7102020-05-30 18:14:57 +0200160#ifdef VMS
Bram Moolenaarcda77642016-06-04 13:32:35 +0200161int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162#else
Bram Moolenaarcda77642016-06-04 13:32:35 +0200163static int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164#endif
165
166#ifdef FEAT_XCLIPBOARD
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100167static int do_xterm_trace(void);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100168# define XT_TRACE_DELAY 50 // delay for xterm tracing
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169#endif
170
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100171static void handle_resize(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172
173#if defined(SIGWINCH)
Bram Moolenaard99df422016-01-29 23:20:40 +0100174static RETSIGTYPE sig_winch SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175#endif
dbivolaruab16ad32021-12-29 19:41:47 +0000176#if defined(SIGTSTP)
177static RETSIGTYPE sig_tstp SIGPROTOARG;
178// volatile because it is used in signal handler sig_tstp() and sigcont_handler().
179static volatile sig_atomic_t in_mch_suspend = FALSE;
180#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000181#if defined(SIGINT)
Bram Moolenaard99df422016-01-29 23:20:40 +0100182static RETSIGTYPE catch_sigint SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000183#endif
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200184#if defined(SIGUSR1)
185static RETSIGTYPE catch_sigusr1 SIGPROTOARG;
186#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000187#if defined(SIGPWR)
Bram Moolenaard99df422016-01-29 23:20:40 +0100188static RETSIGTYPE catch_sigpwr SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000189#endif
Bram Moolenaar651fca82021-11-29 20:39:38 +0000190#if defined(SIGALRM) && defined(FEAT_X11) && !defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000191# define SET_SIG_ALARM
Bram Moolenaard99df422016-01-29 23:20:40 +0100192static RETSIGTYPE sig_alarm SIGPROTOARG;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100193// volatile because it is used in signal handler sig_alarm().
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200194static volatile sig_atomic_t sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000195#endif
Bram Moolenaard99df422016-01-29 23:20:40 +0100196static RETSIGTYPE deathtrap SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000197
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100198static void catch_int_signal(void);
199static void set_signals(void);
200static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)());
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +0200201#ifdef HAVE_SIGPROCMASK
202# define SIGSET_DECL(set) sigset_t set;
203# define BLOCK_SIGNALS(set) block_signals(set)
204# define UNBLOCK_SIGNALS(set) unblock_signals(set)
205#else
206# define SIGSET_DECL(set)
207# define BLOCK_SIGNALS(set) do { /**/ } while (0)
208# define UNBLOCK_SIGNALS(set) do { /**/ } while (0)
209#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100210static int have_wildcard(int, char_u **);
211static int have_dollars(int, char_u **);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000212
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100213static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000214
215#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000216# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217#endif
218
Bram Moolenaar0f873732019-12-05 20:28:46 +0100219// volatile because it is used in signal handler sig_winch().
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200220static volatile sig_atomic_t do_resize = FALSE;
dbivolaruab16ad32021-12-29 19:41:47 +0000221// volatile because it is used in signal handler sig_tstp().
222static volatile sig_atomic_t got_tstp = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000223static char_u *extra_shell_arg = NULL;
224static int show_shell_mess = TRUE;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100225// volatile because it is used in signal handler deathtrap().
226static volatile sig_atomic_t deadly_signal = 0; // The signal we caught
227// volatile because it is used in signal handler deathtrap().
228static volatile sig_atomic_t in_mch_delay = FALSE; // sleeping in mch_delay()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000229
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +0100230#if defined(FEAT_JOB_CHANNEL) && !defined(USE_SYSTEM)
231static int dont_check_job_ended = 0;
232#endif
233
Bram Moolenaar26e86442020-05-17 14:06:16 +0200234// Current terminal mode from mch_settmode(). Can differ from cur_tmode.
235static tmode_T mch_cur_tmode = TMODE_COOK;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236
237#ifdef USE_XSMP
238typedef struct
239{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100240 SmcConn smcconn; // The SM connection ID
241 IceConn iceconn; // The ICE connection ID
242 char *clientid; // The client ID for the current smc session
243 Bool save_yourself; // If we're in the middle of a save_yourself
244 Bool shutdown; // If we're in shutdown mode
Bram Moolenaar071d4272004-06-13 20:20:40 +0000245} xsmp_config_T;
246
247static xsmp_config_T xsmp;
248#endif
249
250#ifdef SYS_SIGLIST_DECLARED
251/*
252 * I have seen
253 * extern char *_sys_siglist[NSIG];
254 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
255 * that describe the signals. That is nearly what we want here. But
256 * autoconf does only check for sys_siglist (without the underscore), I
257 * do not want to change everything today.... jw.
Bram Moolenaar3f7d0902016-11-12 21:13:42 +0100258 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.ac.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000259 */
260#endif
261
262static struct signalinfo
263{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100264 int sig; // Signal number, eg. SIGSEGV etc
265 char *name; // Signal name (not char_u!).
266 char deadly; // Catch as a deadly signal?
Bram Moolenaar071d4272004-06-13 20:20:40 +0000267} signal_info[] =
268{
269#ifdef SIGHUP
270 {SIGHUP, "HUP", TRUE},
271#endif
272#ifdef SIGQUIT
273 {SIGQUIT, "QUIT", TRUE},
274#endif
275#ifdef SIGILL
276 {SIGILL, "ILL", TRUE},
277#endif
278#ifdef SIGTRAP
279 {SIGTRAP, "TRAP", TRUE},
280#endif
281#ifdef SIGABRT
282 {SIGABRT, "ABRT", TRUE},
283#endif
284#ifdef SIGEMT
285 {SIGEMT, "EMT", TRUE},
286#endif
287#ifdef SIGFPE
288 {SIGFPE, "FPE", TRUE},
289#endif
290#ifdef SIGBUS
291 {SIGBUS, "BUS", TRUE},
292#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100293#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100294 // MzScheme uses SEGV in its garbage collector
Bram Moolenaar071d4272004-06-13 20:20:40 +0000295 {SIGSEGV, "SEGV", TRUE},
296#endif
297#ifdef SIGSYS
298 {SIGSYS, "SYS", TRUE},
299#endif
300#ifdef SIGALRM
Bram Moolenaar0f873732019-12-05 20:28:46 +0100301 {SIGALRM, "ALRM", FALSE}, // Perl's alarm() can trigger it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000302#endif
303#ifdef SIGTERM
304 {SIGTERM, "TERM", TRUE},
305#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100306#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000307 {SIGVTALRM, "VTALRM", TRUE},
308#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000309#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100310 // MzScheme uses SIGPROF for its own needs; On Linux with profiling
311 // this makes Vim exit. WE_ARE_PROFILING is defined in Makefile.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000312 {SIGPROF, "PROF", TRUE},
313#endif
314#ifdef SIGXCPU
315 {SIGXCPU, "XCPU", TRUE},
316#endif
317#ifdef SIGXFSZ
318 {SIGXFSZ, "XFSZ", TRUE},
319#endif
320#ifdef SIGUSR1
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200321 {SIGUSR1, "USR1", FALSE},
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000323#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100324 // Used for sysmouse handling
Bram Moolenaar071d4272004-06-13 20:20:40 +0000325 {SIGUSR2, "USR2", TRUE},
326#endif
327#ifdef SIGINT
328 {SIGINT, "INT", FALSE},
329#endif
330#ifdef SIGWINCH
331 {SIGWINCH, "WINCH", FALSE},
332#endif
333#ifdef SIGTSTP
334 {SIGTSTP, "TSTP", FALSE},
335#endif
336#ifdef SIGPIPE
337 {SIGPIPE, "PIPE", FALSE},
338#endif
339 {-1, "Unknown!", FALSE}
340};
341
Bram Moolenaar25724922009-07-14 15:38:41 +0000342 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100343mch_chdir(char *path)
Bram Moolenaar25724922009-07-14 15:38:41 +0000344{
345 if (p_verbose >= 5)
346 {
347 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100348 smsg("chdir(%s)", path);
Bram Moolenaar25724922009-07-14 15:38:41 +0000349 verbose_leave();
350 }
351# ifdef VMS
352 return chdir(vms_fixfilename(path));
353# else
354 return chdir(path);
355# endif
356}
357
Bram Moolenaar0f873732019-12-05 20:28:46 +0100358// Why is NeXT excluded here (and not in os_unixx.h)?
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +0100359#if defined(ECHOE) && defined(ICANON) \
360 && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) \
361 && !defined(__NeXT__)
Bram Moolenaar4f44b882017-08-13 20:06:18 +0200362# define NEW_TTY_SYSTEM
363#endif
364
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000365/*
Bram Moolenaard23a8232018-02-10 18:45:26 +0100366 * Write s[len] to the screen (stdout).
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000367 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100369mch_write(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000370{
Bram Moolenaar42335f52018-09-13 15:33:43 +0200371 vim_ignored = (int)write(1, (char *)s, len);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100372 if (p_wd) // Unix is too fast, slow down a bit more
Bram Moolenaar8fdd7212016-03-26 19:41:48 +0100373 RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374}
375
376/*
Bram Moolenaare40b9d42019-01-27 16:55:47 +0100377 * Function passed to inchar_loop() to handle window resizing.
378 * If "check_only" is TRUE: Return whether there was a resize.
379 * If "check_only" is FALSE: Deal with the window resized.
380 */
381 static int
382resize_func(int check_only)
383{
384 if (check_only)
385 return do_resize;
386 while (do_resize)
387 handle_resize();
388 return FALSE;
389}
390
391/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000392 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000393 * Get a characters from the keyboard.
394 * Return the number of characters that are available.
395 * If wtime == 0 do not wait for characters.
396 * If wtime == n wait a short time for characters.
397 * If wtime == -1 wait forever for characters.
398 */
399 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100400mch_inchar(
401 char_u *buf,
402 int maxlen,
Bram Moolenaar0f873732019-12-05 20:28:46 +0100403 long wtime, // don't use "time", MIPS cannot handle it
Bram Moolenaar05540972016-01-30 20:31:25 +0100404 int tb_change_cnt)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000405{
Bram Moolenaare40b9d42019-01-27 16:55:47 +0100406 return inchar_loop(buf, maxlen, wtime, tb_change_cnt,
407 WaitForChar, resize_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408}
409
410 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100411handle_resize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412{
413 do_resize = FALSE;
414 shell_resized();
415}
416
417/*
Bram Moolenaar40b1b542016-04-20 20:18:23 +0200418 * Return non-zero if a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000419 */
420 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100421mch_char_avail(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422{
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200423 return WaitForChar(0L, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424}
425
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200426#if defined(FEAT_TERMINAL) || defined(PROTO)
427/*
428 * Check for any pending input or messages.
429 */
430 int
431mch_check_messages(void)
432{
433 return WaitForChar(0L, NULL, TRUE);
434}
435#endif
436
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
438# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000439# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000440# endif
441# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
442# include <sys/sysctl.h>
443# endif
444# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
445# include <sys/sysinfo.h>
446# endif
Bram Moolenaar362dc332018-03-05 21:59:37 +0100447# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100448# include <mach/mach_host.h>
449# include <mach/mach_port.h>
Bram Moolenaar988615f2018-02-27 17:58:20 +0100450# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000451
452/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000453 * Return total amount of memory available in Kbyte.
454 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000455 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000456 long_u
Bram Moolenaar05540972016-01-30 20:31:25 +0100457mch_total_mem(int special UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000459 long_u mem = 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100460 long_u shiftright = 10; // how much to shift "mem" right for Kbyte
Bram Moolenaar071d4272004-06-13 20:20:40 +0000461
Bram Moolenaar362dc332018-03-05 21:59:37 +0100462# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100463 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100464 // Mac (Darwin) way of getting the amount of RAM available
Bram Moolenaar988615f2018-02-27 17:58:20 +0100465 mach_port_t host = mach_host_self();
466 kern_return_t kret;
467# ifdef HOST_VM_INFO64
468 struct vm_statistics64 vm_stat;
469 natural_t count = HOST_VM_INFO64_COUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470
Bram Moolenaar988615f2018-02-27 17:58:20 +0100471 kret = host_statistics64(host, HOST_VM_INFO64,
472 (host_info64_t)&vm_stat, &count);
473# else
474 struct vm_statistics vm_stat;
475 natural_t count = HOST_VM_INFO_COUNT;
476
477 kret = host_statistics(host, HOST_VM_INFO,
478 (host_info_t)&vm_stat, &count);
479# endif
480 if (kret == KERN_SUCCESS)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100481 // get the amount of user memory by summing each usage
Bram Moolenaar988615f2018-02-27 17:58:20 +0100482 mem = (long_u)(vm_stat.free_count + vm_stat.active_count
483 + vm_stat.inactive_count
484# ifdef MAC_OS_X_VERSION_10_9
485 + vm_stat.compressor_page_count
486# endif
Bram Moolenaar62b7f6a2018-03-22 21:44:07 +0100487 ) * sysconf(_SC_PAGESIZE);
Bram Moolenaar988615f2018-02-27 17:58:20 +0100488 mach_port_deallocate(mach_task_self(), host);
489 }
490# endif
491
492# ifdef HAVE_SYSCTL
493 if (mem == 0)
494 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100495 // BSD way of getting the amount of RAM available.
Bram Moolenaar988615f2018-02-27 17:58:20 +0100496 int mib[2];
497 size_t len = sizeof(long_u);
498# ifdef HW_USERMEM64
499 long_u physmem;
500# else
Bram Moolenaar0f873732019-12-05 20:28:46 +0100501 // sysctl() may return 32 bit or 64 bit, accept both
Bram Moolenaar988615f2018-02-27 17:58:20 +0100502 union {
503 int_u u32;
504 long_u u64;
505 } physmem;
506# endif
507
508 mib[0] = CTL_HW;
509# ifdef HW_USERMEM64
510 mib[1] = HW_USERMEM64;
511# else
512 mib[1] = HW_USERMEM;
513# endif
514 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
515 {
516# ifdef HW_USERMEM64
517 mem = (long_u)physmem;
518# else
519 if (len == sizeof(physmem.u64))
520 mem = (long_u)physmem.u64;
521 else
522 mem = (long_u)physmem.u32;
523# endif
524 }
525 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200526# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000527
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200528# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529 if (mem == 0)
530 {
531 struct sysinfo sinfo;
532
Bram Moolenaar0f873732019-12-05 20:28:46 +0100533 // Linux way of getting amount of RAM available
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000535 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200536# ifdef HAVE_SYSINFO_MEM_UNIT
Bram Moolenaar0f873732019-12-05 20:28:46 +0100537 // avoid overflow as much as possible
Bram Moolenaar914572a2007-05-01 11:37:47 +0000538 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
539 {
540 sinfo.mem_unit = sinfo.mem_unit >> 1;
541 --shiftright;
542 }
543 mem = sinfo.totalram * sinfo.mem_unit;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200544# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545 mem = sinfo.totalram;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200546# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000547 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200549# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200551# ifdef HAVE_SYSCONF
Bram Moolenaar071d4272004-06-13 20:20:40 +0000552 if (mem == 0)
553 {
554 long pagesize, pagecount;
555
Bram Moolenaar0f873732019-12-05 20:28:46 +0100556 // Solaris way of getting amount of RAM available
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557 pagesize = sysconf(_SC_PAGESIZE);
558 pagecount = sysconf(_SC_PHYS_PAGES);
559 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000560 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100561 // avoid overflow as much as possible
Bram Moolenaar914572a2007-05-01 11:37:47 +0000562 while (shiftright > 0 && (pagesize & 1) == 0)
563 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000564 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000565 --shiftright;
566 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000567 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000568 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000569 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200570# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000571
Bram Moolenaar0f873732019-12-05 20:28:46 +0100572 // Return the minimum of the physical memory and the user limit, because
573 // using more than the user limit may cause Vim to be terminated.
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200574# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575 {
576 struct rlimit rlp;
577
578 if (getrlimit(RLIMIT_DATA, &rlp) == 0
579 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200580# ifdef RLIM_INFINITY
Bram Moolenaar071d4272004-06-13 20:20:40 +0000581 && rlp.rlim_cur != RLIM_INFINITY
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200582# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000583 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000585 {
586 mem = (long_u)rlp.rlim_cur;
587 shiftright = 10;
588 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000589 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200590# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000591
592 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000593 return mem >> shiftright;
594 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595}
596#endif
597
Bram Moolenaar0981c872020-08-23 14:28:37 +0200598/*
599 * "flags": MCH_DELAY_IGNOREINPUT - don't read input
600 * MCH_DELAY_SETTMODE - use settmode() even for short delays
601 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602 void
Bram Moolenaar0981c872020-08-23 14:28:37 +0200603mch_delay(long msec, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000604{
Bram Moolenaar26e86442020-05-17 14:06:16 +0200605 tmode_T old_tmode;
Bram Moolenaar80361a52020-10-05 21:39:25 +0200606 int call_settmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000607#ifdef FEAT_MZSCHEME
Bram Moolenaar0f873732019-12-05 20:28:46 +0100608 long total = msec; // remember original value
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000609#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610
Bram Moolenaar0981c872020-08-23 14:28:37 +0200611 if (flags & MCH_DELAY_IGNOREINPUT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100613 // Go to cooked mode without echo, to allow SIGINT interrupting us
614 // here. But we don't want QUIT to kill us (CTRL-\ used in a
615 // shell may produce SIGQUIT).
Bram Moolenaar26e86442020-05-17 14:06:16 +0200616 // Only do this if sleeping for more than half a second.
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000617 in_mch_delay = TRUE;
Bram Moolenaar80361a52020-10-05 21:39:25 +0200618 call_settmode = mch_cur_tmode == TMODE_RAW
619 && (msec > 500 || (flags & MCH_DELAY_SETTMODE));
620 if (call_settmode)
621 {
622 old_tmode = mch_cur_tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000623 settmode(TMODE_SLEEP);
Bram Moolenaar80361a52020-10-05 21:39:25 +0200624 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625
626 /*
627 * Everybody sleeps in a different way...
628 * Prefer nanosleep(), some versions of usleep() can only sleep up to
629 * one second.
630 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000631#ifdef FEAT_MZSCHEME
632 do
633 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100634 // if total is large enough, wait by portions in p_mzq
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000635 if (total > p_mzq)
636 msec = p_mzq;
637 else
638 msec = total;
639 total -= msec;
640#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641#ifdef HAVE_NANOSLEEP
642 {
643 struct timespec ts;
644
645 ts.tv_sec = msec / 1000;
646 ts.tv_nsec = (msec % 1000) * 1000000;
647 (void)nanosleep(&ts, NULL);
648 }
649#else
650# ifdef HAVE_USLEEP
651 while (msec >= 1000)
652 {
653 usleep((unsigned int)(999 * 1000));
654 msec -= 999;
655 }
656 usleep((unsigned int)(msec * 1000));
657# else
658# ifndef HAVE_SELECT
659 poll(NULL, 0, (int)msec);
660# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661 {
662 struct timeval tv;
663
664 tv.tv_sec = msec / 1000;
665 tv.tv_usec = (msec % 1000) * 1000;
Bram Moolenaar0981c872020-08-23 14:28:37 +0200666 // NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
667 // a patch from Sun to fix this. Reported by Gunnar Pedersen.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 select(0, NULL, NULL, NULL, &tv);
669 }
Bram Moolenaar0f873732019-12-05 20:28:46 +0100670# endif // HAVE_SELECT
671# endif // HAVE_NANOSLEEP
672#endif // HAVE_USLEEP
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000673#ifdef FEAT_MZSCHEME
674 }
675 while (total > 0);
676#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677
Bram Moolenaar80361a52020-10-05 21:39:25 +0200678 if (call_settmode)
Bram Moolenaar26e86442020-05-17 14:06:16 +0200679 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000680 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681 }
682 else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200683 WaitForChar(msec, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000684}
685
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000686#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
688# define HAVE_CHECK_STACK_GROWTH
689/*
690 * Support for checking for an almost-out-of-stack-space situation.
691 */
692
693/*
694 * Return a pointer to an item on the stack. Used to find out if the stack
695 * grows up or down.
696 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000697static int stack_grows_downwards;
698
699/*
700 * Find out if the stack grows upwards or downwards.
701 * "p" points to a variable on the stack of the caller.
702 */
703 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100704check_stack_growth(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705{
706 int i;
707
708 stack_grows_downwards = (p > (char *)&i);
709}
710#endif
711
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000712#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713static char *stack_limit = NULL;
714
715#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
716# include <pthread.h>
717# include <pthread_np.h>
718#endif
719
720/*
721 * Find out until how var the stack can grow without getting into trouble.
722 * Called when starting up and when switching to the signal stack in
723 * deathtrap().
724 */
725 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100726get_stack_limit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727{
728 struct rlimit rlp;
729 int i;
730 long lim;
731
Bram Moolenaar0f873732019-12-05 20:28:46 +0100732 // Set the stack limit to 15/16 of the allowable size. Skip this when the
733 // limit doesn't fit in a long (rlim_cur might be "long long").
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 if (getrlimit(RLIMIT_STACK, &rlp) == 0
735 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
736# ifdef RLIM_INFINITY
737 && rlp.rlim_cur != RLIM_INFINITY
738# endif
739 )
740 {
741 lim = (long)rlp.rlim_cur;
742#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
743 {
744 pthread_attr_t attr;
745 size_t size;
746
Bram Moolenaar0f873732019-12-05 20:28:46 +0100747 // On FreeBSD the initial thread always has a fixed stack size, no
748 // matter what the limits are set to. Normally it's 1 Mbyte.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 pthread_attr_init(&attr);
750 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
751 {
752 pthread_attr_getstacksize(&attr, &size);
753 if (lim > (long)size)
754 lim = (long)size;
755 }
756 pthread_attr_destroy(&attr);
757 }
758#endif
759 if (stack_grows_downwards)
760 {
761 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
762 if (stack_limit >= (char *)&i)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100763 // overflow, set to 1/16 of current stack position
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764 stack_limit = (char *)((long)&i / 16L);
765 }
766 else
767 {
768 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
769 if (stack_limit <= (char *)&i)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100770 stack_limit = NULL; // overflow
Bram Moolenaar071d4272004-06-13 20:20:40 +0000771 }
772 }
773}
774
775/*
776 * Return FAIL when running out of stack space.
777 * "p" must point to any variable local to the caller that's on the stack.
778 */
779 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100780mch_stackcheck(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000781{
782 if (stack_limit != NULL)
783 {
784 if (stack_grows_downwards)
785 {
786 if (p < stack_limit)
787 return FAIL;
788 }
789 else if (p > stack_limit)
790 return FAIL;
791 }
792 return OK;
793}
794#endif
795
796#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
797/*
798 * Support for using the signal stack.
799 * This helps when we run out of stack space, which causes a SIGSEGV. The
800 * signal handler then must run on another stack, since the normal stack is
801 * completely full.
802 */
803
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804# ifdef HAVE_SIGALTSTACK
Bram Moolenaar0f873732019-12-05 20:28:46 +0100805static stack_t sigstk; // for sigaltstack()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000806# else
Bram Moolenaar0f873732019-12-05 20:28:46 +0100807static struct sigstack sigstk; // for sigstack()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808# endif
809
Zdenek Dohnalba9c23e2021-08-11 14:20:05 +0200810/*
811 * Get a size of signal stack.
812 * Preference (if available): sysconf > SIGSTKSZ > guessed size
813 */
814static long int get_signal_stack_size()
815{
816# ifdef HAVE_SYSCONF_SIGSTKSZ
817 long int size = -1;
818
819 // return size only if sysconf doesn't return an error
820 if ((size = sysconf(_SC_SIGSTKSZ)) > -1)
821 return size;
822# endif
823
824# ifdef SIGSTKSZ
825 // if sysconf() isn't available or gives error, return SIGSTKSZ
826 // if defined
827 return SIGSTKSZ;
828# endif
829
830 // otherwise guess the size
831 return 8000;
832}
833
Bram Moolenaar071d4272004-06-13 20:20:40 +0000834static char *signal_stack;
835
836 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100837init_signal_stack(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838{
839 if (signal_stack != NULL)
840 {
841# ifdef HAVE_SIGALTSTACK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000842# ifdef HAVE_SS_BASE
843 sigstk.ss_base = signal_stack;
844# else
845 sigstk.ss_sp = signal_stack;
846# endif
Zdenek Dohnalba9c23e2021-08-11 14:20:05 +0200847 sigstk.ss_size = get_signal_stack_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848 sigstk.ss_flags = 0;
849 (void)sigaltstack(&sigstk, NULL);
850# else
851 sigstk.ss_sp = signal_stack;
852 if (stack_grows_downwards)
Zdenek Dohnalba9c23e2021-08-11 14:20:05 +0200853 sigstk.ss_sp += get_signal_stack_size() - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854 sigstk.ss_onstack = 0;
855 (void)sigstack(&sigstk, NULL);
856# endif
857 }
858}
859#endif
860
861/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000862 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863 * will barf when the second argument to signal() is ``wrong''.
864 * Let me try it with a few tricky defines from my own osdef.h (jw).
865 */
866#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867 static RETSIGTYPE
868sig_winch SIGDEFARG(sigarg)
869{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100870 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaar071d4272004-06-13 20:20:40 +0000871 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
872 do_resize = TRUE;
873 SIGRETURN;
874}
875#endif
876
dbivolaruab16ad32021-12-29 19:41:47 +0000877#if defined(SIGTSTP)
878 static RETSIGTYPE
879sig_tstp SIGDEFARG(sigarg)
880{
881 // Second time we get called we actually need to suspend
882 if (in_mch_suspend)
883 {
884 signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL);
885 raise(sigarg);
886 }
dbivolaru79a6e252022-01-23 16:41:14 +0000887 else
888 got_tstp = TRUE;
dbivolaruab16ad32021-12-29 19:41:47 +0000889
890 // this is not required on all systems, but it doesn't hurt anybody
891 signal(SIGTSTP, (RETSIGTYPE (*)())sig_tstp);
dbivolaruab16ad32021-12-29 19:41:47 +0000892 SIGRETURN;
893}
894#endif
895
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000897 static RETSIGTYPE
898catch_sigint SIGDEFARG(sigarg)
899{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100900 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaar071d4272004-06-13 20:20:40 +0000901 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
902 got_int = TRUE;
903 SIGRETURN;
904}
905#endif
906
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200907#if defined(SIGUSR1)
908 static RETSIGTYPE
909catch_sigusr1 SIGDEFARG(sigarg)
910{
911 // this is not required on all systems, but it doesn't hurt anybody
912 signal(SIGUSR1, (RETSIGTYPE (*)())catch_sigusr1);
913 got_sigusr1 = TRUE;
914 SIGRETURN;
915}
916#endif
917
Bram Moolenaar071d4272004-06-13 20:20:40 +0000918#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000919 static RETSIGTYPE
920catch_sigpwr SIGDEFARG(sigarg)
921{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100922 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000923 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000924 /*
925 * I'm not sure we get the SIGPWR signal when the system is really going
926 * down or when the batteries are almost empty. Just preserve the swap
927 * files and don't exit, that can't do any harm.
928 */
929 ml_sync_all(FALSE, FALSE);
930 SIGRETURN;
931}
932#endif
933
934#ifdef SET_SIG_ALARM
935/*
936 * signal function for alarm().
937 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000938 static RETSIGTYPE
939sig_alarm SIGDEFARG(sigarg)
940{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100941 // doesn't do anything, just to break a system call
Bram Moolenaar071d4272004-06-13 20:20:40 +0000942 sig_alarm_called = TRUE;
943 SIGRETURN;
944}
945#endif
946
Bram Moolenaaredce7422019-01-20 18:39:30 +0100947#if (defined(HAVE_SETJMP_H) \
948 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
949 || defined(FEAT_LIBCALL))) \
950 || defined(PROTO)
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100951# define USING_SETJMP 1
Bram Moolenaaredce7422019-01-20 18:39:30 +0100952
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100953// argument to SETJMP()
954static JMP_BUF lc_jump_env;
955
956# ifdef SIGHASARG
Bram Moolenaar32aa1022019-11-02 22:54:41 +0100957// Caught signal number, 0 when no signal was caught; used for mch_libcall().
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100958// Volatile because it is used in signal handlers.
959static volatile sig_atomic_t lc_signal;
960# endif
961
962// TRUE when lc_jump_env is valid.
963// Volatile because it is used in signal handler deathtrap().
964static volatile sig_atomic_t lc_active INIT(= FALSE);
965
Bram Moolenaar071d4272004-06-13 20:20:40 +0000966/*
967 * A simplistic version of setjmp() that only allows one level of using.
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100968 * Used to protect areas where we could crash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000969 * Don't call twice before calling mch_endjmp()!.
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100970 *
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971 * Usage:
972 * mch_startjmp();
973 * if (SETJMP(lc_jump_env) != 0)
974 * {
975 * mch_didjmp();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100976 * emsg("crash!");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000977 * }
978 * else
979 * {
980 * do_the_work;
981 * mch_endjmp();
982 * }
983 * Note: Can't move SETJMP() here, because a function calling setjmp() must
984 * not return before the saved environment is used.
985 * Returns OK for normal return, FAIL when the protected code caused a
986 * problem and LONGJMP() was used.
987 */
Bram Moolenaar113e1072019-01-20 15:30:40 +0100988 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100989mch_startjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990{
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100991# ifdef SIGHASARG
Bram Moolenaar071d4272004-06-13 20:20:40 +0000992 lc_signal = 0;
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100993# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000994 lc_active = TRUE;
995}
996
Bram Moolenaar113e1072019-01-20 15:30:40 +0100997 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100998mch_endjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000999{
1000 lc_active = FALSE;
1001}
1002
Bram Moolenaar113e1072019-01-20 15:30:40 +01001003 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001004mch_didjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001005{
1006# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaarb7a7e032018-12-28 17:01:59 +01001007 // On FreeBSD the signal stack has to be reset after using siglongjmp(),
1008 // otherwise catching the signal only works once.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001009 init_signal_stack();
1010# endif
1011}
1012#endif
1013
1014/*
1015 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001016 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001017 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001018 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
1019 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001020 */
1021 static RETSIGTYPE
1022deathtrap SIGDEFARG(sigarg)
1023{
Bram Moolenaar0f873732019-12-05 20:28:46 +01001024 static int entered = 0; // count the number of times we got here.
1025 // Note: when memory has been corrupted
1026 // this may get an arbitrary value!
Bram Moolenaar071d4272004-06-13 20:20:40 +00001027#ifdef SIGHASARG
1028 int i;
1029#endif
1030
Bram Moolenaarb2148f52019-01-20 23:43:57 +01001031#if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001032 /*
1033 * Catch a crash in protected code.
1034 * Restores the environment saved in lc_jump_env, which looks like
1035 * SETJMP() returns 1.
1036 */
1037 if (lc_active)
1038 {
1039# if defined(SIGHASARG)
1040 lc_signal = sigarg;
1041# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01001042 lc_active = FALSE; // don't jump again
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043 LONGJMP(lc_jump_env, 1);
Bram Moolenaar0f873732019-12-05 20:28:46 +01001044 // NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045 }
1046#endif
1047
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001048#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +00001049# ifdef SIGQUIT
Bram Moolenaar0f873732019-12-05 20:28:46 +01001050 // While in mch_delay() we go to cooked mode to allow a CTRL-C to
1051 // interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
1052 // pressing CTRL-\, but we don't want Vim to exit then.
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +00001053 if (in_mch_delay && sigarg == SIGQUIT)
1054 SIGRETURN;
1055# endif
1056
Bram Moolenaar0f873732019-12-05 20:28:46 +01001057 // When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
1058 // here. This avoids that a non-reentrant function is interrupted, e.g.,
1059 // free(). Calling free() again may then cause a crash.
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001060 if (entered == 0
1061 && (0
1062# ifdef SIGHUP
1063 || sigarg == SIGHUP
1064# endif
1065# ifdef SIGQUIT
1066 || sigarg == SIGQUIT
1067# endif
1068# ifdef SIGTERM
1069 || sigarg == SIGTERM
1070# endif
1071# ifdef SIGPWR
1072 || sigarg == SIGPWR
1073# endif
1074# ifdef SIGUSR1
1075 || sigarg == SIGUSR1
1076# endif
1077# ifdef SIGUSR2
1078 || sigarg == SIGUSR2
1079# endif
1080 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001081 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001082 SIGRETURN;
1083#endif
1084
Bram Moolenaar0f873732019-12-05 20:28:46 +01001085 // Remember how often we have been called.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001086 ++entered;
1087
Bram Moolenaar0f873732019-12-05 20:28:46 +01001088 // Executing autocommands is likely to use more stack space than we have
1089 // available in the signal stack.
Bram Moolenaare429e702016-06-10 19:49:14 +02001090 block_autocmds();
Bram Moolenaare429e702016-06-10 19:49:14 +02001091
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092#ifdef FEAT_EVAL
Bram Moolenaar0f873732019-12-05 20:28:46 +01001093 // Set the v:dying variable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001094 set_vim_var_nr(VV_DYING, (long)entered);
1095#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001096 v_dying = entered;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001098#ifdef HAVE_STACK_LIMIT
Bram Moolenaar0f873732019-12-05 20:28:46 +01001099 // Since we are now using the signal stack, need to reset the stack
1100 // limit. Otherwise using a regexp will fail.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001101 get_stack_limit();
1102#endif
1103
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001104#if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01001105 // This is for opening gdb the moment Vim crashes.
1106 // You need to manually adjust the file name and Vim executable name.
1107 // Suggested by SungHyun Nam.
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001108 {
1109# define VI_GDB_FILE "/tmp/vimgdb"
1110# define VIM_NAME "/usr/bin/vim"
1111 FILE *fp = fopen(VI_GDB_FILE, "w");
1112 if (fp)
1113 {
1114 fprintf(fp,
1115 "file %s\n"
1116 "attach %d\n"
1117 "set height 1000\n"
1118 "bt full\n"
1119 , VIM_NAME, getpid());
1120 fclose(fp);
1121 system("xterm -e gdb -x "VI_GDB_FILE);
1122 unlink(VI_GDB_FILE);
1123 }
1124 }
1125#endif
1126
Bram Moolenaar071d4272004-06-13 20:20:40 +00001127#ifdef SIGHASARG
Bram Moolenaar0f873732019-12-05 20:28:46 +01001128 // try to find the name of this signal
Bram Moolenaar071d4272004-06-13 20:20:40 +00001129 for (i = 0; signal_info[i].sig != -1; i++)
1130 if (sigarg == signal_info[i].sig)
1131 break;
1132 deadly_signal = sigarg;
1133#endif
1134
Bram Moolenaar0f873732019-12-05 20:28:46 +01001135 full_screen = FALSE; // don't write message to the GUI, it might be
1136 // part of the problem...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001137 /*
1138 * If something goes wrong after entering here, we may get here again.
1139 * When this happens, give a message and try to exit nicely (resetting the
1140 * terminal mode, etc.)
1141 * When this happens twice, just exit, don't even try to give a message,
1142 * stack may be corrupt or something weird.
1143 * When this still happens again (or memory was corrupted in such a way
1144 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1145 */
1146 if (entered >= 3)
1147 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001148 reset_signals(); // don't catch any signals anymore
Bram Moolenaar071d4272004-06-13 20:20:40 +00001149 may_core_dump();
1150 if (entered >= 4)
1151 _exit(8);
1152 exit(7);
1153 }
1154 if (entered == 2)
1155 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001156 // No translation, it may call malloc().
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001157 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158 out_flush();
1159 getout(1);
1160 }
1161
Bram Moolenaar0f873732019-12-05 20:28:46 +01001162 // No translation, it may call malloc().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163#ifdef SIGHASARG
Bram Moolenaar69212b12020-05-10 14:14:03 +02001164 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\r\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165 signal_info[i].name);
1166#else
Bram Moolenaar69212b12020-05-10 14:14:03 +02001167 sprintf((char *)IObuff, "Vim: Caught deadly signal\r\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001168#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001169
Bram Moolenaar0f873732019-12-05 20:28:46 +01001170 // Preserve files and exit. This sets the really_exiting flag to prevent
1171 // calling free().
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001172 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173
Bram Moolenaar0f873732019-12-05 20:28:46 +01001174 // NOTREACHED
Bram Moolenaare429e702016-06-10 19:49:14 +02001175
Bram Moolenaar009b2592004-10-24 19:18:58 +00001176#ifdef NBDEBUG
1177 reset_signals();
1178 may_core_dump();
1179 abort();
1180#endif
1181
Bram Moolenaar071d4272004-06-13 20:20:40 +00001182 SIGRETURN;
1183}
1184
Bram Moolenaar071d4272004-06-13 20:20:40 +00001185/*
Bram Moolenaar2e310482018-08-21 13:09:10 +02001186 * Invoked after receiving SIGCONT. We don't know what happened while
1187 * sleeping, deal with part of that.
1188 */
1189 static void
1190after_sigcont(void)
1191{
Bram Moolenaar2e310482018-08-21 13:09:10 +02001192 // Don't change "oldtitle" in a signal handler, set a flag to obtain it
1193 // again later.
1194 oldtitle_outdated = TRUE;
Bram Moolenaar651fca82021-11-29 20:39:38 +00001195
Bram Moolenaar2e310482018-08-21 13:09:10 +02001196 settmode(TMODE_RAW);
1197 need_check_timestamps = TRUE;
1198 did_check_timestamps = FALSE;
1199}
1200
1201#if defined(SIGCONT)
1202static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001203
1204/*
1205 * With multi-threading, suspending might not work immediately. Catch the
1206 * SIGCONT signal, which will be used as an indication whether the suspending
1207 * has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001208 *
1209 * On Linux, signal is not always handled immediately either.
1210 * See https://bugs.launchpad.net/bugs/291373
Bram Moolenaar2e310482018-08-21 13:09:10 +02001211 * Probably because the signal is handled in another thread.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001212 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001213 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001214 */
Bram Moolenaar8e82c052018-08-21 19:47:48 +02001215static volatile sig_atomic_t sigcont_received;
Bram Moolenaarf1883472018-08-20 21:58:57 +02001216static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001217
1218/*
1219 * signal handler for SIGCONT
1220 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001221 static RETSIGTYPE
1222sigcont_handler SIGDEFARG(sigarg)
1223{
Bram Moolenaar2e310482018-08-21 13:09:10 +02001224 if (in_mch_suspend)
1225 {
1226 sigcont_received = TRUE;
1227 }
1228 else
1229 {
1230 // We didn't suspend ourselves, assume we were stopped by a SIGSTOP
1231 // signal (which can't be intercepted) and get a SIGCONT. Need to get
1232 // back to a sane mode. We should redraw, but we can't really do that
1233 // in a signal handler, do a redraw later.
1234 after_sigcont();
1235 redraw_later(CLEAR);
1236 cursor_on_force();
1237 out_flush();
1238 }
1239
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240 SIGRETURN;
1241}
1242#endif
1243
Bram Moolenaar6dff58f2018-09-30 21:43:26 +02001244#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001245# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001246static void *clip_star_save = NULL;
1247static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001248# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001249
1250/*
1251 * Called when Vim is going to sleep or execute a shell command.
1252 * We can't respond to requests for the X selections. Lose them, otherwise
1253 * other applications will hang. But first copy the text to cut buffer 0.
1254 */
1255 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001256loose_clipboard(void)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001257{
1258 if (clip_star.owned || clip_plus.owned)
1259 {
1260 x11_export_final_selection();
1261 if (clip_star.owned)
1262 clip_lose_selection(&clip_star);
1263 if (clip_plus.owned)
1264 clip_lose_selection(&clip_plus);
1265 if (x11_display != NULL)
1266 XFlush(x11_display);
1267 }
1268}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001269
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001270# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001271/*
1272 * Save clipboard text to restore later.
1273 */
1274 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001275save_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001276{
1277 if (clip_star.owned)
1278 clip_star_save = get_register('*', TRUE);
1279 if (clip_plus.owned)
1280 clip_plus_save = get_register('+', TRUE);
1281}
1282
1283/*
1284 * Restore clipboard text if no one own the X selection.
1285 */
1286 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001287restore_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001288{
1289 if (clip_star_save != NULL)
1290 {
1291 if (!clip_gen_owner_exists(&clip_star))
1292 put_register('*', clip_star_save);
1293 else
1294 free_register(clip_star_save);
1295 clip_star_save = NULL;
1296 }
1297 if (clip_plus_save != NULL)
1298 {
1299 if (!clip_gen_owner_exists(&clip_plus))
1300 put_register('+', clip_plus_save);
1301 else
1302 free_register(clip_plus_save);
1303 clip_plus_save = NULL;
1304 }
1305}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001306# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001307#endif
1308
Bram Moolenaar071d4272004-06-13 20:20:40 +00001309/*
1310 * If the machine has job control, use it to suspend the program,
1311 * otherwise fake it by starting a new shell.
1312 */
1313 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001314mch_suspend(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315{
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001316 if (ignore_sigtstp)
1317 return;
1318
Bram Moolenaar041c7102020-05-30 18:14:57 +02001319#if defined(SIGTSTP)
Bram Moolenaar2e310482018-08-21 13:09:10 +02001320 in_mch_suspend = TRUE;
1321
Bram Moolenaar0f873732019-12-05 20:28:46 +01001322 out_flush(); // needed to make cursor visible on some systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00001323 settmode(TMODE_COOK);
Bram Moolenaar0f873732019-12-05 20:28:46 +01001324 out_flush(); // needed to disable mouse on some systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325
1326# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001327 loose_clipboard();
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 sigcont_received = FALSE;
1331# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001332
Bram Moolenaar0f873732019-12-05 20:28:46 +01001333 kill(0, SIGTSTP); // send ourselves a STOP signal
Bram Moolenaar2e310482018-08-21 13:09:10 +02001334
1335# if defined(SIGCONT)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001336 /*
1337 * Wait for the SIGCONT signal to be handled. It generally happens
Bram Moolenaar2e310482018-08-21 13:09:10 +02001338 * immediately, but somehow not all the time, probably because it's handled
1339 * in another thread. Do not call pause() because there would be race
1340 * condition which would hang Vim if signal happened in between the test of
1341 * sigcont_received and the call to pause(). If signal is not yet received,
1342 * sleep 0, 1, 2, 3 ms. Don't bother waiting further if signal is not
1343 * received after 1+2+3 ms (not expected to happen).
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001344 */
1345 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001346 long wait_time;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001347
Bram Moolenaar262735e2009-07-14 10:20:22 +00001348 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar0981c872020-08-23 14:28:37 +02001349 mch_delay(wait_time, 0);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001350 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001351# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001352 in_mch_suspend = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353
Bram Moolenaar2e310482018-08-21 13:09:10 +02001354 after_sigcont();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001355#else
1356 suspend_shell();
1357#endif
1358}
1359
1360 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001361mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001362{
1363 Columns = 80;
1364 Rows = 24;
1365
1366 out_flush();
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001367
1368#ifdef SIGTSTP
1369 // Check whether we were invoked with SIGTSTP set to be ignored. If it is
1370 // that indicates the shell (or program) that launched us does not support
1371 // tty job control and thus we should ignore that signal. If invoked as a
1372 // restricted editor (e.g., as "rvim") SIGTSTP is always ignored.
1373 ignore_sigtstp = restricted || SIG_IGN == signal(SIGTSTP, SIG_ERR);
1374#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001375 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001376
Bram Moolenaar56718732006-03-15 22:53:57 +00001377#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001378 mac_conv_init();
1379#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001380#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1381 win_clip_init();
1382#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383}
1384
1385 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001386set_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001387{
1388#if defined(SIGWINCH)
1389 /*
1390 * WINDOW CHANGE signal is handled with sig_winch().
1391 */
1392 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1393#endif
1394
Bram Moolenaar071d4272004-06-13 20:20:40 +00001395#ifdef SIGTSTP
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001396 // See mch_init() for the conditions under which we ignore SIGTSTP.
Bram Moolenaar8e4af852022-01-24 12:20:45 +00001397 // In the GUI default TSTP processing is OK.
1398 // Checking both gui.in_use and gui.starting because gui.in_use is not set
1399 // at this point (set after menus are displayed), but gui.starting is set.
1400 signal(SIGTSTP, ignore_sigtstp ? SIG_IGN
1401# ifdef FEAT_GUI
1402 : gui.in_use || gui.starting ? SIG_DFL
1403# endif
1404 : (RETSIGTYPE (*)())sig_tstp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001405#endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001406#if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001407 signal(SIGCONT, sigcont_handler);
1408#endif
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001409#ifdef SIGPIPE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001410 /*
1411 * We want to ignore breaking of PIPEs.
1412 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001413 signal(SIGPIPE, SIG_IGN);
1414#endif
1415
Bram Moolenaar071d4272004-06-13 20:20:40 +00001416#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001417 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001418#endif
1419
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001420#ifdef SIGUSR1
1421 /*
1422 * Call user's handler on SIGUSR1
1423 */
1424 signal(SIGUSR1, (RETSIGTYPE (*)())catch_sigusr1);
1425#endif
1426
Bram Moolenaar071d4272004-06-13 20:20:40 +00001427 /*
1428 * Ignore alarm signals (Perl's alarm() generates it).
1429 */
1430#ifdef SIGALRM
1431 signal(SIGALRM, SIG_IGN);
1432#endif
1433
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001434#ifdef SIGPWR
Bram Moolenaar071d4272004-06-13 20:20:40 +00001435 /*
1436 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1437 * work will be lost.
1438 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001439 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1440#endif
1441
1442 /*
1443 * Arrange for other signals to gracefully shutdown Vim.
1444 */
1445 catch_signals(deathtrap, SIG_ERR);
1446
1447#if defined(FEAT_GUI) && defined(SIGHUP)
1448 /*
1449 * When the GUI is running, ignore the hangup signal.
1450 */
1451 if (gui.in_use)
1452 signal(SIGHUP, SIG_IGN);
1453#endif
1454}
1455
Bram Moolenaardf177f62005-02-22 08:39:57 +00001456#if defined(SIGINT) || defined(PROTO)
1457/*
1458 * Catch CTRL-C (only works while in Cooked mode).
1459 */
1460 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001461catch_int_signal(void)
Bram Moolenaardf177f62005-02-22 08:39:57 +00001462{
1463 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1464}
1465#endif
1466
Bram Moolenaar071d4272004-06-13 20:20:40 +00001467 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001468reset_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001469{
1470 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar2e310482018-08-21 13:09:10 +02001471#if defined(SIGCONT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001472 // SIGCONT isn't in the list, because its default action is ignore
Bram Moolenaar071d4272004-06-13 20:20:40 +00001473 signal(SIGCONT, SIG_DFL);
1474#endif
1475}
1476
1477 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001478catch_signals(
1479 RETSIGTYPE (*func_deadly)(),
1480 RETSIGTYPE (*func_other)())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001481{
1482 int i;
1483
1484 for (i = 0; signal_info[i].sig != -1; i++)
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001485 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001486 if (signal_info[i].deadly)
1487 {
1488#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1489 struct sigaction sa;
1490
Bram Moolenaar0f873732019-12-05 20:28:46 +01001491 // Setup to use the alternate stack for the signal function.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001492 sa.sa_handler = func_deadly;
1493 sigemptyset(&sa.sa_mask);
1494# if defined(__linux__) && defined(_REENTRANT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001495 // On Linux, with glibc compiled for kernel 2.2, there is a bug in
1496 // thread handling in combination with using the alternate stack:
1497 // pthread library functions try to use the stack pointer to
1498 // identify the current thread, causing a SEGV signal, which
1499 // recursively calls deathtrap() and hangs.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001500 sa.sa_flags = 0;
1501# else
1502 sa.sa_flags = SA_ONSTACK;
1503# endif
1504 sigaction(signal_info[i].sig, &sa, NULL);
1505#else
1506# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1507 struct sigvec sv;
1508
Bram Moolenaar0f873732019-12-05 20:28:46 +01001509 // Setup to use the alternate stack for the signal function.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001510 sv.sv_handler = func_deadly;
1511 sv.sv_mask = 0;
1512 sv.sv_flags = SV_ONSTACK;
1513 sigvec(signal_info[i].sig, &sv, NULL);
1514# else
1515 signal(signal_info[i].sig, func_deadly);
1516# endif
1517#endif
1518 }
1519 else if (func_other != SIG_ERR)
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001520 {
1521 // Deal with non-deadly signals.
1522#ifdef SIGTSTP
1523 signal(signal_info[i].sig,
1524 signal_info[i].sig == SIGTSTP && ignore_sigtstp
1525 ? SIG_IGN : func_other);
1526#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001527 signal(signal_info[i].sig, func_other);
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001528#endif
1529 }
1530 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001531}
1532
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001533#ifdef HAVE_SIGPROCMASK
1534 static void
1535block_signals(sigset_t *set)
1536{
1537 sigset_t newset;
1538 int i;
1539
1540 sigemptyset(&newset);
1541
1542 for (i = 0; signal_info[i].sig != -1; i++)
1543 sigaddset(&newset, signal_info[i].sig);
1544
Bram Moolenaar2e310482018-08-21 13:09:10 +02001545# if defined(SIGCONT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001546 // SIGCONT isn't in the list, because its default action is ignore
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001547 sigaddset(&newset, SIGCONT);
1548# endif
1549
1550 sigprocmask(SIG_BLOCK, &newset, set);
1551}
1552
1553 static void
1554unblock_signals(sigset_t *set)
1555{
1556 sigprocmask(SIG_SETMASK, set, NULL);
1557}
1558#endif
1559
Bram Moolenaar071d4272004-06-13 20:20:40 +00001560/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001561 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001562 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1563 * return TRUE
1564 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1565 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001566 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001567 * Returns TRUE when Vim should exit.
1568 */
1569 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001570vim_handle_signal(int sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001571{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001572 static int got_signal = 0;
1573 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001574
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001575 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001576 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001577 case SIGNAL_BLOCK: blocked = TRUE;
1578 break;
1579
1580 case SIGNAL_UNBLOCK: blocked = FALSE;
1581 if (got_signal != 0)
1582 {
1583 kill(getpid(), got_signal);
1584 got_signal = 0;
1585 }
1586 break;
1587
1588 default: if (!blocked)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001589 return TRUE; // exit!
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001590 got_signal = sig;
1591#ifdef SIGPWR
1592 if (sig != SIGPWR)
1593#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01001594 got_int = TRUE; // break any loops
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001595 break;
1596 }
1597 return FALSE;
1598}
1599
1600/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001601 * Check_win checks whether we have an interactive stdout.
1602 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001603 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001604mch_check_win(int argc UNUSED, char **argv UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001605{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606 if (isatty(1))
1607 return OK;
1608 return FAIL;
1609}
1610
1611/*
1612 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1613 */
1614 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001615mch_input_isatty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616{
1617 if (isatty(read_cmd_fd))
1618 return TRUE;
1619 return FALSE;
1620}
1621
1622#ifdef FEAT_X11
1623
Bram Moolenaar651fca82021-11-29 20:39:38 +00001624# if defined(ELAPSED_TIMEVAL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001625
Bram Moolenaar071d4272004-06-13 20:20:40 +00001626/*
1627 * Give a message about the elapsed time for opening the X window.
1628 */
1629 static void
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001630xopen_message(long elapsed_msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001631{
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001632 smsg(_("Opening the X display took %ld msec"), elapsed_msec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001633}
1634# endif
1635#endif
1636
Bram Moolenaar651fca82021-11-29 20:39:38 +00001637#if defined(FEAT_X11)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001638/*
1639 * A few functions shared by X11 title and clipboard code.
1640 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001641
1642static int got_x_error = FALSE;
1643
1644/*
1645 * X Error handler, otherwise X just exits! (very rude) -- webb
1646 */
1647 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001648x_error_handler(Display *dpy, XErrorEvent *error_event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001649{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001650 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001651 STRCAT(IObuff, _("\nVim: Got X error\n"));
1652
Bram Moolenaarb1062eb2020-05-09 16:11:33 +02001653 // In the GUI we cannot print a message and continue, because no X calls
1654 // are allowed here (causes my system to hang). Silently continuing seems
1655 // like the best alternative. Do preserve files, in case we crash.
1656 ml_sync_all(FALSE, FALSE);
1657
1658#ifdef FEAT_GUI
1659 if (!gui.in_use)
1660#endif
1661 msg((char *)IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001662
Bram Moolenaar0f873732019-12-05 20:28:46 +01001663 return 0; // NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +00001664}
1665
1666/*
1667 * Another X Error handler, just used to check for errors.
1668 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001669 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001670x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001671{
1672 got_x_error = TRUE;
1673 return 0;
1674}
1675
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001676/*
1677 * Return TRUE when connection to the X server is desired.
1678 */
1679 static int
1680x_connect_to_server(void)
1681{
1682 // No point in connecting if we are exiting or dying.
1683 if (exiting || v_dying)
1684 return FALSE;
1685
1686#if defined(FEAT_CLIENTSERVER)
1687 if (x_force_connect)
1688 return TRUE;
1689#endif
1690 if (x_no_connect)
1691 return FALSE;
1692
Bram Moolenaara8bfa172018-12-29 22:28:46 +01001693 // Check for a match with "exclude:" from 'clipboard'.
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001694 if (clip_exclude_prog != NULL)
1695 {
Bram Moolenaara8bfa172018-12-29 22:28:46 +01001696 // Just in case we get called recursively, return FALSE. This could
1697 // happen if vpeekc() is used while executing the prog and it causes a
1698 // related callback to be invoked.
1699 if (regprog_in_use(clip_exclude_prog))
1700 return FALSE;
1701
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001702 if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
1703 return FALSE;
1704 }
1705 return TRUE;
1706}
1707
Bram Moolenaar071d4272004-06-13 20:20:40 +00001708#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaarb2148f52019-01-20 23:43:57 +01001709# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001710/*
1711 * An X IO Error handler, used to catch error while opening the display.
1712 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001713 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001714x_IOerror_check(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001715{
Bram Moolenaar0f873732019-12-05 20:28:46 +01001716 // This function should not return, it causes exit(). Longjump instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001717 LONGJMP(lc_jump_env, 1);
Bram Moolenaar1eed5322019-02-26 17:03:54 +01001718# if defined(VMS) || defined(__CYGWIN__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001719 return 0; // avoid the compiler complains about missing return value
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001720# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001721}
1722# endif
1723
1724/*
1725 * An X IO Error handler, used to catch terminal errors.
1726 */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001727static int xterm_dpy_retry_count = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001728
Bram Moolenaar071d4272004-06-13 20:20:40 +00001729 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001730x_IOerror_handler(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001731{
1732 xterm_dpy = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001733 xterm_dpy_retry_count = 5; // Try reconnecting five times
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734 x11_window = 0;
1735 x11_display = NULL;
1736 xterm_Shell = (Widget)0;
1737
Bram Moolenaar0f873732019-12-05 20:28:46 +01001738 // This function should not return, it causes exit(). Longjump instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739 LONGJMP(x_jump_env, 1);
Bram Moolenaar1eed5322019-02-26 17:03:54 +01001740# if defined(VMS) || defined(__CYGWIN__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001741 return 0; // avoid the compiler complains about missing return value
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001742# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743}
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001744
1745/*
1746 * If the X11 connection was lost try to restore it.
1747 * Helps when the X11 server was stopped and restarted while Vim was inactive
Bram Moolenaarcaad4f02014-12-17 14:36:14 +01001748 * (e.g. through tmux).
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001749 */
1750 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001751may_restore_clipboard(void)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001752{
Bram Moolenaar01e51e52018-12-29 13:09:46 +01001753 // No point in restoring the connecting if we are exiting or dying.
1754 if (!exiting && !v_dying && xterm_dpy_retry_count > 0)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001755 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001756 --xterm_dpy_retry_count;
Bram Moolenaar527a6782014-12-17 17:59:31 +01001757
1758# ifndef LESSTIF_VERSION
Bram Moolenaar0f873732019-12-05 20:28:46 +01001759 // This has been reported to avoid Vim getting stuck.
Bram Moolenaar527a6782014-12-17 17:59:31 +01001760 if (app_context != (XtAppContext)NULL)
1761 {
1762 XtDestroyApplicationContext(app_context);
1763 app_context = (XtAppContext)NULL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01001764 x11_display = NULL; // freed by XtDestroyApplicationContext()
Bram Moolenaar527a6782014-12-17 17:59:31 +01001765 }
1766# endif
1767
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001768 setup_term_clip();
1769 get_x11_title(FALSE);
1770 }
1771}
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001772
1773 void
1774ex_xrestore(exarg_T *eap)
1775{
1776 if (eap->arg != NULL && STRLEN(eap->arg) > 0)
1777 {
1778 if (xterm_display_allocated)
1779 vim_free(xterm_display);
1780 xterm_display = (char *)vim_strsave(eap->arg);
1781 xterm_display_allocated = TRUE;
1782 }
1783 smsg(_("restoring display %s"), xterm_display == NULL
Bram Moolenaar0c5c3fa2019-11-30 22:38:16 +01001784 ? (char *)mch_getenv((char_u *)"DISPLAY") : xterm_display);
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001785
1786 clear_xterm_clip();
1787 x11_window = 0;
1788 xterm_dpy_retry_count = 5; // Try reconnecting five times
1789 may_restore_clipboard();
1790}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791#endif
1792
1793/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001794 * Test if "dpy" and x11_window are valid by getting the window title.
1795 * I don't actually want it yet, so there may be a simpler call to use, but
1796 * this will cause the error handler x_error_check() to be called if anything
1797 * is wrong, such as the window pointer being invalid (as can happen when the
1798 * user changes his DISPLAY, but not his WINDOWID) -- webb
1799 */
1800 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001801test_x11_window(Display *dpy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001802{
1803 int (*old_handler)();
1804 XTextProperty text_prop;
1805
1806 old_handler = XSetErrorHandler(x_error_check);
1807 got_x_error = FALSE;
1808 if (XGetWMName(dpy, x11_window, &text_prop))
1809 XFree((void *)text_prop.value);
1810 XSync(dpy, False);
1811 (void)XSetErrorHandler(old_handler);
1812
1813 if (p_verbose > 0 && got_x_error)
Bram Moolenaar32526b32019-01-19 17:43:09 +01001814 verb_msg(_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815
1816 return (got_x_error ? FAIL : OK);
1817}
1818#endif
1819
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820
1821#ifdef FEAT_X11
1822
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001823static int get_x11_thing(int get_title, int test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824
1825/*
1826 * try to get x11 window and display
1827 *
1828 * return FAIL for failure, OK otherwise
1829 */
1830 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001831get_x11_windis(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832{
1833 char *winid;
1834 static int result = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01001835#define XD_NONE 0 // x11_display not set here
1836#define XD_HERE 1 // x11_display opened here
1837#define XD_GUI 2 // x11_display used from gui.dpy
1838#define XD_XTERM 3 // x11_display used from xterm_dpy
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839 static int x11_display_from = XD_NONE;
1840 static int did_set_error_handler = FALSE;
1841
1842 if (!did_set_error_handler)
1843 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001844 // X just exits if it finds an error otherwise!
Bram Moolenaar071d4272004-06-13 20:20:40 +00001845 (void)XSetErrorHandler(x_error_handler);
1846 did_set_error_handler = TRUE;
1847 }
1848
Bram Moolenaar9372a112005-12-06 19:59:18 +00001849#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850 if (gui.in_use)
1851 {
1852 /*
1853 * If the X11 display was opened here before, for the window where Vim
1854 * was started, close that one now to avoid a memory leak.
1855 */
1856 if (x11_display_from == XD_HERE && x11_display != NULL)
1857 {
1858 XCloseDisplay(x11_display);
1859 x11_display_from = XD_NONE;
1860 }
1861 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1862 {
1863 x11_display_from = XD_GUI;
1864 return OK;
1865 }
1866 x11_display = NULL;
1867 return FAIL;
1868 }
1869 else if (x11_display_from == XD_GUI)
1870 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001871 // GUI must have stopped somehow, clear x11_display
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 x11_window = 0;
1873 x11_display = NULL;
1874 x11_display_from = XD_NONE;
1875 }
1876#endif
1877
Bram Moolenaar0f873732019-12-05 20:28:46 +01001878 // When started with the "-X" argument, don't try connecting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879 if (!x_connect_to_server())
1880 return FAIL;
1881
1882 /*
1883 * If WINDOWID not set, should try another method to find out
1884 * what the current window number is. The only code I know for
1885 * this is very complicated.
1886 * We assume that zero is invalid for WINDOWID.
1887 */
1888 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1889 x11_window = (Window)atol(winid);
1890
1891#ifdef FEAT_XCLIPBOARD
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001892 if (xterm_dpy == x11_display)
1893 // x11_display may have been set to xterm_dpy elsewhere
1894 x11_display_from = XD_XTERM;
1895
Bram Moolenaar071d4272004-06-13 20:20:40 +00001896 if (xterm_dpy != NULL && x11_window != 0)
1897 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001898 // We may have checked it already, but Gnome terminal can move us to
1899 // another window, so we need to check every time.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001900 if (x11_display_from != XD_XTERM)
1901 {
1902 /*
1903 * If the X11 display was opened here before, for the window where
1904 * Vim was started, close that one now to avoid a memory leak.
1905 */
1906 if (x11_display_from == XD_HERE && x11_display != NULL)
1907 XCloseDisplay(x11_display);
1908 x11_display = xterm_dpy;
1909 x11_display_from = XD_XTERM;
1910 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001911 if (test_x11_window(x11_display) == FAIL)
1912 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001913 // probably bad $WINDOWID
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914 x11_window = 0;
1915 x11_display = NULL;
1916 x11_display_from = XD_NONE;
1917 return FAIL;
1918 }
1919 return OK;
1920 }
1921#endif
1922
1923 if (x11_window == 0 || x11_display == NULL)
1924 result = -1;
1925
Bram Moolenaar0f873732019-12-05 20:28:46 +01001926 if (result != -1) // Have already been here and set this
1927 return result; // Don't do all these X calls again
Bram Moolenaar071d4272004-06-13 20:20:40 +00001928
1929 if (x11_window != 0 && x11_display == NULL)
1930 {
1931#ifdef SET_SIG_ALARM
1932 RETSIGTYPE (*sig_save)();
1933#endif
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01001934#ifdef ELAPSED_FUNC
1935 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936
1937 if (p_verbose > 0)
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01001938 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939#endif
1940
1941#ifdef SET_SIG_ALARM
1942 /*
1943 * Opening the Display may hang if the DISPLAY setting is wrong, or
1944 * the network connection is bad. Set an alarm timer to get out.
1945 */
1946 sig_alarm_called = FALSE;
1947 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1948 (RETSIGTYPE (*)())sig_alarm);
1949 alarm(2);
1950#endif
1951 x11_display = XOpenDisplay(NULL);
1952
1953#ifdef SET_SIG_ALARM
1954 alarm(0);
1955 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1956 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaar563bbea2019-01-22 21:45:40 +01001957 verb_msg(_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958#endif
1959 if (x11_display != NULL)
1960 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001961# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00001962 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001963 {
1964 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001965 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001966 verbose_leave();
1967 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001968# endif
1969 if (test_x11_window(x11_display) == FAIL)
1970 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001971 // Maybe window id is bad
Bram Moolenaar071d4272004-06-13 20:20:40 +00001972 x11_window = 0;
1973 XCloseDisplay(x11_display);
1974 x11_display = NULL;
1975 }
1976 else
1977 x11_display_from = XD_HERE;
1978 }
1979 }
1980 if (x11_window == 0 || x11_display == NULL)
1981 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001982
1983# ifdef FEAT_EVAL
1984 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1985# endif
1986
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987 return (result = OK);
1988}
1989
1990/*
1991 * Determine original x11 Window Title
1992 */
1993 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001994get_x11_title(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001996 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001997}
1998
1999/*
2000 * Determine original x11 Window icon
2001 */
2002 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01002003get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002004{
2005 int retval = FALSE;
2006
2007 retval = get_x11_thing(FALSE, test_only);
2008
Bram Moolenaar0f873732019-12-05 20:28:46 +01002009 // could not get old icon, use terminal name
Bram Moolenaar071d4272004-06-13 20:20:40 +00002010 if (oldicon == NULL && !test_only)
2011 {
2012 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002013 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002014 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002015 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002016 }
2017
2018 return retval;
2019}
2020
2021 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01002022get_x11_thing(
Bram Moolenaar0f873732019-12-05 20:28:46 +01002023 int get_title, // get title string
Bram Moolenaar05540972016-01-30 20:31:25 +01002024 int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002025{
2026 XTextProperty text_prop;
2027 int retval = FALSE;
2028 Status status;
2029
2030 if (get_x11_windis() == OK)
2031 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002032 // Get window/icon name if any
Bram Moolenaar071d4272004-06-13 20:20:40 +00002033 if (get_title)
2034 status = XGetWMName(x11_display, x11_window, &text_prop);
2035 else
2036 status = XGetWMIconName(x11_display, x11_window, &text_prop);
2037
2038 /*
2039 * If terminal is xterm, then x11_window may be a child window of the
2040 * outer xterm window that actually contains the window/icon name, so
2041 * keep traversing up the tree until a window with a title/icon is
2042 * found.
2043 */
Bram Moolenaar4b96df52020-01-26 22:00:26 +01002044 // Previously this was only done for xterm and alike. I don't see a
Bram Moolenaar0f873732019-12-05 20:28:46 +01002045 // reason why it would fail for other terminal emulators.
2046 // if (term_is_xterm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002047 {
2048 Window root;
2049 Window parent;
2050 Window win = x11_window;
2051 Window *children;
2052 unsigned int num_children;
2053
2054 while (!status || text_prop.value == NULL)
2055 {
2056 if (!XQueryTree(x11_display, win, &root, &parent, &children,
2057 &num_children))
2058 break;
2059 if (children)
2060 XFree((void *)children);
2061 if (parent == root || parent == 0)
2062 break;
2063
2064 win = parent;
2065 if (get_title)
2066 status = XGetWMName(x11_display, win, &text_prop);
2067 else
2068 status = XGetWMIconName(x11_display, win, &text_prop);
2069 }
2070 }
2071 if (status && text_prop.value != NULL)
2072 {
2073 retval = TRUE;
2074 if (!test_only)
2075 {
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002076 if (get_title)
2077 vim_free(oldtitle);
2078 else
2079 vim_free(oldicon);
Bram Moolenaara12a1612019-01-24 16:39:02 +01002080 if (text_prop.encoding == XA_STRING && !has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002081 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002082 if (get_title)
2083 oldtitle = vim_strsave((char_u *)text_prop.value);
2084 else
2085 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002086 }
2087 else
2088 {
2089 char **cl;
2090 Status transform_status;
2091 int n = 0;
2092
2093 transform_status = XmbTextPropertyToTextList(x11_display,
2094 &text_prop,
2095 &cl, &n);
2096 if (transform_status >= Success && n > 0 && cl[0])
2097 {
2098 if (get_title)
2099 oldtitle = vim_strsave((char_u *) cl[0]);
2100 else
2101 oldicon = vim_strsave((char_u *) cl[0]);
2102 XFreeStringList(cl);
2103 }
2104 else
2105 {
2106 if (get_title)
2107 oldtitle = vim_strsave((char_u *)text_prop.value);
2108 else
2109 oldicon = vim_strsave((char_u *)text_prop.value);
2110 }
2111 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112 }
2113 XFree((void *)text_prop.value);
2114 }
2115 }
2116 return retval;
2117}
2118
Bram Moolenaar0f873732019-12-05 20:28:46 +01002119// Xutf8 functions are not available on older systems. Note that on some
2120// systems X_HAVE_UTF8_STRING may be defined in a header file but
2121// Xutf8SetWMProperties() is not in the X11 library. Configure checks for
2122// that and defines HAVE_XUTF8SETWMPROPERTIES.
Bram Moolenaara12a1612019-01-24 16:39:02 +01002123#if defined(X_HAVE_UTF8_STRING)
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002124# if X_HAVE_UTF8_STRING && HAVE_XUTF8SETWMPROPERTIES
Bram Moolenaar071d4272004-06-13 20:20:40 +00002125# define USE_UTF8_STRING
2126# endif
2127#endif
2128
2129/*
2130 * Set x11 Window Title
2131 *
2132 * get_x11_windis() must be called before this and have returned OK
2133 */
2134 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002135set_x11_title(char_u *title)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002136{
Bram Moolenaar0f873732019-12-05 20:28:46 +01002137 // XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
2138 // when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
2139 // supported everywhere and STRING doesn't work for multi-byte titles.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002140#ifdef USE_UTF8_STRING
2141 if (enc_utf8)
2142 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
2143 NULL, NULL, 0, NULL, NULL, NULL);
2144 else
2145#endif
2146 {
2147#if XtSpecificationRelease >= 4
2148# ifdef FEAT_XFONTSET
2149 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
2150 NULL, NULL, 0, NULL, NULL, NULL);
2151# else
2152 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002153 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002154
Bram Moolenaar0f873732019-12-05 20:28:46 +01002155 // directly from example 3-18 "basicwin" of Xlib Programming Manual
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002156 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002157 XSetWMProperties(x11_display, x11_window, &text_prop,
2158 NULL, NULL, 0, NULL, NULL, NULL);
2159# endif
2160#else
2161 XStoreName(x11_display, x11_window, (char *)title);
2162#endif
2163 }
2164 XFlush(x11_display);
2165}
2166
2167/*
2168 * Set x11 Window icon
2169 *
2170 * get_x11_windis() must be called before this and have returned OK
2171 */
2172 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002173set_x11_icon(char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002174{
Bram Moolenaar0f873732019-12-05 20:28:46 +01002175 // See above for comments about using X*SetWMProperties().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002176#ifdef USE_UTF8_STRING
2177 if (enc_utf8)
2178 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2179 NULL, 0, NULL, NULL, NULL);
2180 else
2181#endif
2182 {
2183#if XtSpecificationRelease >= 4
2184# ifdef FEAT_XFONTSET
2185 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2186 NULL, 0, NULL, NULL, NULL);
2187# else
2188 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002189 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002190
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002191 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002192 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2193 NULL, 0, NULL, NULL, NULL);
2194# endif
2195#else
2196 XSetIconName(x11_display, x11_window, (char *)icon);
2197#endif
2198 }
2199 XFlush(x11_display);
2200}
2201
Bram Moolenaar0f873732019-12-05 20:28:46 +01002202#else // FEAT_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002203
Bram Moolenaar071d4272004-06-13 20:20:40 +00002204 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002205get_x11_title(int test_only UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002206{
2207 return FALSE;
2208}
2209
2210 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002211get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002212{
2213 if (!test_only)
2214 {
2215 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002216 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002218 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002219 }
2220 return FALSE;
2221}
2222
Bram Moolenaar0f873732019-12-05 20:28:46 +01002223#endif // FEAT_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002224
2225 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002226mch_can_restore_title(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002227{
2228 return get_x11_title(TRUE);
2229}
2230
2231 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002232mch_can_restore_icon(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002233{
2234 return get_x11_icon(TRUE);
2235}
2236
2237/*
2238 * Set the window title and icon.
2239 */
2240 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002241mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002242{
2243 int type = 0;
2244 static int recursive = 0;
2245
Bram Moolenaar0f873732019-12-05 20:28:46 +01002246 if (T_NAME == NULL) // no terminal name (yet)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002247 return;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002248 if (title == NULL && icon == NULL) // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249 return;
2250
Bram Moolenaar0f873732019-12-05 20:28:46 +01002251 // When one of the X11 functions causes a deadly signal, we get here again
2252 // recursively. Avoid hanging then (something is probably locked).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002253 if (recursive)
2254 return;
2255 ++recursive;
2256
2257 /*
2258 * if the window ID and the display is known, we may use X11 calls
2259 */
2260#ifdef FEAT_X11
2261 if (get_x11_windis() == OK)
2262 type = 1;
2263#else
Bram Moolenaar097148e2020-08-11 21:58:20 +02002264# if defined(FEAT_GUI_PHOTON) \
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002265 || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 if (gui.in_use)
2267 type = 1;
2268# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269#endif
2270
2271 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002272 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002273 * than x11 calls, because the x11 calls don't always work
2274 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002275 if ((type || *T_TS != NUL) && title != NULL)
2276 {
Bram Moolenaard8f0cef2018-08-19 22:20:16 +02002277 if (oldtitle_outdated)
2278 {
2279 oldtitle_outdated = FALSE;
2280 VIM_CLEAR(oldtitle);
2281 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 if (oldtitle == NULL
2283#ifdef FEAT_GUI
2284 && !gui.in_use
2285#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002286 ) // first call but not in GUI, save title
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287 (void)get_x11_title(FALSE);
2288
Bram Moolenaar0f873732019-12-05 20:28:46 +01002289 if (*T_TS != NUL) // it's OK if t_fs is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00002290 term_settitle(title);
2291#ifdef FEAT_X11
2292 else
2293# ifdef FEAT_GUI_GTK
Bram Moolenaar0f873732019-12-05 20:28:46 +01002294 if (!gui.in_use) // don't do this if GTK+ is running
Bram Moolenaar071d4272004-06-13 20:20:40 +00002295# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002296 set_x11_title(title); // x11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002298#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) \
Bram Moolenaar097148e2020-08-11 21:58:20 +02002299 || defined(FEAT_GUI_PHOTON)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300 else
2301 gui_mch_settitle(title, icon);
2302#endif
Bram Moolenaardac13472019-09-16 21:06:21 +02002303 unix_did_set_title = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002304 }
2305
2306 if ((type || *T_CIS != NUL) && icon != NULL)
2307 {
2308 if (oldicon == NULL
2309#ifdef FEAT_GUI
2310 && !gui.in_use
2311#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002312 ) // first call, save icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002313 get_x11_icon(FALSE);
2314
2315 if (*T_CIS != NUL)
2316 {
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02002317 out_str(T_CIS); // set icon start
Bram Moolenaar071d4272004-06-13 20:20:40 +00002318 out_str_nf(icon);
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02002319 out_str(T_CIE); // set icon end
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 out_flush();
2321 }
2322#ifdef FEAT_X11
2323 else
2324# ifdef FEAT_GUI_GTK
Bram Moolenaar0f873732019-12-05 20:28:46 +01002325 if (!gui.in_use) // don't do this if GTK+ is running
Bram Moolenaar071d4272004-06-13 20:20:40 +00002326# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002327 set_x11_icon(icon); // x11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328#endif
2329 did_set_icon = TRUE;
2330 }
2331 --recursive;
2332}
2333
2334/*
2335 * Restore the window/icon title.
2336 * "which" is one of:
Bram Moolenaar40385db2018-08-07 22:31:44 +02002337 * SAVE_RESTORE_TITLE only restore title
2338 * SAVE_RESTORE_ICON only restore icon
2339 * SAVE_RESTORE_BOTH restore title and icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002340 */
2341 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002342mch_restore_title(int which)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002343{
Bram Moolenaardac13472019-09-16 21:06:21 +02002344 int do_push_pop = unix_did_set_title || did_set_icon;
Bram Moolenaare5c83282019-05-03 23:15:37 +02002345
Bram Moolenaar0f873732019-12-05 20:28:46 +01002346 // only restore the title or icon when it has been set
Bram Moolenaardac13472019-09-16 21:06:21 +02002347 mch_settitle(((which & SAVE_RESTORE_TITLE) && unix_did_set_title) ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348 (oldtitle ? oldtitle : p_titleold) : NULL,
Bram Moolenaar40385db2018-08-07 22:31:44 +02002349 ((which & SAVE_RESTORE_ICON) && did_set_icon) ? oldicon : NULL);
2350
Bram Moolenaare5c83282019-05-03 23:15:37 +02002351 if (do_push_pop)
2352 {
2353 // pop and push from/to the stack
2354 term_pop_title(which);
2355 term_push_title(which);
2356 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002357}
2358
Bram Moolenaar071d4272004-06-13 20:20:40 +00002359
2360/*
2361 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002362 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 */
2364 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002365vim_is_xterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366{
2367 if (name == NULL)
2368 return FALSE;
2369 return (STRNICMP(name, "xterm", 5) == 0
2370 || STRNICMP(name, "nxterm", 6) == 0
2371 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002372 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002373 || STRNICMP(name, "rxvt", 4) == 0
Bram Moolenaar995e4af2017-09-01 20:24:03 +02002374 || STRNICMP(name, "screen.xterm", 12) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375 || STRCMP(name, "builtin_xterm") == 0);
2376}
2377
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002378#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2379/*
2380 * Return TRUE if "name" appears to be that of a terminal
2381 * known to support the xterm-style mouse protocol.
2382 * Relies on term_is_xterm having been set to its correct value.
2383 */
2384 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002385use_xterm_like_mouse(char_u *name)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002386{
2387 return (name != NULL
Bram Moolenaare56132b2016-08-14 18:23:21 +02002388 && (term_is_xterm
2389 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002390 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaar48873ae2021-12-08 21:00:24 +00002391 || STRNICMP(name, "gnome", 5) == 0
Bram Moolenaare56132b2016-08-14 18:23:21 +02002392 || STRICMP(name, "st") == 0
2393 || STRNICMP(name, "st-", 3) == 0
2394 || STRNICMP(name, "stterm", 6) == 0));
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002395}
2396#endif
2397
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398/*
2399 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2400 * Return 1 for "xterm".
2401 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002402 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002403 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404 */
2405 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002406use_xterm_mouse(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002407{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002408 if (ttym_flags == TTYM_SGR)
2409 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002410 if (ttym_flags == TTYM_URXVT)
2411 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002412 if (ttym_flags == TTYM_XTERM2)
2413 return 2;
2414 if (ttym_flags == TTYM_XTERM)
2415 return 1;
2416 return 0;
2417}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002418
2419 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002420vim_is_iris(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002421{
2422 if (name == NULL)
2423 return FALSE;
2424 return (STRNICMP(name, "iris-ansi", 9) == 0
2425 || STRCMP(name, "builtin_iris-ansi") == 0);
2426}
2427
2428 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002429vim_is_vt300(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430{
2431 if (name == NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01002432 return FALSE; // actually all ANSI comp. terminals should be here
2433 // catch VT100 - VT5xx
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002434 return ((STRNICMP(name, "vt", 2) == 0
2435 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002436 || STRCMP(name, "builtin_vt320") == 0);
2437}
2438
2439/*
2440 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2441 * This should include all windowed terminal emulators.
2442 */
2443 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002444vim_is_fastterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002445{
2446 if (name == NULL)
2447 return FALSE;
2448 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2449 return TRUE;
2450 return ( STRNICMP(name, "hpterm", 6) == 0
2451 || STRNICMP(name, "sun-cmd", 7) == 0
2452 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002453 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454 || STRNICMP(name, "dtterm", 6) == 0);
2455}
2456
2457/*
2458 * Insert user name in s[len].
2459 * Return OK if a name found.
2460 */
2461 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002462mch_get_user_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463{
2464#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002465 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466 return OK;
2467#else
2468 return mch_get_uname(getuid(), s, len);
2469#endif
2470}
2471
2472/*
2473 * Insert user name for "uid" in s[len].
2474 * Return OK if a name found.
2475 */
2476 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002477mch_get_uname(uid_t uid, char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002478{
2479#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2480 struct passwd *pw;
2481
2482 if ((pw = getpwuid(uid)) != NULL
2483 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2484 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002485 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002486 return OK;
2487 }
2488#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002489 sprintf((char *)s, "%d", (int)uid); // assumes s is long enough
2490 return FAIL; // a number is not a name
Bram Moolenaar071d4272004-06-13 20:20:40 +00002491}
2492
2493/*
2494 * Insert host name is s[len].
2495 */
2496
2497#ifdef HAVE_SYS_UTSNAME_H
2498 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002499mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500{
2501 struct utsname vutsname;
2502
2503 if (uname(&vutsname) < 0)
2504 *s = NUL;
2505 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002506 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002508#else // HAVE_SYS_UTSNAME_H
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509
2510# ifdef HAVE_SYS_SYSTEMINFO_H
2511# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2512# endif
2513
2514 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002515mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516{
2517# ifdef VAXC
2518 vaxc$gethostname((char *)s, len);
2519# else
2520 gethostname((char *)s, len);
2521# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002522 s[len - 1] = NUL; // make sure it's terminated
Bram Moolenaar071d4272004-06-13 20:20:40 +00002523}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002524#endif // HAVE_SYS_UTSNAME_H
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525
2526/*
2527 * return process ID
2528 */
2529 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002530mch_get_pid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531{
2532 return (long)getpid();
2533}
2534
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002535/*
2536 * return TRUE if process "pid" is still running
2537 */
2538 int
Bram Moolenaar1b243ea2019-04-28 22:50:40 +02002539mch_process_running(long pid)
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002540{
Bram Moolenaar44dea9d2021-06-23 21:13:20 +02002541 // If there is no error the process must be running.
2542 if (kill(pid, 0) == 0)
2543 return TRUE;
2544#ifdef ESRCH
2545 // If the error is ESRCH then the process is not running.
2546 if (errno == ESRCH)
2547 return FALSE;
2548#endif
2549 // If the process is running and owned by another user we get EPERM. With
2550 // other errors the process might be running, assuming it is then.
2551 return TRUE;
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002552}
2553
Bram Moolenaar071d4272004-06-13 20:20:40 +00002554#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002555 static char *
Bram Moolenaar05540972016-01-30 20:31:25 +01002556strerror(int err)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557{
2558 extern int sys_nerr;
2559 extern char *sys_errlist[];
2560 static char er[20];
2561
2562 if (err > 0 && err < sys_nerr)
2563 return (sys_errlist[err]);
2564 sprintf(er, "Error %d", err);
2565 return er;
2566}
2567#endif
2568
2569/*
Bram Moolenaar964b3742019-05-24 18:54:09 +02002570 * Get name of current directory into buffer "buf" of length "len" bytes.
2571 * "len" must be at least PATH_MAX.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 * Return OK for success, FAIL for failure.
2573 */
2574 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002575mch_dirname(char_u *buf, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002576{
2577#if defined(USE_GETCWD)
2578 if (getcwd((char *)buf, len) == NULL)
2579 {
2580 STRCPY(buf, strerror(errno));
2581 return FAIL;
2582 }
2583 return OK;
2584#else
2585 return (getwd((char *)buf) != NULL ? OK : FAIL);
2586#endif
2587}
2588
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002590 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002591 *
2592 * return FAIL for failure, OK for success
2593 */
2594 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002595mch_FullName(
2596 char_u *fname,
2597 char_u *buf,
2598 int len,
Bram Moolenaar0f873732019-12-05 20:28:46 +01002599 int force) // also expand when already absolute path
Bram Moolenaar071d4272004-06-13 20:20:40 +00002600{
2601 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002602#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002603 int fd = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002604 static int dont_fchdir = FALSE; // TRUE when fchdir() doesn't work
Bram Moolenaar38323e42007-03-06 19:22:53 +00002605#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606 char_u olddir[MAXPATHL];
2607 char_u *p;
2608 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002609#ifdef __CYGWIN__
Bram Moolenaar0f873732019-12-05 20:28:46 +01002610 char_u posix_fname[MAXPATHL]; // Cygwin docs mention MAX_PATH, but
2611 // it's not always defined
Bram Moolenaarbf820722008-06-21 11:12:49 +00002612#endif
2613
Bram Moolenaar38323e42007-03-06 19:22:53 +00002614#ifdef VMS
2615 fname = vms_fixfilename(fname);
2616#endif
2617
Bram Moolenaara2442432007-04-26 14:26:37 +00002618#ifdef __CYGWIN__
2619 /*
2620 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2621 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002622# if CYGWIN_VERSION_DLL_MAJOR >= 1007
Bram Moolenaar0f873732019-12-05 20:28:46 +01002623 // Use CCP_RELATIVE to avoid that it sometimes returns a path that ends in
2624 // a forward slash.
Bram Moolenaar06b07342015-12-31 22:26:28 +01002625 cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE,
2626 fname, posix_fname, MAXPATHL);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002627# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002628 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002629# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002630 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002631#endif
2632
Bram Moolenaar0f873732019-12-05 20:28:46 +01002633 // Expand it if forced or not an absolute path.
2634 // Do not do it for "/file", the result is always "/".
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002635 if ((force || !mch_isFullName(fname))
2636 && ((p = vim_strrchr(fname, '/')) == NULL || p != fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002637 {
2638 /*
2639 * If the file name has a path, change to that directory for a moment,
Bram Moolenaar964b3742019-05-24 18:54:09 +02002640 * and then get the directory (and get back to where we were).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002641 * This will get the correct path name with "../" things.
2642 */
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002643 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002644 {
Bram Moolenaar4eaef992021-08-30 21:26:16 +02002645 if (STRCMP(p, "/..") == 0)
2646 // for "/path/dir/.." include the "/.."
2647 p += 3;
2648
Bram Moolenaar38323e42007-03-06 19:22:53 +00002649#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002650 /*
2651 * Use fchdir() if possible, it's said to be faster and more
2652 * reliable. But on SunOS 4 it might not work. Check this by
2653 * doing a fchdir() right now.
2654 */
2655 if (!dont_fchdir)
2656 {
2657 fd = open(".", O_RDONLY | O_EXTRA, 0);
2658 if (fd >= 0 && fchdir(fd) < 0)
2659 {
2660 close(fd);
2661 fd = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002662 dont_fchdir = TRUE; // don't try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00002663 }
2664 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002665#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002666
Bram Moolenaar0f873732019-12-05 20:28:46 +01002667 // Only change directory when we are sure we can return to where
2668 // we are now. After doing "su" chdir(".") might not work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002669 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002670#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002671 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002672#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002673 (mch_dirname(olddir, MAXPATHL) == FAIL
2674 || mch_chdir((char *)olddir) != 0))
2675 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002676 p = NULL; // can't get current dir: don't chdir
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677 retval = FAIL;
2678 }
2679 else
2680 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002681 // The directory is copied into buf[], to be able to remove
2682 // the file name without changing it (could be a string in
2683 // read-only memory)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002684 if (p - fname >= len)
2685 retval = FAIL;
2686 else
2687 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002688 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002689 if (mch_chdir((char *)buf))
Bram Moolenaarc6376c72021-10-03 19:29:48 +01002690 {
2691 // Path does not exist (yet). For a full path fail,
2692 // will use the path as-is. For a relative path use
2693 // the current directory and append the file name.
2694 if (mch_isFullName(fname))
2695 retval = FAIL;
2696 else
2697 p = NULL;
2698 }
Bram Moolenaar4eaef992021-08-30 21:26:16 +02002699 else if (*p == '/')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 fname = p + 1;
Bram Moolenaar4eaef992021-08-30 21:26:16 +02002701 else
2702 fname = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703 *buf = NUL;
2704 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002705 }
2706 }
2707 if (mch_dirname(buf, len) == FAIL)
2708 {
2709 retval = FAIL;
2710 *buf = NUL;
2711 }
2712 if (p != NULL)
2713 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002714#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002715 if (fd >= 0)
2716 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002717 if (p_verbose >= 5)
2718 {
2719 verbose_enter();
Bram Moolenaar32526b32019-01-19 17:43:09 +01002720 msg("fchdir() to previous dir");
Bram Moolenaar25724922009-07-14 15:38:41 +00002721 verbose_leave();
2722 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723 l = fchdir(fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 }
2725 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002726#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727 l = mch_chdir((char *)olddir);
2728 if (l != 0)
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00002729 emsg(_(e_cannot_go_back_to_previous_directory));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730 }
itchyny051a40c2021-10-20 10:00:05 +01002731#ifdef HAVE_FCHDIR
2732 if (fd >= 0)
2733 close(fd);
2734#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002735
2736 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002737 if (l >= len - 1)
Bram Moolenaar0f873732019-12-05 20:28:46 +01002738 retval = FAIL; // no space for trailing "/"
Bram Moolenaar38323e42007-03-06 19:22:53 +00002739#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002740 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002741 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002742 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002743#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002744 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002745
Bram Moolenaar0f873732019-12-05 20:28:46 +01002746 // Catch file names which are too long.
Bram Moolenaar78a15312009-05-15 19:33:18 +00002747 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002748 return FAIL;
2749
Bram Moolenaar0f873732019-12-05 20:28:46 +01002750 // Do not append ".", "/dir/." is equal to "/dir".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002751 if (STRCMP(fname, ".") != 0)
2752 STRCAT(buf, fname);
2753
2754 return OK;
2755}
2756
2757/*
2758 * Return TRUE if "fname" does not depend on the current directory.
2759 */
2760 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002761mch_isFullName(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002762{
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002763#ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764 return ( fname[0] == '/' || fname[0] == '.' ||
2765 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2766 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2767 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002768#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769 return (*fname == '/' || *fname == '~');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002770#endif
2771}
2772
Bram Moolenaar24552be2005-12-10 20:17:30 +00002773#if defined(USE_FNAME_CASE) || defined(PROTO)
2774/*
2775 * Set the case of the file name, if it already exists. This will cause the
2776 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002777 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002778 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002779 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002780fname_case(
2781 char_u *name,
Bram Moolenaar0f873732019-12-05 20:28:46 +01002782 int len UNUSED) // buffer size, only used when name gets longer
Bram Moolenaar24552be2005-12-10 20:17:30 +00002783{
2784 struct stat st;
2785 char_u *slash, *tail;
2786 DIR *dirp;
2787 struct dirent *dp;
2788
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002789 if (mch_lstat((char *)name, &st) >= 0)
Bram Moolenaar24552be2005-12-10 20:17:30 +00002790 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002791 // Open the directory where the file is located.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002792 slash = vim_strrchr(name, '/');
2793 if (slash == NULL)
2794 {
2795 dirp = opendir(".");
2796 tail = name;
2797 }
2798 else
2799 {
2800 *slash = NUL;
2801 dirp = opendir((char *)name);
2802 *slash = '/';
2803 tail = slash + 1;
2804 }
2805
2806 if (dirp != NULL)
2807 {
2808 while ((dp = readdir(dirp)) != NULL)
2809 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002810 // Only accept names that differ in case and are the same byte
2811 // length. TODO: accept different length name.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002812 if (STRICMP(tail, dp->d_name) == 0
2813 && STRLEN(tail) == STRLEN(dp->d_name))
2814 {
2815 char_u newname[MAXPATHL + 1];
2816 struct stat st2;
2817
Bram Moolenaar0f873732019-12-05 20:28:46 +01002818 // Verify the inode is equal.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002819 vim_strncpy(newname, name, MAXPATHL);
2820 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2821 MAXPATHL - (tail - name));
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002822 if (mch_lstat((char *)newname, &st2) >= 0
Bram Moolenaar24552be2005-12-10 20:17:30 +00002823 && st.st_ino == st2.st_ino
2824 && st.st_dev == st2.st_dev)
2825 {
2826 STRCPY(tail, dp->d_name);
2827 break;
2828 }
2829 }
2830 }
2831
2832 closedir(dirp);
2833 }
2834 }
2835}
2836#endif
2837
Bram Moolenaar071d4272004-06-13 20:20:40 +00002838/*
2839 * Get file permissions for 'name'.
2840 * Returns -1 when it doesn't exist.
2841 */
2842 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002843mch_getperm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844{
2845 struct stat statb;
2846
Bram Moolenaar0f873732019-12-05 20:28:46 +01002847 // Keep the #ifdef outside of stat(), it may be a macro.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848#ifdef VMS
2849 if (stat((char *)vms_fixfilename(name), &statb))
2850#else
2851 if (stat((char *)name, &statb))
2852#endif
2853 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002854#ifdef __INTERIX
Bram Moolenaar0f873732019-12-05 20:28:46 +01002855 // The top bit makes the value negative, which means the file doesn't
2856 // exist. Remove the bit, we don't use it.
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002857 return statb.st_mode & ~S_ADDACE;
2858#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002859 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002860#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002861}
2862
2863/*
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002864 * Set file permission for "name" to "perm".
2865 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002866 */
2867 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002868mch_setperm(char_u *name, long perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002869{
2870 return (chmod((char *)
2871#ifdef VMS
2872 vms_fixfilename(name),
2873#else
2874 name,
2875#endif
2876 (mode_t)perm) == 0 ? OK : FAIL);
2877}
2878
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002879#if defined(HAVE_FCHMOD) || defined(PROTO)
2880/*
2881 * Set file permission for open file "fd" to "perm".
2882 * Return FAIL for failure, OK otherwise.
2883 */
2884 int
2885mch_fsetperm(int fd, long perm)
2886{
2887 return (fchmod(fd, (mode_t)perm) == 0 ? OK : FAIL);
2888}
2889#endif
2890
Bram Moolenaar071d4272004-06-13 20:20:40 +00002891#if defined(HAVE_ACL) || defined(PROTO)
2892# ifdef HAVE_SYS_ACL_H
2893# include <sys/acl.h>
2894# endif
2895# ifdef HAVE_SYS_ACCESS_H
2896# include <sys/access.h>
2897# endif
2898
2899# ifdef HAVE_SOLARIS_ACL
2900typedef struct vim_acl_solaris_T {
2901 int acl_cnt;
2902 aclent_t *acl_entry;
2903} vim_acl_solaris_T;
2904# endif
2905
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002906#if defined(HAVE_SELINUX) || defined(PROTO)
2907/*
2908 * Copy security info from "from_file" to "to_file".
2909 */
2910 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002911mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002912{
2913 if (from_file == NULL)
2914 return;
2915
2916 if (selinux_enabled == -1)
2917 selinux_enabled = is_selinux_enabled();
2918
2919 if (selinux_enabled > 0)
2920 {
Bram Moolenaar89560232020-10-09 23:04:47 +02002921 // Use "char *" instead of "security_context_t" to avoid a deprecation
2922 // warning.
2923 char *from_context = NULL;
2924 char *to_context = NULL;
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002925
2926 if (getfilecon((char *)from_file, &from_context) < 0)
2927 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002928 // If the filesystem doesn't support extended attributes,
2929 // the original had no special security context and the
2930 // target cannot have one either.
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002931 if (errno == EOPNOTSUPP)
2932 return;
2933
Bram Moolenaar32526b32019-01-19 17:43:09 +01002934 msg_puts(_("\nCould not get security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002935 msg_outtrans(from_file);
2936 msg_putchar('\n');
2937 return;
2938 }
2939 if (getfilecon((char *)to_file, &to_context) < 0)
2940 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01002941 msg_puts(_("\nCould not get security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002942 msg_outtrans(to_file);
2943 msg_putchar('\n');
2944 freecon (from_context);
2945 return ;
2946 }
2947 if (strcmp(from_context, to_context) != 0)
2948 {
2949 if (setfilecon((char *)to_file, from_context) < 0)
2950 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01002951 msg_puts(_("\nCould not set security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002952 msg_outtrans(to_file);
2953 msg_putchar('\n');
2954 }
2955 }
2956 freecon(to_context);
2957 freecon(from_context);
2958 }
2959}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002960#endif // HAVE_SELINUX
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002961
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002962#if defined(HAVE_SMACK) && !defined(PROTO)
2963/*
2964 * Copy security info from "from_file" to "to_file".
2965 */
2966 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002967mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002968{
Bram Moolenaar62f167f2014-04-23 12:52:40 +02002969 static const char * const smack_copied_attributes[] =
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002970 {
2971 XATTR_NAME_SMACK,
2972 XATTR_NAME_SMACKEXEC,
2973 XATTR_NAME_SMACKMMAP
2974 };
2975
2976 char buffer[SMACK_LABEL_LEN];
2977 const char *name;
2978 int index;
2979 int ret;
2980 ssize_t size;
2981
2982 if (from_file == NULL)
2983 return;
2984
2985 for (index = 0 ; index < (int)(sizeof(smack_copied_attributes)
2986 / sizeof(smack_copied_attributes)[0]) ; index++)
2987 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002988 // get the name of the attribute to copy
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002989 name = smack_copied_attributes[index];
2990
Bram Moolenaar0f873732019-12-05 20:28:46 +01002991 // get the value of the attribute in buffer
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002992 size = getxattr((char*)from_file, name, buffer, sizeof(buffer));
2993 if (size >= 0)
2994 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002995 // copy the attribute value of buffer
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002996 ret = setxattr((char*)to_file, name, buffer, (size_t)size, 0);
2997 if (ret < 0)
2998 {
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002999 vim_snprintf((char *)IObuff, IOSIZE,
3000 _("Could not set security context %s for %s"),
3001 name, to_file);
3002 msg_outtrans(IObuff);
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003003 msg_putchar('\n');
3004 }
3005 }
3006 else
3007 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003008 // what reason of not having the attribute value?
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003009 switch (errno)
3010 {
3011 case ENOTSUP:
Bram Moolenaar0f873732019-12-05 20:28:46 +01003012 // extended attributes aren't supported or enabled
3013 // should a message be echoed? not sure...
3014 return; // leave because it isn't useful to continue
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003015
3016 case ERANGE:
3017 default:
Bram Moolenaar0f873732019-12-05 20:28:46 +01003018 // no enough size OR unexpected error
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01003019 vim_snprintf((char *)IObuff, IOSIZE,
3020 _("Could not get security context %s for %s. Removing it!"),
3021 name, from_file);
Bram Moolenaar32526b32019-01-19 17:43:09 +01003022 msg_puts((char *)IObuff);
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01003023 msg_putchar('\n');
Bram Moolenaar0f873732019-12-05 20:28:46 +01003024 // FALLTHROUGH to remove the attribute
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003025
3026 case ENODATA:
Bram Moolenaar0f873732019-12-05 20:28:46 +01003027 // no attribute of this name
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003028 ret = removexattr((char*)to_file, name);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003029 // Silently ignore errors, apparently this happens when
3030 // smack is not actually being used.
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003031 break;
3032 }
3033 }
3034 }
3035}
Bram Moolenaar0f873732019-12-05 20:28:46 +01003036#endif // HAVE_SMACK
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003037
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038/*
3039 * Return a pointer to the ACL of file "fname" in allocated memory.
3040 * Return NULL if the ACL is not available for whatever reason.
3041 */
3042 vim_acl_T
Bram Moolenaar05540972016-01-30 20:31:25 +01003043mch_get_acl(char_u *fname UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044{
3045 vim_acl_T ret = NULL;
3046#ifdef HAVE_POSIX_ACL
3047 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
3048#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003049#ifdef HAVE_SOLARIS_ZFS_ACL
3050 acl_t *aclent;
3051
3052 if (acl_get((char *)fname, 0, &aclent) < 0)
3053 return NULL;
3054 ret = (vim_acl_T)aclent;
3055#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056#ifdef HAVE_SOLARIS_ACL
3057 vim_acl_solaris_T *aclent;
3058
3059 aclent = malloc(sizeof(vim_acl_solaris_T));
3060 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
3061 {
3062 free(aclent);
3063 return NULL;
3064 }
3065 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
3066 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
3067 {
3068 free(aclent->acl_entry);
3069 free(aclent);
3070 return NULL;
3071 }
3072 ret = (vim_acl_T)aclent;
3073#else
3074#if defined(HAVE_AIX_ACL)
3075 int aclsize;
3076 struct acl *aclent;
3077
3078 aclsize = sizeof(struct acl);
3079 aclent = malloc(aclsize);
3080 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
3081 {
3082 if (errno == ENOSPC)
3083 {
3084 aclsize = aclent->acl_len;
3085 aclent = realloc(aclent, aclsize);
3086 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
3087 {
3088 free(aclent);
3089 return NULL;
3090 }
3091 }
3092 else
3093 {
3094 free(aclent);
3095 return NULL;
3096 }
3097 }
3098 ret = (vim_acl_T)aclent;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003099#endif // HAVE_AIX_ACL
3100#endif // HAVE_SOLARIS_ACL
3101#endif // HAVE_SOLARIS_ZFS_ACL
3102#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103 return ret;
3104}
3105
3106/*
3107 * Set the ACL of file "fname" to "acl" (unless it's NULL).
3108 */
3109 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003110mch_set_acl(char_u *fname UNUSED, vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003111{
3112 if (aclent == NULL)
3113 return;
3114#ifdef HAVE_POSIX_ACL
3115 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
3116#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003117#ifdef HAVE_SOLARIS_ZFS_ACL
3118 acl_set((char *)fname, (acl_t *)aclent);
3119#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003120#ifdef HAVE_SOLARIS_ACL
3121 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
3122 ((vim_acl_solaris_T *)aclent)->acl_entry);
3123#else
3124#ifdef HAVE_AIX_ACL
3125 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003126#endif // HAVE_AIX_ACL
3127#endif // HAVE_SOLARIS_ACL
3128#endif // HAVE_SOLARIS_ZFS_ACL
3129#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130}
3131
3132 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003133mch_free_acl(vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003134{
3135 if (aclent == NULL)
3136 return;
3137#ifdef HAVE_POSIX_ACL
3138 acl_free((acl_t)aclent);
3139#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003140#ifdef HAVE_SOLARIS_ZFS_ACL
3141 acl_free((acl_t *)aclent);
3142#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143#ifdef HAVE_SOLARIS_ACL
3144 free(((vim_acl_solaris_T *)aclent)->acl_entry);
3145 free(aclent);
3146#else
3147#ifdef HAVE_AIX_ACL
3148 free(aclent);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003149#endif // HAVE_AIX_ACL
3150#endif // HAVE_SOLARIS_ACL
3151#endif // HAVE_SOLARIS_ZFS_ACL
3152#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003153}
3154#endif
3155
3156/*
3157 * Set hidden flag for "name".
3158 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003160mch_hide(char_u *name UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003161{
Bram Moolenaar0f873732019-12-05 20:28:46 +01003162 // can't hide a file
Bram Moolenaar071d4272004-06-13 20:20:40 +00003163}
3164
3165/*
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003166 * return TRUE if "name" is a directory or a symlink to a directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003167 * return FALSE if "name" is not a directory
3168 * return FALSE for error
3169 */
3170 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003171mch_isdir(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003172{
3173 struct stat statb;
3174
Bram Moolenaar0f873732019-12-05 20:28:46 +01003175 if (*name == NUL) // Some stat()s don't flag "" as an error.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003176 return FALSE;
3177 if (stat((char *)name, &statb))
3178 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003179 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180}
3181
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003182/*
3183 * return TRUE if "name" is a directory, NOT a symlink to a directory
3184 * return FALSE if "name" is not a directory
3185 * return FALSE for error
3186 */
3187 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003188mch_isrealdir(char_u *name)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003189{
3190 struct stat statb;
3191
Bram Moolenaar0f873732019-12-05 20:28:46 +01003192 if (*name == NUL) // Some stat()s don't flag "" as an error.
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003193 return FALSE;
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01003194 if (mch_lstat((char *)name, &statb))
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003195 return FALSE;
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003196 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003197}
3198
Bram Moolenaar071d4272004-06-13 20:20:40 +00003199/*
3200 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
3201 */
3202 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003203executable_file(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204{
3205 struct stat st;
3206
3207 if (stat((char *)name, &st))
3208 return 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003209#ifdef VMS
Bram Moolenaar0f873732019-12-05 20:28:46 +01003210 // Like on Unix system file can have executable rights but not necessarily
3211 // be an executable, but on Unix is not a default for an ordinary file to
3212 // have an executable flag - on VMS it is in most cases.
3213 // Therefore, this check does not have any sense - let keep us to the
3214 // conventions instead:
3215 // *.COM and *.EXE files are the executables - the rest are not. This is
Dominique Pelleaf4a61a2021-12-27 17:21:41 +00003216 // not ideal but better than it was.
Bram Moolenaar206f0112014-03-12 16:51:55 +01003217 int vms_executable = 0;
3218 if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
3219 {
3220 if (strstr(vms_tolower((char*)name),".exe") != NULL
3221 || strstr(vms_tolower((char*)name),".com")!= NULL)
3222 vms_executable = 1;
3223 }
3224 return vms_executable;
3225#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003226 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003227#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003228}
3229
3230/*
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01003231 * Return TRUE if "name" can be found in $PATH and executed, FALSE if not.
Bram Moolenaarb5971142015-03-21 17:32:19 +01003232 * If "use_path" is FALSE only check if "name" is executable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003233 * Return -1 if unknown.
3234 */
3235 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003236mch_can_exe(char_u *name, char_u **path, int use_path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237{
3238 char_u *buf;
3239 char_u *p, *e;
3240 int retval;
3241
Bram Moolenaar0f873732019-12-05 20:28:46 +01003242 // When "use_path" is false and if it's an absolute or relative path don't
3243 // need to use $PATH.
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003244 if (!use_path || gettail(name) != name)
Bram Moolenaar206f0112014-03-12 16:51:55 +01003245 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003246 // There must be a path separator, files in the current directory
3247 // can't be executed.
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003248 if ((use_path || gettail(name) != name) && executable_file(name))
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003249 {
3250 if (path != NULL)
3251 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003252 if (name[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003253 *path = FullName_save(name, TRUE);
3254 else
3255 *path = vim_strsave(name);
3256 }
3257 return TRUE;
3258 }
3259 return FALSE;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003260 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003261
3262 p = (char_u *)getenv("PATH");
3263 if (p == NULL || *p == NUL)
3264 return -1;
Bram Moolenaar964b3742019-05-24 18:54:09 +02003265 buf = alloc(STRLEN(name) + STRLEN(p) + 2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266 if (buf == NULL)
3267 return -1;
3268
3269 /*
3270 * Walk through all entries in $PATH to check if "name" exists there and
3271 * is an executable file.
3272 */
3273 for (;;)
3274 {
3275 e = (char_u *)strchr((char *)p, ':');
3276 if (e == NULL)
3277 e = p + STRLEN(p);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003278 if (e - p <= 1) // empty entry means current dir
Bram Moolenaar071d4272004-06-13 20:20:40 +00003279 STRCPY(buf, "./");
3280 else
3281 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003282 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003283 add_pathsep(buf);
3284 }
3285 STRCAT(buf, name);
3286 retval = executable_file(buf);
3287 if (retval == 1)
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003288 {
3289 if (path != NULL)
3290 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003291 if (buf[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003292 *path = FullName_save(buf, TRUE);
3293 else
3294 *path = vim_strsave(buf);
3295 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003296 break;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003297 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003298
3299 if (*e != ':')
3300 break;
3301 p = e + 1;
3302 }
3303
3304 vim_free(buf);
3305 return retval;
3306}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003307
3308/*
3309 * Check what "name" is:
3310 * NODE_NORMAL: file or directory (or doesn't exist)
3311 * NODE_WRITABLE: writable device, socket, fifo, etc.
3312 * NODE_OTHER: non-writable things
3313 */
3314 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003315mch_nodetype(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003316{
3317 struct stat st;
3318
3319 if (stat((char *)name, &st))
3320 return NODE_NORMAL;
3321 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3322 return NODE_NORMAL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003323 if (S_ISBLK(st.st_mode)) // block device isn't writable
Bram Moolenaar071d4272004-06-13 20:20:40 +00003324 return NODE_OTHER;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003325 // Everything else is writable?
Bram Moolenaar071d4272004-06-13 20:20:40 +00003326 return NODE_WRITABLE;
3327}
3328
3329 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003330mch_early_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003331{
3332#ifdef HAVE_CHECK_STACK_GROWTH
3333 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334
Bram Moolenaar071d4272004-06-13 20:20:40 +00003335 check_stack_growth((char *)&i);
3336
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003337# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338 get_stack_limit();
3339# endif
3340
3341#endif
3342
3343 /*
3344 * Setup an alternative stack for signals. Helps to catch signals when
3345 * running out of stack space.
3346 * Use of sigaltstack() is preferred, it's more portable.
3347 * Ignore any errors.
3348 */
3349#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Zdenek Dohnalba9c23e2021-08-11 14:20:05 +02003350 signal_stack = alloc(get_signal_stack_size());
Bram Moolenaar071d4272004-06-13 20:20:40 +00003351 init_signal_stack();
3352#endif
3353}
3354
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003355#if defined(EXITFREE) || defined(PROTO)
3356 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003357mch_free_mem(void)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003358{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003359# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3360 if (clip_star.owned)
3361 clip_lose_selection(&clip_star);
3362 if (clip_plus.owned)
3363 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003364# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003365# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003366 if (xterm_Shell != (Widget)0)
3367 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003368# ifndef LESSTIF_VERSION
Bram Moolenaar0f873732019-12-05 20:28:46 +01003369 // Lesstif crashes here, lose some memory
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003370 if (xterm_dpy != NULL)
3371 XtCloseDisplay(xterm_dpy);
3372 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003373 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003374 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003375# ifdef FEAT_X11
Bram Moolenaar0f873732019-12-05 20:28:46 +01003376 x11_display = NULL; // freed by XtDestroyApplicationContext()
Bram Moolenaare8208012008-06-20 09:59:25 +00003377# endif
3378 }
3379# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003380# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003381# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003382 if (x11_display != NULL
3383# ifdef FEAT_XCLIPBOARD
3384 && x11_display != xterm_dpy
3385# endif
3386 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003387 XCloseDisplay(x11_display);
3388# endif
3389# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaard23a8232018-02-10 18:45:26 +01003390 VIM_CLEAR(signal_stack);
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003391# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003392 vim_free(oldtitle);
3393 vim_free(oldicon);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003394}
3395#endif
3396
Bram Moolenaar071d4272004-06-13 20:20:40 +00003397/*
3398 * Output a newline when exiting.
3399 * Make sure the newline goes to the same stream as the text.
3400 */
3401 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003402exit_scroll(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003403{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003404 if (silent_mode)
3405 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003406 if (newline_on_exit || msg_didout)
3407 {
3408 if (msg_use_printf())
3409 {
3410 if (info_message)
3411 mch_msg("\n");
3412 else
3413 mch_errmsg("\r\n");
3414 }
3415 else
3416 out_char('\n');
3417 }
Bram Moolenaar7007e312021-03-27 12:11:33 +01003418 else if (!is_not_a_term())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003419 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003420 restore_cterm_colors(); // get original colors back
3421 msg_clr_eos_force(); // clear the rest of the display
3422 windgoto((int)Rows - 1, 0); // may have moved the cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00003423 }
3424}
3425
Bram Moolenaarb4151682020-05-11 22:13:28 +02003426#ifdef USE_GCOV_FLUSH
ichizokdee78e12021-12-09 21:08:01 +00003427# if (defined(__GNUC__) \
3428 && ((__GNUC__ == 11 && __GNUC_MINOR__ >= 1) || (__GNUC__ >= 12))) \
3429 || (defined(__clang__) && (__clang_major__ >= 12))
3430extern void __gcov_dump(void);
3431extern void __gcov_reset(void);
3432# define __gcov_flush() do { __gcov_dump(); __gcov_reset(); } while (0)
3433# else
3434extern void __gcov_flush(void);
3435# endif
Bram Moolenaarb4151682020-05-11 22:13:28 +02003436#endif
3437
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003439mch_exit(int r)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003440{
3441 exiting = TRUE;
3442
3443#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3444 x11_export_final_selection();
3445#endif
3446
3447#ifdef FEAT_GUI
3448 if (!gui.in_use)
3449#endif
3450 {
3451 settmode(TMODE_COOK);
Bram Moolenaar7007e312021-03-27 12:11:33 +01003452 if (!is_not_a_term())
3453 {
3454 // restore xterm title and icon name
3455 mch_restore_title(SAVE_RESTORE_BOTH);
3456 term_pop_title(SAVE_RESTORE_BOTH);
3457 }
Bram Moolenaar651fca82021-11-29 20:39:38 +00003458
Bram Moolenaar071d4272004-06-13 20:20:40 +00003459 /*
3460 * When t_ti is not empty but it doesn't cause swapping terminal
3461 * pages, need to output a newline when msg_didout is set. But when
3462 * t_ti does swap pages it should not go to the shell page. Do this
3463 * before stoptermcap().
3464 */
3465 if (swapping_screen() && !newline_on_exit)
3466 exit_scroll();
3467
Bram Moolenaar0f873732019-12-05 20:28:46 +01003468 // Stop termcap: May need to check for T_CRV response, which
3469 // requires RAW mode.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470 stoptermcap();
3471
3472 /*
3473 * A newline is only required after a message in the alternate screen.
3474 * This is set to TRUE by wait_return().
3475 */
3476 if (!swapping_screen() || newline_on_exit)
3477 exit_scroll();
3478
Bram Moolenaar0f873732019-12-05 20:28:46 +01003479 // Cursor may have been switched off without calling starttermcap()
3480 // when doing "vim -u vimrc" and vimrc contains ":q".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003481 if (full_screen)
3482 cursor_on();
3483 }
3484 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01003485 ml_close_all(TRUE); // remove all memfiles
Bram Moolenaarb4151682020-05-11 22:13:28 +02003486
3487#ifdef USE_GCOV_FLUSH
3488 // Flush coverage info before possibly being killed by a deadly signal.
3489 __gcov_flush();
3490#endif
3491
Bram Moolenaar071d4272004-06-13 20:20:40 +00003492 may_core_dump();
3493#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003494 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003495 gui_exit(r);
3496#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003497
Bram Moolenaar56718732006-03-15 22:53:57 +00003498#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003499 mac_conv_cleanup();
3500#endif
3501
Bram Moolenaar071d4272004-06-13 20:20:40 +00003502#ifdef __QNX__
Bram Moolenaar0f873732019-12-05 20:28:46 +01003503 // A core dump won't be created if the signal handler
3504 // doesn't return, so we can't call exit()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003505 if (deadly_signal != 0)
3506 return;
3507#endif
3508
Bram Moolenaar009b2592004-10-24 19:18:58 +00003509#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003510 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003511#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003512
3513#ifdef EXITFREE
3514 free_all_mem();
3515#endif
3516
Bram Moolenaar071d4272004-06-13 20:20:40 +00003517 exit(r);
3518}
3519
3520 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003521may_core_dump(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003522{
3523 if (deadly_signal != 0)
3524 {
3525 signal(deadly_signal, SIG_DFL);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003526 kill(getpid(), deadly_signal); // Die using the signal we caught
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527 }
3528}
3529
3530#ifndef VMS
3531
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003532/*
3533 * Get the file descriptor to use for tty operations.
3534 */
3535 static int
3536get_tty_fd(int fd)
3537{
3538 int tty_fd = fd;
3539
3540#if defined(HAVE_SVR4_PTYS) && defined(SUN_SYSTEM)
3541 // On SunOS: Get the terminal parameters from "fd", or the slave device of
3542 // "fd" when it is a master device.
3543 if (mch_isatty(fd) > 1)
3544 {
3545 char *name;
3546
3547 name = ptsname(fd);
3548 if (name == NULL)
3549 return -1;
3550
3551 tty_fd = open(name, O_RDONLY | O_NOCTTY | O_EXTRA, 0);
3552 if (tty_fd < 0)
3553 return -1;
3554 }
3555#endif
3556 return tty_fd;
3557}
3558
3559 static int
3560mch_tcgetattr(int fd, void *term)
3561{
3562 int tty_fd;
3563 int retval = -1;
3564
3565 tty_fd = get_tty_fd(fd);
3566 if (tty_fd >= 0)
3567 {
3568#ifdef NEW_TTY_SYSTEM
3569# ifdef HAVE_TERMIOS_H
3570 retval = tcgetattr(tty_fd, (struct termios *)term);
3571# else
3572 retval = ioctl(tty_fd, TCGETA, (struct termio *)term);
3573# endif
3574#else
3575 // for "old" tty systems
3576 retval = ioctl(tty_fd, TIOCGETP, (struct sgttyb *)term);
3577#endif
3578 if (tty_fd != fd)
3579 close(tty_fd);
3580 }
3581 return retval;
3582}
3583
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584 void
Bram Moolenaar26e86442020-05-17 14:06:16 +02003585mch_settmode(tmode_T tmode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586{
3587 static int first = TRUE;
3588
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003589#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590# ifdef HAVE_TERMIOS_H
3591 static struct termios told;
3592 struct termios tnew;
3593# else
3594 static struct termio told;
3595 struct termio tnew;
3596# endif
3597
3598 if (first)
3599 {
3600 first = FALSE;
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003601 mch_tcgetattr(read_cmd_fd, &told);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602 }
3603
3604 tnew = told;
3605 if (tmode == TMODE_RAW)
3606 {
Bram Moolenaar041c7102020-05-30 18:14:57 +02003607 // ~ICRNL enables typing ^V^M
Bram Moolenaar928eec62020-05-31 13:09:47 +02003608 // ~IXON disables CTRL-S stopping output, so that it can be mapped.
3609 tnew.c_iflag &= ~(ICRNL | IXON);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003610 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
Bram Moolenaare3f915d2020-07-14 23:02:44 +02003611# if defined(IEXTEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01003612 | IEXTEN // IEXTEN enables typing ^V on SOLARIS
Bram Moolenaar071d4272004-06-13 20:20:40 +00003613# endif
3614 );
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003615# ifdef ONLCR
3616 // Don't map NL -> CR NL, we do it ourselves.
3617 // Also disable expanding tabs if possible.
3618# ifdef XTABS
3619 tnew.c_oflag &= ~(ONLCR | XTABS);
3620# else
3621# ifdef TAB3
3622 tnew.c_oflag &= ~(ONLCR | TAB3);
3623# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003624 tnew.c_oflag &= ~ONLCR;
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003625# endif
3626# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003627# endif
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003628 tnew.c_cc[VMIN] = 1; // return after 1 char
3629 tnew.c_cc[VTIME] = 0; // don't wait
Bram Moolenaar071d4272004-06-13 20:20:40 +00003630 }
3631 else if (tmode == TMODE_SLEEP)
Bram Moolenaar40de4562016-07-01 15:03:46 +02003632 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003633 // Also reset ICANON here, otherwise on Solaris select() won't see
3634 // typeahead characters.
Bram Moolenaar40de4562016-07-01 15:03:46 +02003635 tnew.c_lflag &= ~(ICANON | ECHO);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003636 tnew.c_cc[VMIN] = 1; // return after 1 char
3637 tnew.c_cc[VTIME] = 0; // don't wait
Bram Moolenaar40de4562016-07-01 15:03:46 +02003638 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003639
3640# if defined(HAVE_TERMIOS_H)
3641 {
3642 int n = 10;
3643
Bram Moolenaar0f873732019-12-05 20:28:46 +01003644 // A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3645 // few times.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3647 && errno == EINTR && n > 0)
3648 --n;
3649 }
3650# else
3651 ioctl(read_cmd_fd, TCSETA, &tnew);
3652# endif
3653
3654#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655 /*
3656 * for "old" tty systems
3657 */
3658# ifndef TIOCSETN
Bram Moolenaar0f873732019-12-05 20:28:46 +01003659# define TIOCSETN TIOCSETP // for hpux 9.0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003660# endif
3661 static struct sgttyb ttybold;
3662 struct sgttyb ttybnew;
3663
3664 if (first)
3665 {
3666 first = FALSE;
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003667 mch_tcgetattr(read_cmd_fd, &ttybold);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003668 }
3669
3670 ttybnew = ttybold;
3671 if (tmode == TMODE_RAW)
3672 {
3673 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3674 ttybnew.sg_flags |= RAW;
3675 }
3676 else if (tmode == TMODE_SLEEP)
3677 ttybnew.sg_flags &= ~(ECHO);
3678 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3679#endif
Bram Moolenaar26e86442020-05-17 14:06:16 +02003680 mch_cur_tmode = tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681}
3682
3683/*
3684 * Try to get the code for "t_kb" from the stty setting
3685 *
3686 * Even if termcap claims a backspace key, the user's setting *should*
3687 * prevail. stty knows more about reality than termcap does, and if
3688 * somebody's usual erase key is DEL (which, for most BSD users, it will
3689 * be), they're going to get really annoyed if their erase key starts
3690 * doing forward deletes for no reason. (Eric Fischer)
3691 */
3692 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003693get_stty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003694{
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003695 ttyinfo_T info;
3696 char_u buf[2];
3697 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003698
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003699 if (get_tty_info(read_cmd_fd, &info) == OK)
3700 {
3701 intr_char = info.interrupt;
3702 buf[0] = info.backspace;
3703 buf[1] = NUL;
3704 add_termcode((char_u *)"kb", buf, FALSE);
3705
Bram Moolenaar0f873732019-12-05 20:28:46 +01003706 // If <BS> and <DEL> are now the same, redefine <DEL>.
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003707 p = find_termcode((char_u *)"kD");
3708 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3709 do_fixdel(NULL);
3710 }
3711}
3712
3713/*
3714 * Obtain the characters that Backspace and Enter produce on "fd".
3715 * Returns OK or FAIL.
3716 */
3717 int
3718get_tty_info(int fd, ttyinfo_T *info)
3719{
3720#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003721# ifdef HAVE_TERMIOS_H
3722 struct termios keys;
3723# else
3724 struct termio keys;
3725# endif
3726
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003727 if (mch_tcgetattr(fd, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003728 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003729 info->backspace = keys.c_cc[VERASE];
3730 info->interrupt = keys.c_cc[VINTR];
3731 if (keys.c_iflag & ICRNL)
3732 info->enter = NL;
3733 else
3734 info->enter = CAR;
3735 if (keys.c_oflag & ONLCR)
3736 info->nl_does_cr = TRUE;
3737 else
3738 info->nl_does_cr = FALSE;
3739 return OK;
3740 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741#else
Bram Moolenaar0f873732019-12-05 20:28:46 +01003742 // for "old" tty systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00003743 struct sgttyb keys;
3744
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003745 if (mch_tcgetattr(fd, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003747 info->backspace = keys.sg_erase;
3748 info->interrupt = keys.sg_kill;
3749 info->enter = CAR;
3750 info->nl_does_cr = TRUE;
3751 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003752 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753#endif
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003754 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755}
3756
Bram Moolenaar0f873732019-12-05 20:28:46 +01003757#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003759static int mouse_ison = FALSE;
3760
Bram Moolenaar071d4272004-06-13 20:20:40 +00003761/*
3762 * Set mouse clicks on or off.
3763 */
3764 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003765mch_setmouse(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003766{
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003767#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003768 static int bevalterm_ison = FALSE;
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003769#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003770 int xterm_mouse_vers;
3771
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003772#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaara06afc72018-08-27 23:24:16 +02003773 if (!on)
3774 // Make sure not tracing mouse movements. Important when a button-down
3775 // was received but no release yet.
3776 stop_xterm_trace();
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003777#endif
Bram Moolenaara06afc72018-08-27 23:24:16 +02003778
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003779 if (on == mouse_ison
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003780#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003781 && p_bevalterm == bevalterm_ison
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003782#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003783 )
Bram Moolenaar0f873732019-12-05 20:28:46 +01003784 // return quickly if nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00003785 return;
3786
3787 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003788
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003789#ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003790 if (ttym_flags == TTYM_URXVT)
3791 {
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003792 out_str_nf((char_u *)(on ? "\033[?1015h" : "\033[?1015l"));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003793 mouse_ison = on;
Bram Moolenaarc8427482011-10-20 21:09:35 +02003794 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003795#endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003796
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003797 if (ttym_flags == TTYM_SGR)
3798 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003799 // SGR mode supports columns above 223
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003800 out_str_nf((char_u *)(on ? "\033[?1006h" : "\033[?1006l"));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003801 mouse_ison = on;
3802 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003803
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003804#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003805 if (bevalterm_ison != (p_bevalterm && on))
3806 {
3807 bevalterm_ison = (p_bevalterm && on);
3808 if (xterm_mouse_vers > 1 && !bevalterm_ison)
Bram Moolenaar0f873732019-12-05 20:28:46 +01003809 // disable mouse movement events, enabling is below
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003810 out_str_nf((char_u *)("\033[?1003l"));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003811 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003812#endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003813
Bram Moolenaar071d4272004-06-13 20:20:40 +00003814 if (xterm_mouse_vers > 0)
3815 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003816 if (on) // enable mouse events, use mouse tracking if available
Bram Moolenaar071d4272004-06-13 20:20:40 +00003817 out_str_nf((char_u *)
3818 (xterm_mouse_vers > 1
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003819 ? (
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003820#ifdef FEAT_BEVAL_TERM
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003821 bevalterm_ison ? "\033[?1003h" :
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003822#endif
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003823 "\033[?1002h")
3824 : "\033[?1000h"));
Bram Moolenaar0f873732019-12-05 20:28:46 +01003825 else // disable mouse events, could probably always send the same
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826 out_str_nf((char_u *)
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003827 (xterm_mouse_vers > 1 ? "\033[?1002l" : "\033[?1000l"));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003828 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829 }
3830
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003831#ifdef FEAT_MOUSE_DEC
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832 else if (ttym_flags == TTYM_DEC)
3833 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003834 if (on) // enable mouse events
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
Bram Moolenaar0f873732019-12-05 20:28:46 +01003836 else // disable mouse events
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837 out_str_nf((char_u *)"\033['z");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003838 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003839 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003840#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003841
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003842#ifdef FEAT_MOUSE_GPM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003843 else
3844 {
3845 if (on)
3846 {
3847 if (gpm_open())
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003848 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003849 }
3850 else
3851 {
3852 gpm_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003853 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003854 }
3855 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003856#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003857
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003858#ifdef FEAT_SYSMOUSE
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003859 else
3860 {
3861 if (on)
3862 {
3863 if (sysmouse_open() == OK)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003864 mouse_ison = TRUE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003865 }
3866 else
3867 {
3868 sysmouse_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003869 mouse_ison = FALSE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003870 }
3871 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003872#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003873
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003874#ifdef FEAT_MOUSE_JSB
Bram Moolenaar071d4272004-06-13 20:20:40 +00003875 else
3876 {
3877 if (on)
3878 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003879 // D - Enable Mouse up/down messages
3880 // L - Enable Left Button Reporting
3881 // M - Enable Middle Button Reporting
3882 // R - Enable Right Button Reporting
3883 // K - Enable SHIFT and CTRL key Reporting
3884 // + - Enable Advanced messaging of mouse moves and up/down messages
3885 // Q - Quiet No Ack
3886 // # - Numeric value of mouse pointer required
3887 // 0 = Multiview 2000 cursor, used as standard
3888 // 1 = Windows Arrow
3889 // 2 = Windows I Beam
3890 // 3 = Windows Hour Glass
3891 // 4 = Windows Cross Hair
3892 // 5 = Windows UP Arrow
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003893# ifdef JSBTERM_MOUSE_NONADVANCED
Bram Moolenaar0f873732019-12-05 20:28:46 +01003894 // Disables full feedback of pointer movements
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003895 out_str_nf((char_u *)"\033[0~ZwLMRK1Q\033\\");
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003896# else
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003897 out_str_nf((char_u *)"\033[0~ZwLMRK+1Q\033\\");
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003898# endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003899 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003900 }
3901 else
3902 {
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003903 out_str_nf((char_u *)"\033[0~ZwQ\033\\");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003904 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905 }
3906 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003907#endif
3908#ifdef FEAT_MOUSE_PTERM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003909 else
3910 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003911 // 1 = button press, 6 = release, 7 = drag, 1h...9l = right button
Bram Moolenaar071d4272004-06-13 20:20:40 +00003912 if (on)
3913 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3914 else
3915 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003916 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003917 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003918#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003919}
3920
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003921#if defined(FEAT_BEVAL_TERM) || defined(PROTO)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003922/*
3923 * Called when 'balloonevalterm' changed.
3924 */
3925 void
3926mch_bevalterm_changed(void)
3927{
3928 mch_setmouse(mouse_ison);
3929}
3930#endif
3931
Bram Moolenaar071d4272004-06-13 20:20:40 +00003932/*
3933 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3934 */
3935 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003936check_mouse_termcode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003937{
3938# ifdef FEAT_MOUSE_XTERM
3939 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003940# ifdef FEAT_MOUSE_URXVT
3941 && use_xterm_mouse() != 3
3942# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003943# ifdef FEAT_GUI
3944 && !gui.in_use
3945# endif
3946 )
3947 {
3948 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003949 ? "\233M" : "\033[M"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003950 if (*p_mouse != NUL)
3951 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003952 // force mouse off and maybe on to send possibly new mouse
3953 // activation sequence to the xterm, with(out) drag tracing.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003954 mch_setmouse(FALSE);
3955 setmouse();
3956 }
3957 }
3958 else
3959 del_mouse_termcode(KS_MOUSE);
3960# endif
3961
3962# ifdef FEAT_MOUSE_GPM
3963 if (!use_xterm_mouse()
3964# ifdef FEAT_GUI
3965 && !gui.in_use
3966# endif
3967 )
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003968 set_mouse_termcode(KS_GPM_MOUSE, (char_u *)"\033MG");
Bram Moolenaarbedf0912019-05-04 16:58:45 +02003969 else
3970 del_mouse_termcode(KS_GPM_MOUSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003971# endif
3972
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003973# ifdef FEAT_SYSMOUSE
3974 if (!use_xterm_mouse()
3975# ifdef FEAT_GUI
3976 && !gui.in_use
3977# endif
3978 )
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003979 set_mouse_termcode(KS_MOUSE, (char_u *)"\033MS");
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003980# endif
3981
Bram Moolenaar071d4272004-06-13 20:20:40 +00003982# ifdef FEAT_MOUSE_JSB
Bram Moolenaar0f873732019-12-05 20:28:46 +01003983 // Conflicts with xterm mouse: "\033[" and "\033[M" ???
Bram Moolenaar071d4272004-06-13 20:20:40 +00003984 if (!use_xterm_mouse()
3985# ifdef FEAT_GUI
3986 && !gui.in_use
3987# endif
3988 )
Bram Moolenaar424bcae2022-01-31 14:59:41 +00003989 set_mouse_termcode(KS_JSBTERM_MOUSE, (char_u *)"\033[0~zw");
Bram Moolenaar071d4272004-06-13 20:20:40 +00003990 else
3991 del_mouse_termcode(KS_JSBTERM_MOUSE);
3992# endif
3993
3994# ifdef FEAT_MOUSE_NET
Bram Moolenaar0f873732019-12-05 20:28:46 +01003995 // There is no conflict, but one may type "ESC }" from Insert mode. Don't
3996 // define it in the GUI or when using an xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003997 if (!use_xterm_mouse()
3998# ifdef FEAT_GUI
3999 && !gui.in_use
4000# endif
4001 )
Bram Moolenaar424bcae2022-01-31 14:59:41 +00004002 set_mouse_termcode(KS_NETTERM_MOUSE, (char_u *)"\033}");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004003 else
4004 del_mouse_termcode(KS_NETTERM_MOUSE);
4005# endif
4006
4007# ifdef FEAT_MOUSE_DEC
Bram Moolenaar0f873732019-12-05 20:28:46 +01004008 // Conflicts with xterm mouse: "\033[" and "\033[M"
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02004009 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00004010# ifdef FEAT_GUI
4011 && !gui.in_use
4012# endif
4013 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00004014 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaar424bcae2022-01-31 14:59:41 +00004015 ? "\233" : "\033["));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016 else
4017 del_mouse_termcode(KS_DEC_MOUSE);
4018# endif
4019# ifdef FEAT_MOUSE_PTERM
Bram Moolenaar0f873732019-12-05 20:28:46 +01004020 // same conflict as the dec mouse
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02004021 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022# ifdef FEAT_GUI
4023 && !gui.in_use
4024# endif
4025 )
Bram Moolenaar424bcae2022-01-31 14:59:41 +00004026 set_mouse_termcode(KS_PTERM_MOUSE, (char_u *)"\033[");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027 else
4028 del_mouse_termcode(KS_PTERM_MOUSE);
4029# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02004030# ifdef FEAT_MOUSE_URXVT
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02004031 if (use_xterm_mouse() == 3
Bram Moolenaarc8427482011-10-20 21:09:35 +02004032# ifdef FEAT_GUI
4033 && !gui.in_use
4034# endif
4035 )
4036 {
4037 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaar424bcae2022-01-31 14:59:41 +00004038 ? "\233*M" : "\033[*M"));
Bram Moolenaarc8427482011-10-20 21:09:35 +02004039
4040 if (*p_mouse != NUL)
4041 {
4042 mch_setmouse(FALSE);
4043 setmouse();
4044 }
4045 }
4046 else
4047 del_mouse_termcode(KS_URXVT_MOUSE);
4048# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004049 if (use_xterm_mouse() == 4
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01004050# ifdef FEAT_GUI
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004051 && !gui.in_use
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01004052# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004053 )
4054 {
4055 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaar424bcae2022-01-31 14:59:41 +00004056 ? "\233<*M" : "\033[<*M"));
Bram Moolenaara529ce02017-06-22 22:37:57 +02004057
4058 set_mouse_termcode(KS_SGR_MOUSE_RELEASE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaar424bcae2022-01-31 14:59:41 +00004059 ? "\233<*m" : "\033[<*m"));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004060
4061 if (*p_mouse != NUL)
4062 {
4063 mch_setmouse(FALSE);
4064 setmouse();
4065 }
4066 }
4067 else
Bram Moolenaara529ce02017-06-22 22:37:57 +02004068 {
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004069 del_mouse_termcode(KS_SGR_MOUSE);
Bram Moolenaara529ce02017-06-22 22:37:57 +02004070 del_mouse_termcode(KS_SGR_MOUSE_RELEASE);
4071 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004073
Bram Moolenaar071d4272004-06-13 20:20:40 +00004074#ifndef VMS
4075
4076/*
4077 * Try to get the current window size:
4078 * 1. with an ioctl(), most accurate method
4079 * 2. from the environment variables LINES and COLUMNS
4080 * 3. from the termcap
4081 * 4. keep using the old values
4082 * Return OK when size could be determined, FAIL otherwise.
4083 */
4084 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004085mch_get_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004086{
4087 long rows = 0;
4088 long columns = 0;
4089 char_u *p;
4090
4091 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092 * 1. try using an ioctl. It is the most accurate method.
4093 *
4094 * Try using TIOCGWINSZ first, some systems that have it also define
4095 * TIOCGSIZE but don't have a struct ttysize.
4096 */
4097# ifdef TIOCGWINSZ
4098 {
4099 struct winsize ws;
4100 int fd = 1;
4101
Bram Moolenaar0f873732019-12-05 20:28:46 +01004102 // When stdout is not a tty, use stdin for the ioctl().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004103 if (!isatty(fd) && isatty(read_cmd_fd))
4104 fd = read_cmd_fd;
4105 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
4106 {
4107 columns = ws.ws_col;
4108 rows = ws.ws_row;
4109 }
4110 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004111# else // TIOCGWINSZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112# ifdef TIOCGSIZE
4113 {
4114 struct ttysize ts;
4115 int fd = 1;
4116
Bram Moolenaar0f873732019-12-05 20:28:46 +01004117 // When stdout is not a tty, use stdin for the ioctl().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118 if (!isatty(fd) && isatty(read_cmd_fd))
4119 fd = read_cmd_fd;
4120 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
4121 {
4122 columns = ts.ts_cols;
4123 rows = ts.ts_lines;
4124 }
4125 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004126# endif // TIOCGSIZE
4127# endif // TIOCGWINSZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00004128
4129 /*
4130 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004131 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
4132 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004134 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135 {
4136 if ((p = (char_u *)getenv("LINES")))
4137 rows = atoi((char *)p);
4138 if ((p = (char_u *)getenv("COLUMNS")))
4139 columns = atoi((char *)p);
4140 }
4141
4142#ifdef HAVE_TGETENT
4143 /*
4144 * 3. try reading "co" and "li" entries from termcap
4145 */
4146 if (columns == 0 || rows == 0)
4147 getlinecol(&columns, &rows);
4148#endif
4149
4150 /*
4151 * 4. If everything fails, use the old values
4152 */
4153 if (columns <= 0 || rows <= 0)
4154 return FAIL;
4155
4156 Rows = rows;
4157 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02004158 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159 return OK;
4160}
4161
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004162#if defined(FEAT_TERMINAL) || defined(PROTO)
4163/*
4164 * Report the windows size "rows" and "cols" to tty "fd".
4165 */
4166 int
4167mch_report_winsize(int fd, int rows, int cols)
4168{
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004169 int tty_fd;
4170 int retval = -1;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004171
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004172 tty_fd = get_tty_fd(fd);
4173 if (tty_fd >= 0)
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004174 {
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004175# if defined(TIOCSWINSZ)
4176 struct winsize ws;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004177
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004178 ws.ws_col = cols;
4179 ws.ws_row = rows;
4180 ws.ws_xpixel = cols * 5;
4181 ws.ws_ypixel = rows * 10;
4182 retval = ioctl(tty_fd, TIOCSWINSZ, &ws);
4183 ch_log(NULL, "ioctl(TIOCSWINSZ) %s",
4184 retval == 0 ? "success" : "failed");
4185# elif defined(TIOCSSIZE)
4186 struct ttysize ts;
4187
4188 ts.ts_cols = cols;
4189 ts.ts_lines = rows;
4190 retval = ioctl(tty_fd, TIOCSSIZE, &ts);
4191 ch_log(NULL, "ioctl(TIOCSSIZE) %s",
4192 retval == 0 ? "success" : "failed");
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004193# endif
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004194 if (tty_fd != fd)
4195 close(tty_fd);
4196 }
4197 return retval == 0 ? OK : FAIL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004198}
4199#endif
4200
Bram Moolenaar071d4272004-06-13 20:20:40 +00004201/*
4202 * Try to set the window size to Rows and Columns.
4203 */
4204 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004205mch_set_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004206{
4207 if (*T_CWS)
4208 {
4209 /*
4210 * NOTE: if you get an error here that term_set_winsize() is
4211 * undefined, check the output of configure. It could probably not
4212 * find a ncurses, termcap or termlib library.
4213 */
4214 term_set_winsize((int)Rows, (int)Columns);
4215 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01004216 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004217 }
4218}
4219
Bram Moolenaar0f873732019-12-05 20:28:46 +01004220#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221
4222/*
4223 * Rows and/or Columns has changed.
4224 */
4225 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004226mch_new_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004227{
Bram Moolenaar0f873732019-12-05 20:28:46 +01004228 // Nothing to do.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229}
4230
Bram Moolenaar205b8862011-09-07 15:04:31 +02004231/*
4232 * Wait for process "child" to end.
4233 * Return "child" if it exited properly, <= 0 on error.
4234 */
4235 static pid_t
Bram Moolenaar05540972016-01-30 20:31:25 +01004236wait4pid(pid_t child, waitstatus *status)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004237{
4238 pid_t wait_pid = 0;
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004239 long delay_msec = 1;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004240
4241 while (wait_pid != child)
4242 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004243 // When compiled with Python threads are probably used, in which case
4244 // wait() sometimes hangs for no obvious reason. Use waitpid()
4245 // instead and loop (like the GUI). Also needed for other interfaces,
4246 // they might call system().
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004247# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004248 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004249# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02004250 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004251# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02004252 if (wait_pid == 0)
4253 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004254 // Wait for 1 to 10 msec before trying again.
Bram Moolenaar0981c872020-08-23 14:28:37 +02004255 mch_delay(delay_msec, MCH_DELAY_IGNOREINPUT | MCH_DELAY_SETTMODE);
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004256 if (++delay_msec > 10)
4257 delay_msec = 10;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004258 continue;
4259 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004260 if (wait_pid <= 0
4261# ifdef ECHILD
4262 && errno == ECHILD
4263# endif
4264 )
4265 break;
4266 }
4267 return wait_pid;
4268}
4269
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01004270#if !defined(USE_SYSTEM) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar7da34602017-08-01 17:14:21 +02004271/*
4272 * Set the environment for a child process.
4273 */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004274 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004275set_child_environment(
4276 long rows,
4277 long columns,
4278 char *term,
4279 int is_terminal UNUSED)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004280{
4281# ifdef HAVE_SETENV
4282 char envbuf[50];
4283# else
Bram Moolenaar5f7e7bd2017-07-22 14:08:43 +02004284 static char envbuf_Term[30];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004285 static char envbuf_Rows[20];
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004286 static char envbuf_Lines[20];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004287 static char envbuf_Columns[20];
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004288 static char envbuf_Colors[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004289# ifdef FEAT_TERMINAL
Bram Moolenaard7a137f2018-06-12 18:05:24 +02004290 static char envbuf_Version[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004291# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004292# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004293 static char envbuf_Servername[60];
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004294# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004295# endif
4296
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004297# ifdef HAVE_SETENV
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004298 setenv("TERM", term, 1);
4299 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004300 setenv("ROWS", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004301 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004302 setenv("LINES", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004303 sprintf((char *)envbuf, "%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004304 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaar759d8152020-04-26 16:52:49 +02004305 sprintf((char *)envbuf, "%d", t_colors);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004306 setenv("COLORS", (char *)envbuf, 1);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004307# ifdef FEAT_TERMINAL
4308 if (is_terminal)
4309 {
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004310 sprintf((char *)envbuf, "%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004311 setenv("VIM_TERMINAL", (char *)envbuf, 1);
4312 }
4313# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004314# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004315 setenv("VIM_SERVERNAME", serverName == NULL ? "" : (char *)serverName, 1);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004316# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004317# else
4318 /*
4319 * Putenv does not copy the string, it has to remain valid.
4320 * Use a static array to avoid losing allocated memory.
Bram Moolenaar7da34602017-08-01 17:14:21 +02004321 * This won't work well when running multiple children...
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004322 */
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004323 vim_snprintf(envbuf_Term, sizeof(envbuf_Term), "TERM=%s", term);
4324 putenv(envbuf_Term);
4325 vim_snprintf(envbuf_Rows, sizeof(envbuf_Rows), "ROWS=%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004326 putenv(envbuf_Rows);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004327 vim_snprintf(envbuf_Lines, sizeof(envbuf_Lines), "LINES=%ld", rows);
4328 putenv(envbuf_Lines);
4329 vim_snprintf(envbuf_Columns, sizeof(envbuf_Columns),
4330 "COLUMNS=%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004331 putenv(envbuf_Columns);
Bram Moolenaaraffc8fd2020-04-28 21:58:29 +02004332 vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", t_colors);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004333 putenv(envbuf_Colors);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004334# ifdef FEAT_TERMINAL
4335 if (is_terminal)
4336 {
4337 vim_snprintf(envbuf_Version, sizeof(envbuf_Version),
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004338 "VIM_TERMINAL=%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004339 putenv(envbuf_Version);
4340 }
4341# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004342# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004343 vim_snprintf(envbuf_Servername, sizeof(envbuf_Servername),
4344 "VIM_SERVERNAME=%s", serverName == NULL ? "" : (char *)serverName);
4345 putenv(envbuf_Servername);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004346# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004347# endif
4348}
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004349
4350 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004351set_default_child_environment(int is_terminal)
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004352{
Bram Moolenaar493359e2018-06-12 20:25:52 +02004353 set_child_environment(Rows, Columns, "dumb", is_terminal);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004354}
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004355#endif
4356
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004357#if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004358/*
4359 * Open a PTY, with FD for the master and slave side.
4360 * When failing "pty_master_fd" and "pty_slave_fd" are -1.
Bram Moolenaar59386482019-02-10 22:43:46 +01004361 * When successful both file descriptors are stored and the allocated pty name
4362 * is stored in both "*name1" and "*name2".
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004363 */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004364 static void
Bram Moolenaar59386482019-02-10 22:43:46 +01004365open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **name1, char_u **name2)
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004366{
4367 char *tty_name;
4368
Bram Moolenaar59386482019-02-10 22:43:46 +01004369 if (name1 != NULL)
4370 *name1 = NULL;
4371 if (name2 != NULL)
4372 *name2 = NULL;
4373
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004374 *pty_master_fd = mch_openpty(&tty_name); // open pty
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004375 if (*pty_master_fd >= 0)
4376 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004377 // Leaving out O_NOCTTY may lead to waitpid() always returning
4378 // 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4379 // adding O_NOCTTY always works when defined.
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004380#ifdef O_NOCTTY
4381 *pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4382#else
4383 *pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4384#endif
4385 if (*pty_slave_fd < 0)
4386 {
4387 close(*pty_master_fd);
4388 *pty_master_fd = -1;
4389 }
Bram Moolenaar59386482019-02-10 22:43:46 +01004390 else
4391 {
4392 if (name1 != NULL)
4393 *name1 = vim_strsave((char_u *)tty_name);
4394 if (name2 != NULL)
4395 *name2 = vim_strsave((char_u *)tty_name);
4396 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004397 }
4398}
4399#endif
4400
Bram Moolenaarfae42832017-08-01 22:24:26 +02004401/*
4402 * Send SIGINT to a child process if "c" is an interrupt character.
4403 */
Bram Moolenaar840d16f2019-09-10 21:27:18 +02004404 static void
Bram Moolenaarfae42832017-08-01 22:24:26 +02004405may_send_sigint(int c UNUSED, pid_t pid UNUSED, pid_t wpid UNUSED)
4406{
4407# ifdef SIGINT
4408 if (c == Ctrl_C || c == intr_char)
4409 {
4410# ifdef HAVE_SETSID
4411 kill(-pid, SIGINT);
4412# else
4413 kill(0, SIGINT);
4414# endif
4415 if (wpid > 0)
4416 kill(wpid, SIGINT);
4417 }
4418# endif
4419}
4420
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004421#if !defined(USE_SYSTEM) || defined(FEAT_TERMINAL) || defined(PROTO)
Bram Moolenaar13568252018-03-16 20:46:58 +01004422
Bram Moolenaar0f873732019-12-05 20:28:46 +01004423/*
4424 * Parse "cmd" and return the result in "argvp" which is an allocated array of
4425 * pointers, the last one is NULL.
4426 * The "sh_tofree" and "shcf_tofree" must be later freed by the caller.
4427 */
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004428 int
4429unix_build_argv(
Bram Moolenaar13568252018-03-16 20:46:58 +01004430 char_u *cmd,
4431 char ***argvp,
4432 char_u **sh_tofree,
4433 char_u **shcf_tofree)
4434{
4435 char **argv = NULL;
4436 int argc;
4437
4438 *sh_tofree = vim_strsave(p_sh);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004439 if (*sh_tofree == NULL) // out of memory
Bram Moolenaar13568252018-03-16 20:46:58 +01004440 return FAIL;
4441
4442 if (mch_parse_cmd(*sh_tofree, TRUE, &argv, &argc) == FAIL)
4443 return FAIL;
4444 *argvp = argv;
4445
4446 if (cmd != NULL)
4447 {
4448 char_u *s;
4449 char_u *p;
4450
4451 if (extra_shell_arg != NULL)
4452 argv[argc++] = (char *)extra_shell_arg;
4453
Bram Moolenaar0f873732019-12-05 20:28:46 +01004454 // Break 'shellcmdflag' into white separated parts. This doesn't
4455 // handle quoted strings, they are very unlikely to appear.
Bram Moolenaar964b3742019-05-24 18:54:09 +02004456 *shcf_tofree = alloc(STRLEN(p_shcf) + 1);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004457 if (*shcf_tofree == NULL) // out of memory
Bram Moolenaar13568252018-03-16 20:46:58 +01004458 return FAIL;
4459 s = *shcf_tofree;
4460 p = p_shcf;
4461 while (*p != NUL)
4462 {
4463 argv[argc++] = (char *)s;
4464 while (*p && *p != ' ' && *p != TAB)
4465 *s++ = *p++;
4466 *s++ = NUL;
4467 p = skipwhite(p);
4468 }
4469
4470 argv[argc++] = (char *)cmd;
4471 }
4472 argv[argc] = NULL;
4473 return OK;
4474}
4475#endif
4476
4477#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
4478/*
4479 * Use a terminal window to run a shell command in.
4480 */
4481 static int
4482mch_call_shell_terminal(
4483 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004484 int options UNUSED) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01004485{
4486 jobopt_T opt;
4487 char **argv = NULL;
4488 char_u *tofree1 = NULL;
4489 char_u *tofree2 = NULL;
4490 int retval = -1;
4491 buf_T *buf;
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004492 job_T *job;
Bram Moolenaar13568252018-03-16 20:46:58 +01004493 aco_save_T aco;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004494 oparg_T oa; // operator arguments
Bram Moolenaar13568252018-03-16 20:46:58 +01004495
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004496 if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar13568252018-03-16 20:46:58 +01004497 goto theend;
4498
4499 init_job_options(&opt);
4500 ch_log(NULL, "starting terminal for system command '%s'", cmd);
4501 buf = term_start(NULL, argv, &opt, TERM_START_SYSTEM);
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004502 if (buf == NULL)
4503 goto theend;
4504
4505 job = term_getjob(buf->b_term);
4506 ++job->jv_refcount;
Bram Moolenaar13568252018-03-16 20:46:58 +01004507
Bram Moolenaar0f873732019-12-05 20:28:46 +01004508 // Find a window to make "buf" curbuf.
Bram Moolenaar13568252018-03-16 20:46:58 +01004509 aucmd_prepbuf(&aco, buf);
4510
4511 clear_oparg(&oa);
4512 while (term_use_loop())
4513 {
4514 if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active)
4515 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004516 // If terminal_loop() returns OK we got a key that is handled
4517 // in Normal model. We don't do redrawing anyway.
Bram Moolenaar13568252018-03-16 20:46:58 +01004518 if (terminal_loop(TRUE) == OK)
4519 normal_cmd(&oa, TRUE);
4520 }
4521 else
4522 normal_cmd(&oa, TRUE);
4523 }
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004524 retval = job->jv_exitval;
Bram Moolenaar13568252018-03-16 20:46:58 +01004525 ch_log(NULL, "system command finished");
4526
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004527 job_unref(job);
4528
Bram Moolenaar0f873732019-12-05 20:28:46 +01004529 // restore curwin/curbuf and a few other things
Bram Moolenaar13568252018-03-16 20:46:58 +01004530 aucmd_restbuf(&aco);
4531
4532 wait_return(TRUE);
4533 do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
4534
4535theend:
4536 vim_free(argv);
4537 vim_free(tofree1);
4538 vim_free(tofree2);
4539 return retval;
4540}
4541#endif
4542
4543#ifdef USE_SYSTEM
4544/*
4545 * Use system() to start the shell: simple but slow.
4546 */
4547 static int
4548mch_call_shell_system(
Bram Moolenaar05540972016-01-30 20:31:25 +01004549 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004550 int options) // SHELL_*, see vim.h
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551{
4552#ifdef VMS
4553 char *ifn = NULL;
4554 char *ofn = NULL;
4555#endif
Bram Moolenaar26e86442020-05-17 14:06:16 +02004556 tmode_T tmode = cur_tmode;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004557 char_u *newcmd; // only needed for unix
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01004558 int x;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559
4560 out_flush();
4561
4562 if (options & SHELL_COOKED)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004563 settmode(TMODE_COOK); // set to normal mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00004564
Bram Moolenaar62b42182010-09-21 22:09:37 +02004565# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004566 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02004567 loose_clipboard();
4568# endif
4569
Bram Moolenaar071d4272004-06-13 20:20:40 +00004570 if (cmd == NULL)
4571 x = system((char *)p_sh);
4572 else
4573 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004574# ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004575 if (ofn = strchr((char *)cmd, '>'))
4576 *ofn++ = '\0';
4577 if (ifn = strchr((char *)cmd, '<'))
4578 {
4579 char *p;
4580
4581 *ifn++ = '\0';
Bram Moolenaar0f873732019-12-05 20:28:46 +01004582 p = strchr(ifn,' '); // chop off any trailing spaces
Bram Moolenaar071d4272004-06-13 20:20:40 +00004583 if (p)
4584 *p = '\0';
4585 }
4586 if (ofn)
4587 x = vms_sys((char *)cmd, ofn, ifn);
4588 else
4589 x = system((char *)cmd);
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004590# else
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004591 newcmd = alloc(STRLEN(p_sh)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004593 + STRLEN(p_shcf) + STRLEN(cmd) + 4);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004594 if (newcmd == NULL)
4595 x = 0;
4596 else
4597 {
4598 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
4599 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
4600 (char *)p_shcf,
4601 (char *)cmd);
4602 x = system((char *)newcmd);
4603 vim_free(newcmd);
4604 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004605# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004606 }
4607# ifdef VMS
4608 x = vms_sys_status(x);
4609# endif
4610 if (emsg_silent)
4611 ;
4612 else if (x == 127)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004613 msg_puts(_("\nCannot execute shell sh\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614 else if (x && !(options & SHELL_SILENT))
4615 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004616 msg_puts(_("\nshell returned "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 msg_outnum((long)x);
4618 msg_putchar('\n');
4619 }
4620
4621 if (tmode == TMODE_RAW)
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004622 {
4623 // The shell may have messed with the mode, always set it.
4624 cur_tmode = TMODE_UNKNOWN;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004625 settmode(TMODE_RAW); // set to raw mode
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004626 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 resettitle();
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004628# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4629 restore_clipboard();
4630# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631 return x;
Bram Moolenaar13568252018-03-16 20:46:58 +01004632}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004633
Bram Moolenaar0f873732019-12-05 20:28:46 +01004634#else // USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00004635
Bram Moolenaar0f873732019-12-05 20:28:46 +01004636# define EXEC_FAILED 122 // Exit code when shell didn't execute. Don't use
4637 // 127, some shells use that already
4638# define OPEN_NULL_FAILED 123 // Exit code if /dev/null can't be opened
Bram Moolenaar071d4272004-06-13 20:20:40 +00004639
Bram Moolenaar13568252018-03-16 20:46:58 +01004640/*
4641 * Don't use system(), use fork()/exec().
4642 */
4643 static int
4644mch_call_shell_fork(
4645 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004646 int options) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01004647{
Bram Moolenaar26e86442020-05-17 14:06:16 +02004648 tmode_T tmode = cur_tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004649 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004650 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004651 pid_t wait_pid = 0;
4652# ifdef HAVE_UNION_WAIT
4653 union wait status;
4654# else
4655 int status = -1;
4656# endif
4657 int retval = -1;
4658 char **argv = NULL;
Bram Moolenaar13568252018-03-16 20:46:58 +01004659 char_u *tofree1 = NULL;
4660 char_u *tofree2 = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661 int i;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004662 int pty_master_fd = -1; // for pty's
Bram Moolenaardf177f62005-02-22 08:39:57 +00004663# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004664 int pty_slave_fd = -1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004665# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01004666 int fd_toshell[2]; // for pipes
Bram Moolenaar071d4272004-06-13 20:20:40 +00004667 int fd_fromshell[2];
4668 int pipe_error = FALSE;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004669 int did_settmode = FALSE; // settmode(TMODE_RAW) called
Bram Moolenaar071d4272004-06-13 20:20:40 +00004670
4671 out_flush();
4672 if (options & SHELL_COOKED)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004673 settmode(TMODE_COOK); // set to normal mode
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004674 if (tmode == TMODE_RAW)
4675 // The shell may have messed with the mode, always set it later.
4676 cur_tmode = TMODE_UNKNOWN;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004677
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004678 if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar835dc632016-02-07 14:27:38 +01004679 goto error;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004680
Bram Moolenaar071d4272004-06-13 20:20:40 +00004681 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004682 * For the GUI, when writing the output into the buffer and when reading
4683 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4684 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004685 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004686 if ((options & (SHELL_READ|SHELL_WRITE))
4687# ifdef FEAT_GUI
4688 || (gui.in_use && show_shell_mess)
4689# endif
4690 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004691 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004692# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004693 /*
4694 * Try to open a master pty.
4695 * If this works, open the slave pty.
4696 * If the slave can't be opened, close the master pty.
4697 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004698 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar59386482019-02-10 22:43:46 +01004699 open_pty(&pty_master_fd, &pty_slave_fd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004700 /*
4701 * If not opening a pty or it didn't work, try using pipes.
4702 */
4703 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004704# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705 {
4706 pipe_error = (pipe(fd_toshell) < 0);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004707 if (!pipe_error) // pipe create OK
Bram Moolenaar071d4272004-06-13 20:20:40 +00004708 {
4709 pipe_error = (pipe(fd_fromshell) < 0);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004710 if (pipe_error) // pipe create failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00004711 {
4712 close(fd_toshell[0]);
4713 close(fd_toshell[1]);
4714 }
4715 }
4716 if (pipe_error)
4717 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004718 msg_puts(_("\nCannot create pipes\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004719 out_flush();
4720 }
4721 }
4722 }
4723
Bram Moolenaar0f873732019-12-05 20:28:46 +01004724 if (!pipe_error) // pty or pipe opened or not used
Bram Moolenaar071d4272004-06-13 20:20:40 +00004725 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004726 SIGSET_DECL(curset)
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004727 BLOCK_SIGNALS(&curset);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004728 pid = fork(); // maybe we should use vfork()
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004729 if (pid == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004731 UNBLOCK_SIGNALS(&curset);
4732
Bram Moolenaar32526b32019-01-19 17:43:09 +01004733 msg_puts(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004734 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004736 || (gui.in_use && show_shell_mess)
4737# endif
4738 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004739 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004740# ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01004741 if (pty_master_fd >= 0) // close the pseudo tty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742 {
4743 close(pty_master_fd);
4744 close(pty_slave_fd);
4745 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004746 else // close the pipes
Bram Moolenaardf177f62005-02-22 08:39:57 +00004747# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748 {
4749 close(fd_toshell[0]);
4750 close(fd_toshell[1]);
4751 close(fd_fromshell[0]);
4752 close(fd_fromshell[1]);
4753 }
4754 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004755 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004756 else if (pid == 0) // child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004757 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004758 reset_signals(); // handle signals normally
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004759 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004760
Bram Moolenaar819524702018-02-27 19:10:00 +01004761# ifdef FEAT_JOB_CHANNEL
4762 if (ch_log_active())
Bram Moolenaar76603ba2020-08-30 17:24:37 +02004763 {
4764 ch_log(NULL, "closing channel log in the child process");
Bram Moolenaar819524702018-02-27 19:10:00 +01004765 ch_logfile((char_u *)"", (char_u *)"");
Bram Moolenaar76603ba2020-08-30 17:24:37 +02004766 }
Bram Moolenaar819524702018-02-27 19:10:00 +01004767# endif
4768
Bram Moolenaar071d4272004-06-13 20:20:40 +00004769 if (!show_shell_mess || (options & SHELL_EXPAND))
4770 {
4771 int fd;
4772
4773 /*
4774 * Don't want to show any message from the shell. Can't just
4775 * close stdout and stderr though, because some systems will
4776 * break if you try to write to them after that, so we must
4777 * use dup() to replace them with something else -- webb
4778 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4779 * waiting for input.
4780 */
4781 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4782 fclose(stdin);
4783 fclose(stdout);
4784 fclose(stderr);
4785
4786 /*
4787 * If any of these open()'s and dup()'s fail, we just continue
4788 * anyway. It's not fatal, and on most systems it will make
4789 * no difference at all. On a few it will cause the execvp()
4790 * to exit with a non-zero status even when the completion
4791 * could be done, which is nothing too serious. If the open()
4792 * or dup() failed we'd just do the same thing ourselves
4793 * anyway -- webb
4794 */
4795 if (fd >= 0)
4796 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004797 vim_ignored = dup(fd); // To replace stdin (fd 0)
4798 vim_ignored = dup(fd); // To replace stdout (fd 1)
4799 vim_ignored = dup(fd); // To replace stderr (fd 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004800
Bram Moolenaar0f873732019-12-05 20:28:46 +01004801 // Don't need this now that we've duplicated it
Bram Moolenaar071d4272004-06-13 20:20:40 +00004802 close(fd);
4803 }
4804 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004805 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004806# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004807 || gui.in_use
4808# endif
4809 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004810 {
4811
Bram Moolenaardf177f62005-02-22 08:39:57 +00004812# ifdef HAVE_SETSID
Bram Moolenaar0f873732019-12-05 20:28:46 +01004813 // Create our own process group, so that the child and all its
4814 // children can be kill()ed. Don't do this when using pipes,
4815 // because stdin is not a tty, we would lose /dev/tty.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004816 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004817 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004818 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004819# if defined(SIGHUP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004820 // When doing "!xterm&" and 'shell' is bash: the shell
4821 // will exit and send SIGHUP to all processes in its
4822 // group, killing the just started process. Ignore SIGHUP
4823 // to avoid that. (suggested by Simon Schubert)
Bram Moolenaar07256082009-02-04 13:19:42 +00004824 signal(SIGHUP, SIG_IGN);
4825# endif
4826 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004827# endif
4828# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004829 if (pty_slave_fd >= 0)
4830 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004831 // push stream discipline modules
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004832 if (options & SHELL_COOKED)
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004833 setup_slavepty(pty_slave_fd);
Bram Moolenaarfff10d92021-10-13 10:05:30 +01004834# ifdef TIOCSCTTY
4835 // Try to become controlling tty (probably doesn't work,
4836 // unless run by root)
4837 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
4838# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004839 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004840# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02004841 set_default_child_environment(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004842
Bram Moolenaara5792f52005-11-23 21:25:05 +00004843 /*
4844 * stderr is only redirected when using the GUI, so that a
4845 * program like gpg can still access the terminal to get a
4846 * passphrase using stderr.
4847 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004848# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004849 if (pty_master_fd >= 0)
4850 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004851 close(pty_master_fd); // close master side of pty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004852
Bram Moolenaar0f873732019-12-05 20:28:46 +01004853 // set up stdin/stdout/stderr for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004854 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004855 vim_ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004856 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004857 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004858 if (gui.in_use)
4859 {
4860 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004861 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004862 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004863
Bram Moolenaar0f873732019-12-05 20:28:46 +01004864 close(pty_slave_fd); // has been dupped, close it now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004865 }
4866 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004867# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004868 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004869 // set up stdin for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004870 close(fd_toshell[1]);
4871 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004872 vim_ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004873 close(fd_toshell[0]);
4874
Bram Moolenaar0f873732019-12-05 20:28:46 +01004875 // set up stdout for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004876 close(fd_fromshell[0]);
4877 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004878 vim_ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004879 close(fd_fromshell[1]);
4880
Bram Moolenaara5792f52005-11-23 21:25:05 +00004881# ifdef FEAT_GUI
4882 if (gui.in_use)
4883 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004884 // set up stderr for the child
Bram Moolenaara5792f52005-11-23 21:25:05 +00004885 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004886 vim_ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004887 }
4888# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004889 }
4890 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004891
Bram Moolenaar071d4272004-06-13 20:20:40 +00004892 /*
4893 * There is no type cast for the argv, because the type may be
4894 * different on different machines. This may cause a warning
4895 * message with strict compilers, don't worry about it.
4896 * Call _exit() instead of exit() to avoid closing the connection
4897 * to the X server (esp. with GTK, which uses atexit()).
4898 */
4899 execvp(argv[0], argv);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004900 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004902 else // parent
Bram Moolenaar071d4272004-06-13 20:20:40 +00004903 {
4904 /*
4905 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004906 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004907 */
4908 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004909 catch_int_signal();
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004910 UNBLOCK_SIGNALS(&curset);
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01004911# ifdef FEAT_JOB_CHANNEL
4912 ++dont_check_job_ended;
4913# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004914 /*
4915 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004916 * This is also used to pipe stdin/stdout to/from the external
4917 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004919 if ((options & (SHELL_READ|SHELL_WRITE))
4920# ifdef FEAT_GUI
4921 || (gui.in_use && show_shell_mess)
4922# endif
4923 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004924 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004925# define BUFLEN 100 // length for buffer, pseudo tty limit is 128
Bram Moolenaar071d4272004-06-13 20:20:40 +00004926 char_u buffer[BUFLEN + 1];
Bram Moolenaar0f873732019-12-05 20:28:46 +01004927 int buffer_off = 0; // valid bytes in buffer[]
4928 char_u ta_buf[BUFLEN + 1]; // TypeAHead
4929 int ta_len = 0; // valid bytes in ta_buf[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00004930 int len;
4931 int p_more_save;
4932 int old_State;
4933 int c;
4934 int toshell_fd;
4935 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004936 garray_T ga;
4937 int noread_cnt;
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01004938# ifdef ELAPSED_FUNC
4939 elapsed_T start_tv;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004940# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004941
Bram Moolenaardf177f62005-02-22 08:39:57 +00004942# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004943 if (pty_master_fd >= 0)
4944 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004945 fromshell_fd = pty_master_fd;
4946 toshell_fd = dup(pty_master_fd);
4947 }
4948 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004949# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004950 {
4951 close(fd_toshell[0]);
4952 close(fd_fromshell[1]);
4953 toshell_fd = fd_toshell[1];
4954 fromshell_fd = fd_fromshell[0];
4955 }
4956
4957 /*
4958 * Write to the child if there are typed characters.
4959 * Read from the child if there are characters available.
4960 * Repeat the reading a few times if more characters are
4961 * available. Need to check for typed keys now and then, but
4962 * not too often (delays when no chars are available).
4963 * This loop is quit if no characters can be read from the pty
4964 * (WaitForChar detected special condition), or there are no
4965 * characters available and the child has exited.
4966 * Only check if the child has exited when there is no more
4967 * output. The child may exit before all the output has
4968 * been printed.
4969 *
4970 * Currently this busy loops!
4971 * This can probably dead-lock when the write blocks!
4972 */
4973 p_more_save = p_more;
4974 p_more = FALSE;
4975 old_State = State;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004976 State = EXTERNCMD; // don't redraw at window resize
Bram Moolenaar071d4272004-06-13 20:20:40 +00004977
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004978 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004979 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004980 // Fork a process that will write the lines to the
4981 // external program.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004982 if ((wpid = fork()) == -1)
4983 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004984 msg_puts(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004985 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004986 else if (wpid == 0) // child
Bram Moolenaardf177f62005-02-22 08:39:57 +00004987 {
4988 linenr_T lnum = curbuf->b_op_start.lnum;
4989 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004990 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004991 size_t l;
4992
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004993 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004994 for (;;)
4995 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004996 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004997 if (l == 0)
4998 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004999 else if (lp[written] == NL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005000 // NL -> NUL translation
Bram Moolenaardf177f62005-02-22 08:39:57 +00005001 len = write(toshell_fd, "", (size_t)1);
5002 else
5003 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01005004 char_u *s = vim_strchr(lp + written, NL);
5005
Bram Moolenaar89d40322006-08-29 15:30:07 +00005006 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00005007 s == NULL ? l
5008 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00005009 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00005010 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00005011 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005012 // Finished a line, add a NL, unless this line
5013 // should not have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005014 if (lnum != curbuf->b_op_end.lnum
Bram Moolenaar34d72d42015-07-17 14:18:08 +02005015 || (!curbuf->b_p_bin
5016 && curbuf->b_p_fixeol)
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005017 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00005018 && (lnum !=
5019 curbuf->b_ml.ml_line_count
5020 || curbuf->b_p_eol)))
Bram Moolenaar42335f52018-09-13 15:33:43 +02005021 vim_ignored = write(toshell_fd, "\n",
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00005022 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005023 ++lnum;
5024 if (lnum > curbuf->b_op_end.lnum)
5025 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005026 // finished all the lines, close pipe
Bram Moolenaardf177f62005-02-22 08:39:57 +00005027 close(toshell_fd);
5028 toshell_fd = -1;
5029 break;
5030 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00005031 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005032 written = 0;
5033 }
5034 else if (len > 0)
5035 written += len;
5036 }
5037 _exit(0);
5038 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01005039 else // parent
Bram Moolenaardf177f62005-02-22 08:39:57 +00005040 {
5041 close(toshell_fd);
5042 toshell_fd = -1;
5043 }
5044 }
5045
5046 if (options & SHELL_READ)
5047 ga_init2(&ga, 1, BUFLEN);
5048
5049 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005050# ifdef ELAPSED_FUNC
5051 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005052# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005053 for (;;)
5054 {
5055 /*
5056 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005057 * if there are any.
5058 * Don't do this if we are expanding wild cards (would eat
5059 * typeahead).
5060 * Don't do this when filtering and terminal is in cooked
5061 * mode, the shell command will handle the I/O. Avoids
5062 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005063 * Don't get characters when the child has already
5064 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00005065 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005066 * while (noread_cnt > 4), avoids that ":r !ls" eats
5067 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005068 */
5069 len = 0;
5070 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005071 && ((options &
5072 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
5073 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005074# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005075 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005076# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005077 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005078 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005079 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005080 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005081 if (ta_len == 0)
5082 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005083 // Get extra characters when we don't have any.
5084 // Reset the counter and timer.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005085 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005086# ifdef ELAPSED_FUNC
5087 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005088# endif
5089 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
5090 }
5091 if (ta_len > 0 || len > 0)
5092 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005093 /*
5094 * For pipes:
5095 * Check for CTRL-C: send interrupt signal to child.
5096 * Check for CTRL-D: EOF, close pipe to child.
5097 */
5098 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
5099 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005100 /*
5101 * Send SIGINT to the child's group or all
5102 * processes in our group.
5103 */
Bram Moolenaarfae42832017-08-01 22:24:26 +02005104 may_send_sigint(ta_buf[ta_len], pid, wpid);
5105
Bram Moolenaar071d4272004-06-13 20:20:40 +00005106 if (pty_master_fd < 0 && toshell_fd >= 0
5107 && ta_buf[ta_len] == Ctrl_D)
5108 {
5109 close(toshell_fd);
5110 toshell_fd = -1;
5111 }
5112 }
5113
Bram Moolenaarf4140482020-02-15 23:06:45 +01005114 term_replace_bs_del_keycode(ta_buf, ta_len, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005115
5116 /*
5117 * For pipes: echo the typed characters.
5118 * For a pty this does not seem to work.
5119 */
5120 if (pty_master_fd < 0)
5121 {
5122 for (i = ta_len; i < ta_len + len; ++i)
5123 {
5124 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
5125 msg_putchar(ta_buf[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005126 else if (has_mbyte)
5127 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005128 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005129
5130 msg_outtrans_len(ta_buf + i, l);
5131 i += l - 1;
5132 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005133 else
5134 msg_outtrans_len(ta_buf + i, 1);
5135 }
5136 windgoto(msg_row, msg_col);
5137 out_flush();
5138 }
5139
5140 ta_len += len;
5141
5142 /*
5143 * Write the characters to the child, unless EOF has
5144 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005145 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005146 * When writing buffer lines, drop the typed
5147 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005148 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005149 if (options & SHELL_WRITE)
5150 ta_len = 0;
5151 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005152 {
5153 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
5154 if (len > 0)
5155 {
5156 ta_len -= len;
5157 mch_memmove(ta_buf, ta_buf + len, ta_len);
5158 }
5159 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005160 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005161 }
5162
Bram Moolenaardf177f62005-02-22 08:39:57 +00005163 if (got_int)
5164 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005165 // CTRL-C sends a signal to the child, we ignore it
5166 // ourselves
Bram Moolenaardf177f62005-02-22 08:39:57 +00005167# ifdef HAVE_SETSID
5168 kill(-pid, SIGINT);
5169# else
5170 kill(0, SIGINT);
5171# endif
5172 if (wpid > 0)
5173 kill(wpid, SIGINT);
5174 got_int = FALSE;
5175 }
5176
Bram Moolenaar071d4272004-06-13 20:20:40 +00005177 /*
5178 * Check if the child has any characters to be printed.
5179 * Read them and write them to our window. Repeat this as
5180 * long as there is something to do, avoid the 10ms wait
5181 * for mch_inchar(), or sending typeahead characters to
5182 * the external process.
5183 * TODO: This should handle escape sequences, compatible
5184 * to some terminal (vt52?).
5185 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005186 ++noread_cnt;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005187 while (RealWaitForChar(fromshell_fd, 10L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005188 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005189 len = read_eintr(fromshell_fd, buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00005190 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005191 );
Bram Moolenaar0f873732019-12-05 20:28:46 +01005192 if (len <= 0) // end of file or error
Bram Moolenaar071d4272004-06-13 20:20:40 +00005193 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005194
5195 noread_cnt = 0;
5196 if (options & SHELL_READ)
5197 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005198 // Do NUL -> NL translation, append NL separated
5199 // lines to the current buffer.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005200 for (i = 0; i < len; ++i)
5201 {
5202 if (buffer[i] == NL)
5203 append_ga_line(&ga);
5204 else if (buffer[i] == NUL)
5205 ga_append(&ga, NL);
5206 else
5207 ga_append(&ga, buffer[i]);
5208 }
5209 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005210 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005211 {
5212 int l;
Bram Moolenaara2150ac2018-03-17 13:15:17 +01005213 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005214
Bram Moolenaardf177f62005-02-22 08:39:57 +00005215 len += buffer_off;
5216 buffer[len] = NUL;
5217
Bram Moolenaar0f873732019-12-05 20:28:46 +01005218 // Check if the last character in buffer[] is
5219 // incomplete, keep these bytes for the next
5220 // round.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221 for (p = buffer; p < buffer + len; p += l)
5222 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02005223 l = MB_CPTR2LEN(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005224 if (l == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005225 l = 1; // NUL byte?
Bram Moolenaar071d4272004-06-13 20:20:40 +00005226 else if (MB_BYTE2LEN(*p) != l)
5227 break;
5228 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01005229 if (p == buffer) // no complete character
Bram Moolenaar071d4272004-06-13 20:20:40 +00005230 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005231 // avoid getting stuck at an illegal byte
Bram Moolenaar071d4272004-06-13 20:20:40 +00005232 if (len >= 12)
5233 ++p;
5234 else
5235 {
5236 buffer_off = len;
5237 continue;
5238 }
5239 }
5240 c = *p;
5241 *p = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005242 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005243 if (p < buffer + len)
5244 {
5245 *p = c;
5246 buffer_off = (buffer + len) - p;
5247 mch_memmove(buffer, p, buffer_off);
5248 continue;
5249 }
5250 buffer_off = 0;
5251 }
5252 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005253 {
5254 buffer[len] = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005255 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005256 }
5257
5258 windgoto(msg_row, msg_col);
5259 cursor_on();
5260 out_flush();
5261 if (got_int)
5262 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005263
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005264# ifdef ELAPSED_FUNC
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005265 if (wait_pid == 0)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005266 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005267 long msec = ELAPSED_FUNC(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005268
Bram Moolenaar0f873732019-12-05 20:28:46 +01005269 // Avoid that we keep looping here without
5270 // checking for a CTRL-C for a long time. Don't
5271 // break out too often to avoid losing typeahead.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005272 if (msec > 2000)
5273 {
5274 noread_cnt = 5;
5275 break;
5276 }
5277 }
5278# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005279 }
5280
Bram Moolenaar0f873732019-12-05 20:28:46 +01005281 // If we already detected the child has finished, continue
5282 // reading output for a short while. Some text may be
5283 // buffered.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005284 if (wait_pid == pid)
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005285 {
5286 if (noread_cnt < 5)
5287 continue;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005288 break;
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005289 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005290
Bram Moolenaar071d4272004-06-13 20:20:40 +00005291 /*
5292 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005293 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005294 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005295# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02005296 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005297# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005298 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005299# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005300 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5301 || (wait_pid == pid && WIFEXITED(status)))
5302 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005303 // Don't break the loop yet, try reading more
5304 // characters from "fromshell_fd" first. When using
5305 // pipes there might still be something to read and
5306 // then we'll break the loop at the "break" above.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005307 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005308 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005309 else
5310 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005311
Bram Moolenaar95a51352013-03-21 22:53:50 +01005312# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005313 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005314 clip_update();
5315# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005316 }
5317finished:
5318 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005319 if (options & SHELL_READ)
5320 {
5321 if (ga.ga_len > 0)
5322 {
5323 append_ga_line(&ga);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005324 // remember that the NL was missing
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005325 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005326 }
5327 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005328 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005329 ga_clear(&ga);
5330 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005331
Bram Moolenaar071d4272004-06-13 20:20:40 +00005332 /*
5333 * Give all typeahead that wasn't used back to ui_inchar().
5334 */
5335 if (ta_len)
5336 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005337 State = old_State;
5338 if (toshell_fd >= 0)
5339 close(toshell_fd);
5340 close(fromshell_fd);
5341 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01005342# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005343 else
5344 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005345 long delay_msec = 1;
5346
Bram Moolenaar8a3da6a2020-12-08 19:18:37 +01005347 if (tmode == TMODE_RAW)
5348 // possibly disables modifyOtherKeys, so that the system
5349 // can recognize CTRL-C
5350 out_str(T_CTE);
Bram Moolenaar0981c872020-08-23 14:28:37 +02005351
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005352 /*
5353 * Similar to the loop above, but only handle X events, no
5354 * I/O.
5355 */
5356 for (;;)
5357 {
5358 if (got_int)
5359 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005360 // CTRL-C sends a signal to the child, we ignore it
5361 // ourselves
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005362# ifdef HAVE_SETSID
5363 kill(-pid, SIGINT);
5364# else
5365 kill(0, SIGINT);
5366# endif
5367 got_int = FALSE;
5368 }
5369# ifdef __NeXT__
5370 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
5371# else
5372 wait_pid = waitpid(pid, &status, WNOHANG);
5373# endif
5374 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5375 || (wait_pid == pid && WIFEXITED(status)))
5376 {
5377 wait_pid = pid;
5378 break;
5379 }
5380
Bram Moolenaar0f873732019-12-05 20:28:46 +01005381 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005382 clip_update();
5383
Bram Moolenaar0f873732019-12-05 20:28:46 +01005384 // Wait for 1 to 10 msec. 1 is faster but gives the child
Bram Moolenaar0981c872020-08-23 14:28:37 +02005385 // less time, gradually wait longer.
5386 mch_delay(delay_msec,
5387 MCH_DELAY_IGNOREINPUT | MCH_DELAY_SETTMODE);
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005388 if (++delay_msec > 10)
5389 delay_msec = 10;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005390 }
Bram Moolenaar0981c872020-08-23 14:28:37 +02005391
Bram Moolenaar8a3da6a2020-12-08 19:18:37 +01005392 if (tmode == TMODE_RAW)
5393 // possibly enables modifyOtherKeys again
5394 out_str(T_CTI);
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005395 }
5396# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005397
5398 /*
5399 * Wait until our child has exited.
5400 * Ignore wait() returning pids of other children and returning
5401 * because of some signal like SIGWINCH.
5402 * Don't wait if wait_pid was already set above, indicating the
5403 * child already exited.
5404 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02005405 if (wait_pid != pid)
5406 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407
Bram Moolenaar624891f2010-10-13 16:22:09 +02005408# ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01005409 // Close slave side of pty. Only do this after the child has
5410 // exited, otherwise the child may hang when it tries to write on
5411 // the pty.
Bram Moolenaar624891f2010-10-13 16:22:09 +02005412 if (pty_master_fd >= 0)
5413 close(pty_slave_fd);
5414# endif
5415
Bram Moolenaar0f873732019-12-05 20:28:46 +01005416 // Make sure the child that writes to the external program is
5417 // dead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005418 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02005419 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00005420 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02005421 wait4pid(wpid, NULL);
5422 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005423
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005424# ifdef FEAT_JOB_CHANNEL
5425 --dont_check_job_ended;
5426# endif
5427
Bram Moolenaar071d4272004-06-13 20:20:40 +00005428 /*
5429 * Set to raw mode right now, otherwise a CTRL-C after
5430 * catch_signals() will kill Vim.
5431 */
5432 if (tmode == TMODE_RAW)
5433 settmode(TMODE_RAW);
5434 did_settmode = TRUE;
5435 set_signals();
5436
5437 if (WIFEXITED(status))
5438 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005439 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar071d4272004-06-13 20:20:40 +00005440 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01005441 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005442 {
5443 if (retval == EXEC_FAILED)
5444 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005445 msg_puts(_("\nCannot execute shell "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005446 msg_outtrans(p_sh);
5447 msg_putchar('\n');
5448 }
5449 else if (!(options & SHELL_SILENT))
5450 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005451 msg_puts(_("\nshell returned "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005452 msg_outnum((long)retval);
5453 msg_putchar('\n');
5454 }
5455 }
5456 }
5457 else
Bram Moolenaar32526b32019-01-19 17:43:09 +01005458 msg_puts(_("\nCommand terminated\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005459 }
5460 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005461
5462error:
5463 if (!did_settmode)
5464 if (tmode == TMODE_RAW)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005465 settmode(TMODE_RAW); // set to raw mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00005466 resettitle();
Bram Moolenaar13568252018-03-16 20:46:58 +01005467 vim_free(argv);
5468 vim_free(tofree1);
5469 vim_free(tofree2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005470
5471 return retval;
Bram Moolenaar13568252018-03-16 20:46:58 +01005472}
Bram Moolenaar0f873732019-12-05 20:28:46 +01005473#endif // USE_SYSTEM
Bram Moolenaar13568252018-03-16 20:46:58 +01005474
5475 int
5476mch_call_shell(
5477 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01005478 int options) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01005479{
5480#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
5481 if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL)
5482 return mch_call_shell_terminal(cmd, options);
5483#endif
5484#ifdef USE_SYSTEM
5485 return mch_call_shell_system(cmd, options);
5486#else
5487 return mch_call_shell_fork(cmd, options);
5488#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005489}
5490
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005491#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005492 void
Bram Moolenaar493359e2018-06-12 20:25:52 +02005493mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005494{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005495 pid_t pid;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005496 int fd_in[2] = {-1, -1}; // for stdin
5497 int fd_out[2] = {-1, -1}; // for stdout
5498 int fd_err[2] = {-1, -1}; // for stderr
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005499 int pty_master_fd = -1;
5500 int pty_slave_fd = -1;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01005501 channel_T *channel = NULL;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005502 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
5503 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
5504 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005505 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005506 int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
5507 int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
Bram Moolenaarb2412082017-08-20 18:09:14 +02005508 int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER;
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005509 int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005510 SIGSET_DECL(curset)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005511
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005512 if (use_out_for_err && use_null_for_out)
5513 use_null_for_err = TRUE;
5514
Bram Moolenaar0f873732019-12-05 20:28:46 +01005515 // default is to fail
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005516 job->jv_status = JOB_FAILED;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005517
Bram Moolenaarb2412082017-08-20 18:09:14 +02005518 if (options->jo_pty
5519 && (!(use_file_for_in || use_null_for_in)
Bram Moolenaar59386482019-02-10 22:43:46 +01005520 || !(use_file_for_out || use_null_for_out)
Bram Moolenaarb2412082017-08-20 18:09:14 +02005521 || !(use_out_for_err || use_file_for_err || use_null_for_err)))
Bram Moolenaar59386482019-02-10 22:43:46 +01005522 open_pty(&pty_master_fd, &pty_slave_fd,
5523 &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005524
Bram Moolenaar0f873732019-12-05 20:28:46 +01005525 // TODO: without the channel feature connect the child to /dev/null?
5526 // Open pipes for stdin, stdout, stderr.
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005527 if (use_file_for_in)
5528 {
5529 char_u *fname = options->jo_io_name[PART_IN];
5530
5531 fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
5532 if (fd_in[0] < 0)
5533 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00005534 semsg(_(e_cant_open_file_str), fname);
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005535 goto failed;
5536 }
5537 }
Bram Moolenaarb2412082017-08-20 18:09:14 +02005538 else
Bram Moolenaar0f873732019-12-05 20:28:46 +01005539 // When writing buffer lines to the input don't use the pty, so that
5540 // the pipe can be closed when all lines were written.
Bram Moolenaarb2412082017-08-20 18:09:14 +02005541 if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in)
5542 && pipe(fd_in) < 0)
5543 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005544
5545 if (use_file_for_out)
5546 {
5547 char_u *fname = options->jo_io_name[PART_OUT];
5548
5549 fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
5550 if (fd_out[1] < 0)
5551 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00005552 semsg(_(e_cant_open_file_str), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005553 goto failed;
5554 }
5555 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005556 else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005557 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005558
5559 if (use_file_for_err)
5560 {
5561 char_u *fname = options->jo_io_name[PART_ERR];
5562
5563 fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
5564 if (fd_err[1] < 0)
5565 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00005566 semsg(_(e_cant_open_file_str), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005567 goto failed;
5568 }
5569 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005570 else if (!use_out_for_err && !use_null_for_err
5571 && pty_master_fd < 0 && pipe(fd_err) < 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005572 goto failed;
5573
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005574 if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5575 {
Bram Moolenaarde279892016-03-11 22:19:44 +01005576 if (options->jo_set & JO_CHANNEL)
5577 {
5578 channel = options->jo_channel;
5579 if (channel != NULL)
5580 ++channel->ch_refcount;
5581 }
5582 else
5583 channel = add_channel();
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005584 if (channel == NULL)
5585 goto failed;
Bram Moolenaarf3360612017-10-01 16:21:31 +02005586 if (job->jv_tty_out != NULL)
5587 ch_log(channel, "using pty %s on fd %d",
5588 job->jv_tty_out, pty_master_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005589 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005590
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005591 BLOCK_SIGNALS(&curset);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005592 pid = fork(); // maybe we should use vfork()
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005593 if (pid == -1)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005594 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005595 // failed to fork
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005596 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005597 goto failed;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005598 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005599 if (pid == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005600 {
Bram Moolenaar4694a172016-04-21 14:05:23 +02005601 int null_fd = -1;
5602 int stderr_works = TRUE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005603
Bram Moolenaar0f873732019-12-05 20:28:46 +01005604 // child
5605 reset_signals(); // handle signals normally
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005606 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005607
Bram Moolenaar819524702018-02-27 19:10:00 +01005608# ifdef FEAT_JOB_CHANNEL
5609 if (ch_log_active())
Bram Moolenaar0f873732019-12-05 20:28:46 +01005610 // close the log file in the child
Bram Moolenaar819524702018-02-27 19:10:00 +01005611 ch_logfile((char_u *)"", (char_u *)"");
5612# endif
5613
Bram Moolenaar835dc632016-02-07 14:27:38 +01005614# ifdef HAVE_SETSID
Bram Moolenaar0f873732019-12-05 20:28:46 +01005615 // Create our own process group, so that the child and all its
5616 // children can be kill()ed. Don't do this when using pipes,
5617 // because stdin is not a tty, we would lose /dev/tty.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005618 (void)setsid();
5619# endif
5620
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005621# ifdef FEAT_TERMINAL
5622 if (options->jo_term_rows > 0)
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005623 {
5624 char *term = (char *)T_NAME;
5625
5626#ifdef FEAT_GUI
5627 if (term_is_gui(T_NAME))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005628 // In the GUI 'term' is not what we want, use $TERM.
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005629 term = getenv("TERM");
5630#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005631 // Use 'term' or $TERM if it starts with "xterm", otherwise fall
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005632 // back to "xterm" or "xterm-color".
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005633 if (term == NULL || *term == NUL || STRNCMP(term, "xterm", 5) != 0)
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005634 {
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005635 if (t_colors >= 256)
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005636 // TODO: should we check this name is supported?
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005637 term = "xterm-256color";
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005638 else if (t_colors > 16)
5639 term = "xterm-color";
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005640 else
5641 term = "xterm";
5642 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005643 set_child_environment(
5644 (long)options->jo_term_rows,
5645 (long)options->jo_term_cols,
Bram Moolenaar493359e2018-06-12 20:25:52 +02005646 term,
5647 is_terminal);
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005648 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005649 else
5650# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02005651 set_default_child_environment(is_terminal);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005652
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005653 if (options->jo_env != NULL)
5654 {
5655 dict_T *dict = options->jo_env;
5656 hashitem_T *hi;
5657 int todo = (int)dict->dv_hashtab.ht_used;
5658
5659 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
5660 if (!HASHITEM_EMPTY(hi))
5661 {
5662 typval_T *item = &dict_lookup(hi)->di_tv;
5663
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +00005664 vim_setenv(hi->hi_key, tv_get_string(item));
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005665 --todo;
5666 }
5667 }
5668
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005669 if (use_null_for_in || use_null_for_out || use_null_for_err)
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005670 {
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005671 null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005672 if (null_fd < 0)
5673 {
5674 perror("opening /dev/null failed");
5675 _exit(OPEN_NULL_FAILED);
5676 }
5677 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005678
Bram Moolenaar223896d2017-08-02 22:33:28 +02005679 if (pty_slave_fd >= 0)
5680 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005681 // push stream discipline modules
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01005682 setup_slavepty(pty_slave_fd);
Bram Moolenaar223896d2017-08-02 22:33:28 +02005683# ifdef TIOCSCTTY
Bram Moolenaar0f873732019-12-05 20:28:46 +01005684 // Try to become controlling tty (probably doesn't work,
5685 // unless run by root)
Bram Moolenaar223896d2017-08-02 22:33:28 +02005686 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
5687# endif
5688 }
5689
Bram Moolenaar0f873732019-12-05 20:28:46 +01005690 // set up stdin for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005691 close(0);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005692 if (use_null_for_in && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005693 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005694 else if (fd_in[0] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005695 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005696 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005697 vim_ignored = dup(fd_in[0]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005698
Bram Moolenaar0f873732019-12-05 20:28:46 +01005699 // set up stderr for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005700 close(2);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005701 if (use_null_for_err && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005702 {
Bram Moolenaar42335f52018-09-13 15:33:43 +02005703 vim_ignored = dup(null_fd);
Bram Moolenaar4694a172016-04-21 14:05:23 +02005704 stderr_works = FALSE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005705 }
5706 else if (use_out_for_err)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005707 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005708 else if (fd_err[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005709 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005710 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005711 vim_ignored = dup(fd_err[1]);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005712
Bram Moolenaar0f873732019-12-05 20:28:46 +01005713 // set up stdout for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005714 close(1);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005715 if (use_null_for_out && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005716 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005717 else if (fd_out[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005718 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005719 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005720 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005721
5722 if (fd_in[0] >= 0)
5723 close(fd_in[0]);
5724 if (fd_in[1] >= 0)
5725 close(fd_in[1]);
5726 if (fd_out[0] >= 0)
5727 close(fd_out[0]);
5728 if (fd_out[1] >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005729 close(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005730 if (fd_err[0] >= 0)
5731 close(fd_err[0]);
5732 if (fd_err[1] >= 0)
5733 close(fd_err[1]);
5734 if (pty_master_fd >= 0)
5735 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005736 close(pty_master_fd); // not used in the child
5737 close(pty_slave_fd); // was duped above
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005738 }
Bram Moolenaarea83bf02016-05-08 09:40:51 +02005739
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005740 if (null_fd >= 0)
5741 close(null_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005742
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005743 if (options->jo_cwd != NULL && mch_chdir((char *)options->jo_cwd) != 0)
5744 _exit(EXEC_FAILED);
5745
Bram Moolenaar0f873732019-12-05 20:28:46 +01005746 // See above for type of argv.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005747 execvp(argv[0], argv);
5748
Bram Moolenaar4694a172016-04-21 14:05:23 +02005749 if (stderr_works)
5750 perror("executing job failed");
Bram Moolenaarfae42832017-08-01 22:24:26 +02005751# ifdef EXITFREE
Bram Moolenaar0f873732019-12-05 20:28:46 +01005752 // calling free_all_mem() here causes problems. Ignore valgrind
5753 // reporting possibly leaked memory.
Bram Moolenaarfae42832017-08-01 22:24:26 +02005754# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005755 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar835dc632016-02-07 14:27:38 +01005756 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005757
Bram Moolenaar0f873732019-12-05 20:28:46 +01005758 // parent
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005759 UNBLOCK_SIGNALS(&curset);
5760
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005761 job->jv_pid = pid;
5762 job->jv_status = JOB_STARTED;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005763 job->jv_channel = channel; // ch_refcount was set above
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005764
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005765 if (pty_master_fd >= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005766 close(pty_slave_fd); // not used in the parent
5767 // close child stdin, stdout and stderr
Bram Moolenaar819524702018-02-27 19:10:00 +01005768 if (fd_in[0] >= 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005769 close(fd_in[0]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005770 if (fd_out[1] >= 0)
Bram Moolenaare98d1212016-03-08 15:37:41 +01005771 close(fd_out[1]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005772 if (fd_err[1] >= 0)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005773 close(fd_err[1]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005774 if (channel != NULL)
5775 {
Bram Moolenaar652de232019-04-04 20:13:09 +02005776 int in_fd = INVALID_FD;
5777 int out_fd = INVALID_FD;
5778 int err_fd = INVALID_FD;
5779
5780 if (!(use_file_for_in || use_null_for_in))
5781 in_fd = fd_in[1] >= 0 ? fd_in[1] : pty_master_fd;
5782
5783 if (!(use_file_for_out || use_null_for_out))
5784 out_fd = fd_out[0] >= 0 ? fd_out[0] : pty_master_fd;
5785
5786 // When using pty_master_fd only set it for stdout, do not duplicate
5787 // it for stderr, it only needs to be read once.
5788 if (!(use_out_for_err || use_file_for_err || use_null_for_err))
5789 {
5790 if (fd_err[0] >= 0)
5791 err_fd = fd_err[0];
5792 else if (out_fd != pty_master_fd)
5793 err_fd = pty_master_fd;
5794 }
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005795
5796 channel_set_pipes(channel, in_fd, out_fd, err_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005797 channel_set_job(channel, job, options);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005798 }
Bram Moolenaar979e8c52017-08-01 15:08:07 +02005799 else
5800 {
5801 if (fd_in[1] >= 0)
5802 close(fd_in[1]);
5803 if (fd_out[0] >= 0)
5804 close(fd_out[0]);
5805 if (fd_err[0] >= 0)
5806 close(fd_err[0]);
5807 if (pty_master_fd >= 0)
5808 close(pty_master_fd);
5809 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005810
Bram Moolenaar0f873732019-12-05 20:28:46 +01005811 // success!
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005812 return;
5813
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005814failed:
Bram Moolenaarde279892016-03-11 22:19:44 +01005815 channel_unref(channel);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005816 if (fd_in[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005817 close(fd_in[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005818 if (fd_in[1] >= 0)
5819 close(fd_in[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005820 if (fd_out[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005821 close(fd_out[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005822 if (fd_out[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005823 close(fd_out[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005824 if (fd_err[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005825 close(fd_err[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005826 if (fd_err[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005827 close(fd_err[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005828 if (pty_master_fd >= 0)
5829 close(pty_master_fd);
5830 if (pty_slave_fd >= 0)
5831 close(pty_slave_fd);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005832}
5833
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005834 static char_u *
5835get_signal_name(int sig)
5836{
5837 int i;
5838 char_u numbuf[NUMBUFLEN];
5839
5840 if (sig == SIGKILL)
5841 return vim_strsave((char_u *)"kill");
5842
5843 for (i = 0; signal_info[i].sig != -1; i++)
5844 if (sig == signal_info[i].sig)
5845 return strlow_save((char_u *)signal_info[i].name);
5846
5847 vim_snprintf((char *)numbuf, NUMBUFLEN, "%d", sig);
5848 return vim_strsave(numbuf);
5849}
5850
Bram Moolenaar835dc632016-02-07 14:27:38 +01005851 char *
5852mch_job_status(job_T *job)
5853{
5854# ifdef HAVE_UNION_WAIT
5855 union wait status;
5856# else
5857 int status = -1;
5858# endif
5859 pid_t wait_pid = 0;
5860
5861# ifdef __NeXT__
5862 wait_pid = wait4(job->jv_pid, &status, WNOHANG, (struct rusage *)0);
5863# else
5864 wait_pid = waitpid(job->jv_pid, &status, WNOHANG);
5865# endif
5866 if (wait_pid == -1)
5867 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005868 // process must have exited
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005869 if (job->jv_status < JOB_ENDED)
5870 ch_log(job->jv_channel, "Job no longer exists: %s",
5871 strerror(errno));
Bram Moolenaar97792de2016-10-15 18:36:49 +02005872 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005873 }
5874 if (wait_pid == 0)
5875 return "run";
5876 if (WIFEXITED(status))
5877 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005878 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar835dc632016-02-07 14:27:38 +01005879 job->jv_exitval = WEXITSTATUS(status);
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005880 if (job->jv_status < JOB_ENDED)
5881 ch_log(job->jv_channel, "Job exited with %d", job->jv_exitval);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005882 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005883 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005884 if (WIFSIGNALED(status))
5885 {
5886 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005887 job->jv_termsig = get_signal_name(WTERMSIG(status));
5888 if (job->jv_status < JOB_ENDED && job->jv_termsig != NULL)
5889 ch_log(job->jv_channel, "Job terminated by signal \"%s\"",
5890 job->jv_termsig);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005891 goto return_dead;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005892 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01005893 return "run";
Bram Moolenaar97792de2016-10-15 18:36:49 +02005894
5895return_dead:
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005896 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005897 job->jv_status = JOB_ENDED;
Bram Moolenaar97792de2016-10-15 18:36:49 +02005898 return "dead";
5899}
5900
5901 job_T *
5902mch_detect_ended_job(job_T *job_list)
5903{
5904# ifdef HAVE_UNION_WAIT
5905 union wait status;
5906# else
5907 int status = -1;
5908# endif
5909 pid_t wait_pid = 0;
5910 job_T *job;
5911
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005912# ifndef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01005913 // Do not do this when waiting for a shell command to finish, we would get
5914 // the exit value here (and discard it), the exit value obtained there
5915 // would then be wrong.
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005916 if (dont_check_job_ended > 0)
5917 return NULL;
5918# endif
5919
Bram Moolenaar97792de2016-10-15 18:36:49 +02005920# ifdef __NeXT__
5921 wait_pid = wait4(-1, &status, WNOHANG, (struct rusage *)0);
5922# else
5923 wait_pid = waitpid(-1, &status, WNOHANG);
5924# endif
5925 if (wait_pid <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005926 // no process ended
Bram Moolenaar97792de2016-10-15 18:36:49 +02005927 return NULL;
5928 for (job = job_list; job != NULL; job = job->jv_next)
5929 {
5930 if (job->jv_pid == wait_pid)
5931 {
5932 if (WIFEXITED(status))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005933 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar97792de2016-10-15 18:36:49 +02005934 job->jv_exitval = WEXITSTATUS(status);
5935 else if (WIFSIGNALED(status))
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005936 {
Bram Moolenaar97792de2016-10-15 18:36:49 +02005937 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005938 job->jv_termsig = get_signal_name(WTERMSIG(status));
5939 }
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005940 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005941 {
5942 ch_log(job->jv_channel, "Job ended");
5943 job->jv_status = JOB_ENDED;
5944 }
5945 return job;
5946 }
5947 }
5948 return NULL;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005949}
5950
Bram Moolenaar3a117e12016-10-30 21:57:52 +01005951/*
5952 * Send a (deadly) signal to "job".
5953 * Return FAIL if "how" is not a valid name.
5954 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01005955 int
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005956mch_signal_job(job_T *job, char_u *how)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005957{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005958 int sig = -1;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005959
Bram Moolenaar923d9262016-02-25 20:56:01 +01005960 if (*how == NUL || STRCMP(how, "term") == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005961 sig = SIGTERM;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005962 else if (STRCMP(how, "hup") == 0)
5963 sig = SIGHUP;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005964 else if (STRCMP(how, "quit") == 0)
5965 sig = SIGQUIT;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005966 else if (STRCMP(how, "int") == 0)
5967 sig = SIGINT;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005968 else if (STRCMP(how, "kill") == 0)
5969 sig = SIGKILL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02005970#ifdef SIGWINCH
5971 else if (STRCMP(how, "winch") == 0)
5972 sig = SIGWINCH;
5973#endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005974 else if (isdigit(*how))
5975 sig = atoi((char *)how);
5976 else
5977 return FAIL;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005978
Bram Moolenaar76ab4fd2018-12-08 14:39:05 +01005979 // Never kill ourselves!
5980 if (job->jv_pid != 0)
5981 {
5982 // TODO: have an option to only kill the process, not the group?
5983 kill(-job->jv_pid, sig);
5984 kill(job->jv_pid, sig);
5985 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005986
Bram Moolenaar835dc632016-02-07 14:27:38 +01005987 return OK;
5988}
Bram Moolenaar76467df2016-02-12 19:30:26 +01005989
5990/*
5991 * Clear the data related to "job".
5992 */
5993 void
5994mch_clear_job(job_T *job)
5995{
Bram Moolenaar0f873732019-12-05 20:28:46 +01005996 // call waitpid because child process may become zombie
Bram Moolenaar76467df2016-02-12 19:30:26 +01005997# ifdef __NeXT__
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005998 (void)wait4(job->jv_pid, NULL, WNOHANG, (struct rusage *)0);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005999# else
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01006000 (void)waitpid(job->jv_pid, NULL, WNOHANG);
Bram Moolenaar76467df2016-02-12 19:30:26 +01006001# endif
6002}
Bram Moolenaar835dc632016-02-07 14:27:38 +01006003#endif
6004
Bram Moolenaar13ebb032017-08-26 22:02:51 +02006005#if defined(FEAT_TERMINAL) || defined(PROTO)
6006 int
6007mch_create_pty_channel(job_T *job, jobopt_T *options)
6008{
6009 int pty_master_fd = -1;
6010 int pty_slave_fd = -1;
6011 channel_T *channel;
6012
Bram Moolenaar59386482019-02-10 22:43:46 +01006013 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaard0342202020-06-29 22:40:42 +02006014 if (pty_master_fd < 0 || pty_slave_fd < 0)
6015 return FAIL;
Bram Moolenaar13ebb032017-08-26 22:02:51 +02006016 close(pty_slave_fd);
6017
6018 channel = add_channel();
6019 if (channel == NULL)
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02006020 {
6021 close(pty_master_fd);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02006022 return FAIL;
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02006023 }
Bram Moolenaarf3360612017-10-01 16:21:31 +02006024 if (job->jv_tty_out != NULL)
6025 ch_log(channel, "using pty %s on fd %d",
6026 job->jv_tty_out, pty_master_fd);
Bram Moolenaar0f873732019-12-05 20:28:46 +01006027 job->jv_channel = channel; // ch_refcount was set by add_channel()
Bram Moolenaar13ebb032017-08-26 22:02:51 +02006028 channel->ch_keep_open = TRUE;
6029
Bram Moolenaar0f873732019-12-05 20:28:46 +01006030 // Only set the pty_master_fd for stdout, do not duplicate it for stderr,
6031 // it only needs to be read once.
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02006032 channel_set_pipes(channel, pty_master_fd, pty_master_fd, INVALID_FD);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02006033 channel_set_job(channel, job, options);
6034 return OK;
6035}
6036#endif
6037
Bram Moolenaar071d4272004-06-13 20:20:40 +00006038/*
6039 * Check for CTRL-C typed by reading all available characters.
6040 * In cooked mode we should get SIGINT, no need to check.
6041 */
6042 void
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02006043mch_breakcheck(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006044{
Bram Moolenaar26e86442020-05-17 14:06:16 +02006045 if ((mch_cur_tmode == TMODE_RAW || force)
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02006046 && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006047 fill_input_buf(FALSE);
6048}
6049
6050/*
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006051 * Wait "msec" msec until a character is available from the mouse, keyboard,
6052 * from inbuf[].
6053 * "msec" == -1 will block forever.
6054 * Invokes timer callbacks when needed.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006055 * When "ignore_input" is TRUE even check for pending input when input is
6056 * already available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006057 * "interrupted" (if not NULL) is set to TRUE when no character is available
6058 * but something else needs to be done.
Bram Moolenaar40b1b542016-04-20 20:18:23 +02006059 * Returns TRUE when a character is available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006060 * When a GUI is being used, this will never get called -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00006061 */
6062 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006063WaitForChar(long msec, int *interrupted, int ignore_input)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006064{
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006065#ifdef FEAT_TIMERS
Bram Moolenaarc9e649a2017-12-18 18:14:47 +01006066 return ui_wait_for_chars_or_timer(
6067 msec, WaitForCharOrMouse, interrupted, ignore_input) == OK;
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006068#else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006069 return WaitForCharOrMouse(msec, interrupted, ignore_input);
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006070#endif
6071}
6072
6073/*
6074 * Wait "msec" msec until a character is available from the mouse or keyboard
6075 * or from inbuf[].
6076 * "msec" == -1 will block forever.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006077 * for "ignore_input" see WaitForCharOr().
Bram Moolenaarcda77642016-06-04 13:32:35 +02006078 * "interrupted" (if not NULL) is set to TRUE when no character is available
6079 * but something else needs to be done.
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006080 * When a GUI is being used, this will never get called -- webb
6081 */
6082 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006083WaitForCharOrMouse(long msec, int *interrupted, int ignore_input)
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006084{
Bram Moolenaar071d4272004-06-13 20:20:40 +00006085#ifdef FEAT_MOUSE_GPM
6086 int gpm_process_wanted;
6087#endif
6088#ifdef FEAT_XCLIPBOARD
6089 int rest;
6090#endif
6091 int avail;
6092
Bram Moolenaar0f873732019-12-05 20:28:46 +01006093 if (!ignore_input && input_available()) // something in inbuf[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00006094 return 1;
6095
6096#if defined(FEAT_MOUSE_DEC)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006097 // May need to query the mouse position.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006098 if (WantQueryMouse)
6099 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00006100 WantQueryMouse = FALSE;
Bram Moolenaar92fd5992019-05-02 23:00:22 +02006101 if (!no_query_mouse_for_testing)
Bram Moolenaar424bcae2022-01-31 14:59:41 +00006102 mch_write((char_u *)"\033[1'|", 5);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006103 }
6104#endif
6105
6106 /*
6107 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
6108 * events. This is a bit complicated, because they might both be defined.
6109 */
6110#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
6111# ifdef FEAT_XCLIPBOARD
6112 rest = 0;
6113 if (do_xterm_trace())
6114 rest = msec;
6115# endif
6116 do
6117 {
6118# ifdef FEAT_XCLIPBOARD
6119 if (rest != 0)
6120 {
6121 msec = XT_TRACE_DELAY;
6122 if (rest >= 0 && rest < XT_TRACE_DELAY)
6123 msec = rest;
6124 if (rest >= 0)
6125 rest -= msec;
6126 }
6127# endif
Bram Moolenaar28e67e02019-08-15 23:05:49 +02006128# ifdef FEAT_SOUND_CANBERRA
6129 // Invoke any pending sound callbacks.
6130 if (has_sound_callback_in_queue())
6131 invoke_sound_callback();
6132# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006133# ifdef FEAT_MOUSE_GPM
6134 gpm_process_wanted = 0;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006135 avail = RealWaitForChar(read_cmd_fd, msec,
Bram Moolenaarcda77642016-06-04 13:32:35 +02006136 &gpm_process_wanted, interrupted);
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006137 if (!avail && !gpm_process_wanted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006138# else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006139 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006140 if (!avail)
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006141# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006142 {
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006143 if (!ignore_input && input_available())
Bram Moolenaar071d4272004-06-13 20:20:40 +00006144 return 1;
6145# ifdef FEAT_XCLIPBOARD
6146 if (rest == 0 || !do_xterm_trace())
6147# endif
6148 break;
6149 }
6150 }
6151 while (FALSE
6152# ifdef FEAT_MOUSE_GPM
6153 || (gpm_process_wanted && mch_gpm_process() == 0)
6154# endif
6155# ifdef FEAT_XCLIPBOARD
6156 || (!avail && rest != 0)
6157# endif
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006158 )
6159 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006160
6161#else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006162 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006163#endif
6164 return avail;
6165}
6166
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01006167#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00006168/*
6169 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006170 * "msec" == 0 will check for characters once.
6171 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006172 * When a GUI is being used, this will not be used for input -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00006173 * Or when a Linux GPM mouse event is waiting.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006174 * Or when a clientserver message is on the queue.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006175 * "interrupted" (if not NULL) is set to TRUE when no character is available
6176 * but something else needs to be done.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006177 */
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006178 static int
Bram Moolenaarcda77642016-06-04 13:32:35 +02006179RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006180{
6181 int ret;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006182 int result;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006183#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006184 static int busy = FALSE;
6185
Bram Moolenaar0f873732019-12-05 20:28:46 +01006186 // May retry getting characters after an event was handled.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006187# define MAY_LOOP
6188
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006189# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006190 // Remember at what time we started, so that we know how much longer we
6191 // should wait after being interrupted.
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01006192 long start_msec = msec;
6193 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006194
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02006195 if (msec > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006196 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006197# endif
6198
Bram Moolenaar0f873732019-12-05 20:28:46 +01006199 // Handle being called recursively. This may happen for the session
6200 // manager stuff, it may save the file, which does a breakcheck.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006201 if (busy)
6202 return 0;
6203#endif
6204
6205#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00006206 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006207#endif
6208 {
6209#ifdef MAY_LOOP
Bram Moolenaar0f873732019-12-05 20:28:46 +01006210 int finished = TRUE; // default is to 'loop' just once
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006211# ifdef FEAT_MZSCHEME
6212 int mzquantum_used = FALSE;
6213# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006214#endif
6215#ifndef HAVE_SELECT
Bram Moolenaar0f873732019-12-05 20:28:46 +01006216 // each channel may use in, out and err
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006217 struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006218 int nfd;
6219# ifdef FEAT_XCLIPBOARD
6220 int xterm_idx = -1;
6221# endif
6222# ifdef FEAT_MOUSE_GPM
6223 int gpm_idx = -1;
6224# endif
6225# ifdef USE_XSMP
6226 int xsmp_idx = -1;
6227# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006228 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006229
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006230# ifdef FEAT_MZSCHEME
6231 mzvim_check_threads();
6232 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6233 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006234 towait = (int)p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006235 mzquantum_used = TRUE;
6236 }
6237# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006238 fds[0].fd = fd;
6239 fds[0].events = POLLIN;
6240 nfd = 1;
6241
Bram Moolenaar071d4272004-06-13 20:20:40 +00006242# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006243 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006244 if (xterm_Shell != (Widget)0)
6245 {
6246 xterm_idx = nfd;
6247 fds[nfd].fd = ConnectionNumber(xterm_dpy);
6248 fds[nfd].events = POLLIN;
6249 nfd++;
6250 }
6251# endif
6252# ifdef FEAT_MOUSE_GPM
6253 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6254 {
6255 gpm_idx = nfd;
6256 fds[nfd].fd = gpm_fd;
6257 fds[nfd].events = POLLIN;
6258 nfd++;
6259 }
6260# endif
6261# ifdef USE_XSMP
6262 if (xsmp_icefd != -1)
6263 {
6264 xsmp_idx = nfd;
6265 fds[nfd].fd = xsmp_icefd;
6266 fds[nfd].events = POLLIN;
6267 nfd++;
6268 }
6269# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006270#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006271 nfd = channel_poll_setup(nfd, &fds, &towait);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006272#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006273 if (interrupted != NULL)
6274 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006275
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006276 ret = poll(fds, nfd, towait);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006277
6278 result = ret > 0 && (fds[0].revents & POLLIN);
Bram Moolenaarcda77642016-06-04 13:32:35 +02006279 if (result == 0 && interrupted != NULL && ret > 0)
6280 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006281
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006282# ifdef FEAT_MZSCHEME
6283 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006284 // MzThreads scheduling is required and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006285 finished = FALSE;
6286# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006287
Bram Moolenaar071d4272004-06-13 20:20:40 +00006288# ifdef FEAT_XCLIPBOARD
6289 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
6290 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006291 xterm_update(); // Maybe we should hand out clipboard
Bram Moolenaar071d4272004-06-13 20:20:40 +00006292 if (--ret == 0 && !input_available())
Bram Moolenaar0f873732019-12-05 20:28:46 +01006293 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006294 finished = FALSE;
6295 }
6296# endif
6297# ifdef FEAT_MOUSE_GPM
6298 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006299 *check_for_gpm = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006300# endif
6301# ifdef USE_XSMP
6302 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
6303 {
6304 if (fds[xsmp_idx].revents & POLLIN)
6305 {
6306 busy = TRUE;
6307 xsmp_handle_requests();
6308 busy = FALSE;
6309 }
6310 else if (fds[xsmp_idx].revents & POLLHUP)
6311 {
6312 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006313 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006314 xsmp_close();
6315 }
6316 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006317 finished = FALSE; // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006318 }
6319# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006320#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006321 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006322 if (ret >= 0)
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006323 channel_poll_check(ret, &fds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006324#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006325
Bram Moolenaar0f873732019-12-05 20:28:46 +01006326#else // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006327
6328 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006329 struct timeval *tvp;
Bram Moolenaar61fb8d82018-11-12 21:45:08 +01006330 // These are static because they can take 8 Kbyte each and cause the
6331 // signal stack to run out with -O3.
6332 static fd_set rfds, wfds, efds;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006333 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006334 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006335
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006336# ifdef FEAT_MZSCHEME
6337 mzvim_check_threads();
6338 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6339 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006340 towait = p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006341 mzquantum_used = TRUE;
6342 }
6343# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006344
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006345 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006346 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006347 tv.tv_sec = towait / 1000;
6348 tv.tv_usec = (towait % 1000) * (1000000/1000);
6349 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006350 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006351 else
6352 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006353
6354 /*
6355 * Select on ready for reading and exceptional condition (end of file).
6356 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006357select_eintr:
6358 FD_ZERO(&rfds);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006359 FD_ZERO(&wfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006360 FD_ZERO(&efds);
6361 FD_SET(fd, &rfds);
K.Takatab247e062022-02-07 10:45:23 +00006362# ifndef __QNX__
Bram Moolenaar0f873732019-12-05 20:28:46 +01006363 // For QNX select() always returns 1 if this is set. Why?
Bram Moolenaar071d4272004-06-13 20:20:40 +00006364 FD_SET(fd, &efds);
6365# endif
6366 maxfd = fd;
6367
Bram Moolenaar071d4272004-06-13 20:20:40 +00006368# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006369 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006370 if (xterm_Shell != (Widget)0)
6371 {
6372 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
6373 if (maxfd < ConnectionNumber(xterm_dpy))
6374 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006375
Bram Moolenaar0f873732019-12-05 20:28:46 +01006376 // An event may have already been read but not handled. In
6377 // particularly, XFlush may cause this.
Bram Moolenaardd82d692012-08-15 17:26:57 +02006378 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006379 }
6380# endif
6381# ifdef FEAT_MOUSE_GPM
6382 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6383 {
6384 FD_SET(gpm_fd, &rfds);
6385 FD_SET(gpm_fd, &efds);
6386 if (maxfd < gpm_fd)
6387 maxfd = gpm_fd;
6388 }
6389# endif
6390# ifdef USE_XSMP
6391 if (xsmp_icefd != -1)
6392 {
6393 FD_SET(xsmp_icefd, &rfds);
6394 FD_SET(xsmp_icefd, &efds);
6395 if (maxfd < xsmp_icefd)
6396 maxfd = xsmp_icefd;
6397 }
6398# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006399# ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006400 maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006401# endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006402 if (interrupted != NULL)
6403 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006404
Bram Moolenaar643b6142018-09-12 20:29:09 +02006405 ret = select(maxfd + 1, SELECT_TYPE_ARG234 &rfds,
6406 SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 &efds, tvp);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006407 result = ret > 0 && FD_ISSET(fd, &rfds);
6408 if (result)
6409 --ret;
Bram Moolenaarcda77642016-06-04 13:32:35 +02006410 else if (interrupted != NULL && ret > 0)
6411 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006412
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006413# ifdef EINTR
6414 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006415 {
dbivolaruab16ad32021-12-29 19:41:47 +00006416 // Check whether the EINTR is caused by SIGTSTP
6417 if (got_tstp && !in_mch_suspend)
6418 {
6419 exarg_T ea;
dbivolaru79a6e252022-01-23 16:41:14 +00006420
dbivolaruab16ad32021-12-29 19:41:47 +00006421 ea.forceit = TRUE;
6422 ex_stop(&ea);
6423 got_tstp = FALSE;
6424 }
6425
Bram Moolenaar0f873732019-12-05 20:28:46 +01006426 // Check whether window has been resized, EINTR may be caused by
6427 // SIGWINCH.
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006428 if (do_resize)
6429 handle_resize();
6430
Bram Moolenaar0f873732019-12-05 20:28:46 +01006431 // Interrupted by a signal, need to try again. We ignore msec
6432 // here, because we do want to check even after a timeout if
6433 // characters are available. Needed for reading output of an
6434 // external command after the process has finished.
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006435 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006436 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006437# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00006438# ifdef __TANDEM
6439 if (ret == -1 && errno == ENOTSUP)
6440 {
6441 FD_ZERO(&rfds);
6442 FD_ZERO(&efds);
6443 ret = 0;
6444 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006445# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006446# ifdef FEAT_MZSCHEME
6447 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006448 // loop if MzThreads must be scheduled and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006449 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006450# endif
6451
Bram Moolenaar071d4272004-06-13 20:20:40 +00006452# ifdef FEAT_XCLIPBOARD
6453 if (ret > 0 && xterm_Shell != (Widget)0
6454 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
6455 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006456 xterm_update(); // Maybe we should hand out clipboard
6457 // continue looping when we only got the X event and the input
6458 // buffer is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00006459 if (--ret == 0 && !input_available())
6460 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006461 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006462 finished = FALSE;
6463 }
6464 }
6465# endif
6466# ifdef FEAT_MOUSE_GPM
Bram Moolenaar33fc4a62022-02-23 18:07:38 +00006467 if (ret > 0 && check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006468 {
6469 if (FD_ISSET(gpm_fd, &efds))
6470 gpm_close();
6471 else if (FD_ISSET(gpm_fd, &rfds))
6472 *check_for_gpm = 1;
6473 }
6474# endif
6475# ifdef USE_XSMP
6476 if (ret > 0 && xsmp_icefd != -1)
6477 {
6478 if (FD_ISSET(xsmp_icefd, &efds))
6479 {
6480 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006481 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006482 xsmp_close();
6483 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006484 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006485 }
6486 else if (FD_ISSET(xsmp_icefd, &rfds))
6487 {
6488 busy = TRUE;
6489 xsmp_handle_requests();
6490 busy = FALSE;
6491 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006492 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006493 }
6494 }
6495# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006496#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar0f873732019-12-05 20:28:46 +01006497 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006498 if (ret >= 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006499 ret = channel_select_check(ret, &rfds, &wfds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006500#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006501
Bram Moolenaar0f873732019-12-05 20:28:46 +01006502#endif // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006503
6504#ifdef MAY_LOOP
6505 if (finished || msec == 0)
6506 break;
6507
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006508# ifdef FEAT_CLIENTSERVER
6509 if (server_waiting())
6510 break;
6511# endif
6512
Bram Moolenaar0f873732019-12-05 20:28:46 +01006513 // We're going to loop around again, find out for how long
Bram Moolenaar071d4272004-06-13 20:20:40 +00006514 if (msec > 0)
6515 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006516# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006517 // Compute remaining wait time.
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006518 msec = start_msec - ELAPSED_FUNC(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006519# else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006520 // Guess we got interrupted halfway.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006521 msec = msec / 2;
6522# endif
6523 if (msec <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006524 break; // waited long enough
Bram Moolenaar071d4272004-06-13 20:20:40 +00006525 }
6526#endif
6527 }
6528
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006529 return result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006530}
6531
Bram Moolenaar071d4272004-06-13 20:20:40 +00006532/*
Bram Moolenaar02743632005-07-25 20:42:36 +00006533 * Expand a path into all matching files and/or directories. Handles "*",
6534 * "?", "[a-z]", "**", etc.
6535 * "path" has backslashes before chars that are not to be expanded.
6536 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006537 */
6538 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006539mch_expandpath(
6540 garray_T *gap,
6541 char_u *path,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006542 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006543{
Bram Moolenaar02743632005-07-25 20:42:36 +00006544 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006545}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006546
6547/*
6548 * mch_expand_wildcards() - this code does wild-card pattern matching using
6549 * the shell
6550 *
6551 * return OK for success, FAIL for error (you may lose some memory) and put
6552 * an error message in *file.
6553 *
6554 * num_pat is number of input patterns
6555 * pat is array of pointers to input patterns
6556 * num_file is pointer to number of matched file names
6557 * file is pointer to array of pointers to matched file names
6558 */
6559
6560#ifndef SEEK_SET
6561# define SEEK_SET 0
6562#endif
6563#ifndef SEEK_END
6564# define SEEK_END 2
6565#endif
6566
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006567#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00006568
Bram Moolenaar071d4272004-06-13 20:20:40 +00006569 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006570mch_expand_wildcards(
6571 int num_pat,
6572 char_u **pat,
6573 int *num_file,
6574 char_u ***file,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006575 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006576{
6577 int i;
6578 size_t len;
Bram Moolenaar85325f82017-03-30 21:18:45 +02006579 long llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006580 char_u *p;
6581 int dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006582
Bram Moolenaarc7247912008-01-13 12:54:11 +00006583 /*
6584 * This is the non-OS/2 implementation (really Unix).
6585 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006586 int j;
6587 char_u *tempname;
6588 char_u *command;
6589 FILE *fd;
6590 char_u *buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006591#define STYLE_ECHO 0 // use "echo", the default
6592#define STYLE_GLOB 1 // use "glob", for csh
6593#define STYLE_VIMGLOB 2 // use "vimglob", for Posix sh
6594#define STYLE_PRINT 3 // use "print -N", for zsh
6595#define STYLE_BT 4 // `cmd` expansion, execute the pattern
6596 // directly
Bram Moolenaar071d4272004-06-13 20:20:40 +00006597 int shell_style = STYLE_ECHO;
6598 int check_spaces;
6599 static int did_find_nul = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006600 int ampersand = FALSE;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006601 // vimglob() function to define for Posix shell
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006602 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006603
Bram Moolenaar0f873732019-12-05 20:28:46 +01006604 *num_file = 0; // default: no files found
Bram Moolenaar071d4272004-06-13 20:20:40 +00006605 *file = NULL;
6606
6607 /*
6608 * If there are no wildcards, just copy the names to allocated memory.
6609 * Saves a lot of time, because we don't have to start a new shell.
6610 */
6611 if (!have_wildcard(num_pat, pat))
6612 return save_patterns(num_pat, pat, num_file, file);
6613
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006614# ifdef HAVE_SANDBOX
Bram Moolenaar0f873732019-12-05 20:28:46 +01006615 // Don't allow any shell command in the sandbox.
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006616 if (sandbox != 0 && check_secure())
6617 return FAIL;
6618# endif
6619
Bram Moolenaar071d4272004-06-13 20:20:40 +00006620 /*
6621 * Don't allow the use of backticks in secure and restricted mode.
6622 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006623 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006624 for (i = 0; i < num_pat; ++i)
6625 if (vim_strchr(pat[i], '`') != NULL
6626 && (check_restricted() || check_secure()))
6627 return FAIL;
6628
6629 /*
6630 * get a name for the temp file
6631 */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02006632 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006633 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00006634 emsg(_(e_cant_get_temp_file_name));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006635 return FAIL;
6636 }
6637
6638 /*
6639 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00006640 * file.
6641 * STYLE_BT: NL separated
6642 * If expanding `cmd` execute it directly.
6643 * STYLE_GLOB: NUL separated
6644 * If we use *csh, "glob" will work better than "echo".
6645 * STYLE_PRINT: NL or NUL separated
6646 * If we use *zsh, "print -N" will work better than "glob".
6647 * STYLE_VIMGLOB: NL separated
6648 * If we use *sh*, we define "vimglob()".
6649 * STYLE_ECHO: space separated.
6650 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006651 */
6652 if (num_pat == 1 && *pat[0] == '`'
6653 && (len = STRLEN(pat[0])) > 2
6654 && *(pat[0] + len - 1) == '`')
6655 shell_style = STYLE_BT;
6656 else if ((len = STRLEN(p_sh)) >= 3)
6657 {
6658 if (STRCMP(p_sh + len - 3, "csh") == 0)
6659 shell_style = STYLE_GLOB;
6660 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
6661 shell_style = STYLE_PRINT;
6662 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006663 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
6664 "sh") != NULL)
6665 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006666
Bram Moolenaar0f873732019-12-05 20:28:46 +01006667 // Compute the length of the command. We need 2 extra bytes: for the
6668 // optional '&' and for the NUL.
6669 // Worst case: "unset nonomatch; print -N >" plus two is 29
Bram Moolenaar071d4272004-06-13 20:20:40 +00006670 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006671 if (shell_style == STYLE_VIMGLOB)
6672 len += STRLEN(sh_vimglob_func);
6673
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006674 for (i = 0; i < num_pat; ++i)
6675 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006676 // Count the length of the patterns in the same way as they are put in
6677 // "command" below.
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006678#ifdef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01006679 len += STRLEN(pat[i]) + 3; // add space and two quotes
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006680#else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006681 ++len; // add space
Bram Moolenaar316059c2006-01-14 21:18:42 +00006682 for (j = 0; pat[i][j] != NUL; ++j)
6683 {
6684 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006685 ++len; // may add a backslash
Bram Moolenaar316059c2006-01-14 21:18:42 +00006686 ++len;
6687 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006688#endif
6689 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006690 command = alloc(len);
6691 if (command == NULL)
6692 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006693 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006694 vim_free(tempname);
6695 return FAIL;
6696 }
6697
6698 /*
6699 * Build the shell command:
6700 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
6701 * recognizes this).
6702 * - Add the shell command to print the expanded names.
6703 * - Add the temp file name.
6704 * - Add the file name patterns.
6705 */
6706 if (shell_style == STYLE_BT)
6707 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006708 // change `command; command& ` to (command; command )
Bram Moolenaar316059c2006-01-14 21:18:42 +00006709 STRCPY(command, "(");
Bram Moolenaar0f873732019-12-05 20:28:46 +01006710 STRCAT(command, pat[0] + 1); // exclude first backtick
Bram Moolenaar071d4272004-06-13 20:20:40 +00006711 p = command + STRLEN(command) - 1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006712 *p-- = ')'; // remove last backtick
Bram Moolenaar1c465442017-03-12 20:10:05 +01006713 while (p > command && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006714 --p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006715 if (*p == '&') // remove trailing '&'
Bram Moolenaar071d4272004-06-13 20:20:40 +00006716 {
Bram Moolenaarbdace832019-03-02 10:13:42 +01006717 ampersand = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006718 *p = ' ';
6719 }
6720 STRCAT(command, ">");
6721 }
6722 else
6723 {
Christian Brabandt8b8d8292021-11-19 12:37:36 +00006724 STRCPY(command, "");
6725 if (shell_style == STYLE_GLOB)
6726 {
6727 // Assume the nonomatch option is valid only for csh like shells,
6728 // otherwise, this may set the positional parameters for the shell,
6729 // e.g. "$*".
6730 if (flags & EW_NOTFOUND)
6731 STRCAT(command, "set nonomatch; ");
6732 else
6733 STRCAT(command, "unset nonomatch; ");
6734 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006735 if (shell_style == STYLE_GLOB)
6736 STRCAT(command, "glob >");
6737 else if (shell_style == STYLE_PRINT)
6738 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00006739 else if (shell_style == STYLE_VIMGLOB)
6740 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006741 else
6742 STRCAT(command, "echo >");
6743 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006744
Bram Moolenaar071d4272004-06-13 20:20:40 +00006745 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00006746
Bram Moolenaar071d4272004-06-13 20:20:40 +00006747 if (shell_style != STYLE_BT)
6748 for (i = 0; i < num_pat; ++i)
6749 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006750 // When using system() always add extra quotes, because the shell
6751 // is started twice. Otherwise put a backslash before special
6752 // characters, except inside ``.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006753#ifdef USE_SYSTEM
6754 STRCAT(command, " \"");
6755 STRCAT(command, pat[i]);
6756 STRCAT(command, "\"");
6757#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00006758 int intick = FALSE;
6759
Bram Moolenaar071d4272004-06-13 20:20:40 +00006760 p = command + STRLEN(command);
6761 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00006762 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00006763 {
6764 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00006765 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006766 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
6767 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006768 // Remove a backslash, take char literally. But keep
6769 // backslash inside backticks, before a special character
6770 // and before a backtick.
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006771 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00006772 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
6773 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006774 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006775 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006776 }
Bram Moolenaare4df1642014-08-29 12:58:44 +02006777 else if (!intick
6778 && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
6779 && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006780 // Put a backslash before a special character, but not
6781 // when inside ``. And not for $var when EW_KEEPDOLLAR is
6782 // set.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006783 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006784
Bram Moolenaar0f873732019-12-05 20:28:46 +01006785 // Copy one character.
Bram Moolenaar280f1262006-01-30 00:14:18 +00006786 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00006787 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006788 *p = NUL;
6789#endif
6790 }
6791 if (flags & EW_SILENT)
6792 show_shell_mess = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006793 if (ampersand)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006794 STRCAT(command, "&"); // put the '&' after the redirection
Bram Moolenaar071d4272004-06-13 20:20:40 +00006795
6796 /*
6797 * Using zsh -G: If a pattern has no matches, it is just deleted from
6798 * the argument list, otherwise zsh gives an error message and doesn't
6799 * expand any other pattern.
6800 */
6801 if (shell_style == STYLE_PRINT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006802 extra_shell_arg = (char_u *)"-G"; // Use zsh NULL_GLOB option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006803
6804 /*
6805 * If we use -f then shell variables set in .cshrc won't get expanded.
6806 * vi can do it, so we will too, but it is only necessary if there is a "$"
6807 * in one of the patterns, otherwise we can still use the fast option.
6808 */
6809 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
Bram Moolenaar0f873732019-12-05 20:28:46 +01006810 extra_shell_arg = (char_u *)"-f"; // Use csh fast option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006811
6812 /*
6813 * execute the shell command
6814 */
6815 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
6816
Bram Moolenaar0f873732019-12-05 20:28:46 +01006817 // When running in the background, give it some time to create the temp
6818 // file, but don't wait for it to finish.
Bram Moolenaarbdace832019-03-02 10:13:42 +01006819 if (ampersand)
Bram Moolenaar0981c872020-08-23 14:28:37 +02006820 mch_delay(10L, MCH_DELAY_IGNOREINPUT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006821
Bram Moolenaar0f873732019-12-05 20:28:46 +01006822 extra_shell_arg = NULL; // cleanup
Bram Moolenaar071d4272004-06-13 20:20:40 +00006823 show_shell_mess = TRUE;
6824 vim_free(command);
6825
Bram Moolenaar0f873732019-12-05 20:28:46 +01006826 if (i != 0) // mch_call_shell() failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00006827 {
6828 mch_remove(tempname);
6829 vim_free(tempname);
6830 /*
6831 * With interactive completion, the error message is not printed.
6832 * However with USE_SYSTEM, I don't know how to turn off error messages
6833 * from the shell, so screen may still get messed up -- webb.
6834 */
6835#ifndef USE_SYSTEM
6836 if (!(flags & EW_SILENT))
6837#endif
6838 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006839 redraw_later_clear(); // probably messed up screen
6840 msg_putchar('\n'); // clear bottom line quickly
6841 cmdline_row = Rows - 1; // continue on last line
Bram Moolenaar071d4272004-06-13 20:20:40 +00006842#ifdef USE_SYSTEM
6843 if (!(flags & EW_SILENT))
6844#endif
6845 {
Bram Moolenaar40bcec12021-12-05 22:19:27 +00006846 msg(_(e_cannot_expand_wildcards));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006847 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006848 }
6849 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006850 // If a `cmd` expansion failed, don't list `cmd` as a match, even when
6851 // EW_NOTFOUND is given
Bram Moolenaar071d4272004-06-13 20:20:40 +00006852 if (shell_style == STYLE_BT)
6853 return FAIL;
6854 goto notfound;
6855 }
6856
6857 /*
6858 * read the names from the file into memory
6859 */
6860 fd = fopen((char *)tempname, READBIN);
6861 if (fd == NULL)
6862 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006863 // Something went wrong, perhaps a file name with a special char.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006864 if (!(flags & EW_SILENT))
6865 {
Bram Moolenaar40bcec12021-12-05 22:19:27 +00006866 msg(_(e_cannot_expand_wildcards));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006867 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006868 }
6869 vim_free(tempname);
6870 goto notfound;
6871 }
6872 fseek(fd, 0L, SEEK_END);
Bram Moolenaar0f873732019-12-05 20:28:46 +01006873 llen = ftell(fd); // get size of temp file
Bram Moolenaar071d4272004-06-13 20:20:40 +00006874 fseek(fd, 0L, SEEK_SET);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006875 if (llen < 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006876 // just in case ftell() would fail
Bram Moolenaar85325f82017-03-30 21:18:45 +02006877 buffer = NULL;
6878 else
6879 buffer = alloc(llen + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006880 if (buffer == NULL)
6881 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006882 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006883 mch_remove(tempname);
6884 vim_free(tempname);
6885 fclose(fd);
6886 return FAIL;
6887 }
Bram Moolenaar85325f82017-03-30 21:18:45 +02006888 len = llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006889 i = fread((char *)buffer, 1, len, fd);
6890 fclose(fd);
6891 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00006892 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006893 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006894 // unexpected read error
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00006895 semsg(_(e_cant_read_file_str), tempname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006896 vim_free(tempname);
6897 vim_free(buffer);
6898 return FAIL;
6899 }
6900 vim_free(tempname);
6901
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006902# ifdef __CYGWIN__
Bram Moolenaar0f873732019-12-05 20:28:46 +01006903 // Translate <CR><NL> into <NL>. Caution, buffer may contain NUL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006904 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02006905 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006906 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
6907 *p++ = buffer[i];
6908 len = p - buffer;
6909# endif
6910
6911
Bram Moolenaar0f873732019-12-05 20:28:46 +01006912 // file names are separated with Space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006913 if (shell_style == STYLE_ECHO)
6914 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006915 buffer[len] = '\n'; // make sure the buffer ends in NL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006916 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006917 for (i = 0; *p != '\n'; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006918 {
6919 while (*p != ' ' && *p != '\n')
6920 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006921 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006922 }
6923 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006924 // file names are separated with NL
Bram Moolenaarc7247912008-01-13 12:54:11 +00006925 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006926 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006927 buffer[len] = NUL; // make sure the buffer ends in NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006928 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006929 for (i = 0; *p != NUL; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006930 {
6931 while (*p != '\n' && *p != NUL)
6932 ++p;
6933 if (*p != NUL)
6934 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006935 p = skipwhite(p); // skip leading white space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006936 }
6937 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006938 // file names are separated with NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006939 else
6940 {
6941 /*
6942 * Some versions of zsh use spaces instead of NULs to separate
6943 * results. Only do this when there is no NUL before the end of the
6944 * buffer, otherwise we would never be able to use file names with
6945 * embedded spaces when zsh does use NULs.
6946 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6947 * don't check for spaces again.
6948 */
6949 check_spaces = FALSE;
6950 if (shell_style == STYLE_PRINT && !did_find_nul)
6951 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006952 // If there is a NUL, set did_find_nul, else set check_spaces
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006953 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006954 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006955 did_find_nul = TRUE;
6956 else
6957 check_spaces = TRUE;
6958 }
6959
6960 /*
6961 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6962 * already is one, for STYLE_GLOB it needs to be added.
6963 */
6964 if (len && buffer[len - 1] == NUL)
6965 --len;
6966 else
6967 buffer[len] = NUL;
6968 i = 0;
6969 for (p = buffer; p < buffer + len; ++p)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006970 if (*p == NUL || (*p == ' ' && check_spaces)) // count entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006971 {
6972 ++i;
6973 *p = NUL;
6974 }
6975 if (len)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006976 ++i; // count last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006977 }
6978 if (i == 0)
6979 {
6980 /*
6981 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6982 * /bin/sh will happily expand it to nothing rather than returning an
6983 * error; and hey, it's good to check anyway -- webb.
6984 */
6985 vim_free(buffer);
6986 goto notfound;
6987 }
6988 *num_file = i;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006989 *file = ALLOC_MULT(char_u *, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006990 if (*file == NULL)
6991 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006992 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006993 vim_free(buffer);
6994 return FAIL;
6995 }
6996
6997 /*
6998 * Isolate the individual file names.
6999 */
7000 p = buffer;
7001 for (i = 0; i < *num_file; ++i)
7002 {
7003 (*file)[i] = p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007004 // Space or NL separates
Bram Moolenaarc7247912008-01-13 12:54:11 +00007005 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
7006 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007007 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00007008 while (!(shell_style == STYLE_ECHO && *p == ' ')
7009 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007010 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007011 if (p == buffer + len) // last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00007012 *p = NUL;
7013 else
7014 {
7015 *p++ = NUL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007016 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00007017 }
7018 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007019 else // NUL separates
Bram Moolenaar071d4272004-06-13 20:20:40 +00007020 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007021 while (*p && p < buffer + len) // skip entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00007022 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007023 ++p; // skip NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007024 }
7025 }
7026
7027 /*
7028 * Move the file names to allocated memory.
7029 */
7030 for (j = 0, i = 0; i < *num_file; ++i)
7031 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007032 // Require the files to exist. Helps when using /bin/sh
Bram Moolenaar071d4272004-06-13 20:20:40 +00007033 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
7034 continue;
7035
Bram Moolenaar0f873732019-12-05 20:28:46 +01007036 // check if this entry should be included
Bram Moolenaar071d4272004-06-13 20:20:40 +00007037 dir = (mch_isdir((*file)[i]));
7038 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
7039 continue;
7040
Bram Moolenaar0f873732019-12-05 20:28:46 +01007041 // Skip files that are not executable if we check for that.
Bram Moolenaarb5971142015-03-21 17:32:19 +01007042 if (!dir && (flags & EW_EXEC)
7043 && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00007044 continue;
7045
Bram Moolenaar964b3742019-05-24 18:54:09 +02007046 p = alloc(STRLEN((*file)[i]) + 1 + dir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007047 if (p)
7048 {
7049 STRCPY(p, (*file)[i]);
7050 if (dir)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007051 add_pathsep(p); // add '/' to a directory name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007052 (*file)[j++] = p;
7053 }
7054 }
7055 vim_free(buffer);
7056 *num_file = j;
7057
Bram Moolenaar0f873732019-12-05 20:28:46 +01007058 if (*num_file == 0) // rejected all entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00007059 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01007060 VIM_CLEAR(*file);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007061 goto notfound;
7062 }
7063
7064 return OK;
7065
7066notfound:
7067 if (flags & EW_NOTFOUND)
7068 return save_patterns(num_pat, pat, num_file, file);
7069 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007070}
7071
Bram Moolenaar0f873732019-12-05 20:28:46 +01007072#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00007073
Bram Moolenaar071d4272004-06-13 20:20:40 +00007074 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007075save_patterns(
7076 int num_pat,
7077 char_u **pat,
7078 int *num_file,
7079 char_u ***file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007080{
7081 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00007082 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007083
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007084 *file = ALLOC_MULT(char_u *, num_pat);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007085 if (*file == NULL)
7086 return FAIL;
7087 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00007088 {
7089 s = vim_strsave(pat[i]);
7090 if (s != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007091 // Be compatible with expand_filename(): halve the number of
7092 // backslashes.
Bram Moolenaard8b02732005-01-14 21:48:43 +00007093 backslash_halve(s);
7094 (*file)[i] = s;
7095 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007096 *num_file = num_pat;
7097 return OK;
7098}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007099
Bram Moolenaar071d4272004-06-13 20:20:40 +00007100/*
7101 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
7102 * expand.
7103 */
7104 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007105mch_has_exp_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007106{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007107 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007108 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007109 if (*p == '\\' && p[1] != NUL)
7110 ++p;
7111 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007112 if (vim_strchr((char_u *)
7113#ifdef VMS
7114 "*?%"
7115#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007116 "*?[{'"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007117#endif
7118 , *p) != NULL)
7119 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007120 }
7121 return FALSE;
7122}
7123
7124/*
7125 * Return TRUE if the string "p" contains a wildcard.
7126 * Don't recognize '~' at the end as a wildcard.
7127 */
7128 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007129mch_has_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007130{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007131 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007132 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007133 if (*p == '\\' && p[1] != NUL)
7134 ++p;
7135 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007136 if (vim_strchr((char_u *)
7137#ifdef VMS
7138 "*?%$"
7139#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007140 "*?[{`'$"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007141#endif
7142 , *p) != NULL
7143 || (*p == '~' && p[1] != NUL))
7144 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007145 }
7146 return FALSE;
7147}
7148
Bram Moolenaar071d4272004-06-13 20:20:40 +00007149 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007150have_wildcard(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007151{
7152 int i;
7153
7154 for (i = 0; i < num; i++)
7155 if (mch_has_wildcard(file[i]))
7156 return 1;
7157 return 0;
7158}
7159
7160 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007161have_dollars(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007162{
7163 int i;
7164
7165 for (i = 0; i < num; i++)
7166 if (vim_strchr(file[i], '$') != NULL)
7167 return TRUE;
7168 return FALSE;
7169}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007170
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007171#if !defined(HAVE_RENAME) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007172/*
7173 * Scaled-down version of rename(), which is missing in Xenix.
7174 * This version can only move regular files and will fail if the
7175 * destination exists.
7176 */
7177 int
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007178mch_rename(const char *src, const char *dest)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007179{
7180 struct stat st;
7181
Bram Moolenaar0f873732019-12-05 20:28:46 +01007182 if (stat(dest, &st) >= 0) // fail if destination exists
Bram Moolenaar071d4272004-06-13 20:20:40 +00007183 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007184 if (link(src, dest) != 0) // link file to new name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007185 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007186 if (mch_remove(src) == 0) // delete link to old name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007187 return 0;
7188 return -1;
7189}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007190#endif // !HAVE_RENAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00007191
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007192#if defined(FEAT_MOUSE_GPM) || defined(PROTO)
Bram Moolenaar33fc4a62022-02-23 18:07:38 +00007193# if defined(DYNAMIC_GPM) || defined(PROTO)
7194/*
7195 * Initialize Gpm's symbols for dynamic linking.
7196 * Must be called only if libgpm_hinst is NULL.
7197 */
7198 static int
7199load_libgpm(void)
7200{
7201 libgpm_hinst = dlopen("libgpm.so", RTLD_LAZY|RTLD_GLOBAL);
7202
7203 if (libgpm_hinst == NULL)
7204 {
7205 if (p_verbose > 0)
7206 smsg_attr(HL_ATTR(HLF_W),
7207 _("Could not load gpm library: %s"), dlerror());
7208 return FAIL;
7209 }
7210
7211 if (
7212 (dll_Gpm_Open = dlsym(libgpm_hinst, "Gpm_Open")) == NULL
7213 || (dll_Gpm_Close = dlsym(libgpm_hinst, "Gpm_Close")) == NULL
7214 || (dll_Gpm_GetEvent = dlsym(libgpm_hinst, "Gpm_GetEvent")) == NULL
7215 || (dll_gpm_flag = dlsym(libgpm_hinst, "gpm_flag")) == NULL
7216 || (dll_gpm_fd = dlsym(libgpm_hinst, "gpm_fd")) == NULL
7217 )
7218 {
7219 semsg(_(e_could_not_load_library_str_str), "gpm", dlerror());
7220 dlclose(libgpm_hinst);
7221 libgpm_hinst = NULL;
7222 dll_gpm_flag = NULL;
7223 dll_gpm_fd = NULL;
7224 return FAIL;
7225 }
7226 return OK;
7227}
7228
7229 int
7230gpm_available(void)
7231{
7232 return libgpm_hinst != NULL || load_libgpm() == OK;
7233}
7234# endif // DYNAMIC_GPM
7235
Bram Moolenaar071d4272004-06-13 20:20:40 +00007236/*
7237 * Initializes connection with gpm (if it isn't already opened)
7238 * Return 1 if succeeded (or connection already opened), 0 if failed
7239 */
7240 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007241gpm_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007242{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007243 static Gpm_Connect gpm_connect; // Must it be kept till closing ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007244
Bram Moolenaar33fc4a62022-02-23 18:07:38 +00007245#ifdef DYNAMIC_GPM
7246 if (!gpm_available())
7247 return 0;
7248#endif
7249
Bram Moolenaar071d4272004-06-13 20:20:40 +00007250 if (!gpm_flag)
7251 {
7252 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
7253 gpm_connect.defaultMask = ~GPM_HARD;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007254 // Default handling for mouse move
7255 gpm_connect.minMod = 0; // Handle any modifier keys
Bram Moolenaar071d4272004-06-13 20:20:40 +00007256 gpm_connect.maxMod = 0xffff;
7257 if (Gpm_Open(&gpm_connect, 0) > 0)
7258 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007259 // gpm library tries to handling TSTP causes
7260 // problems. Anyways, we close connection to Gpm whenever
7261 // we are going to suspend or starting an external process
7262 // so we shouldn't have problem with this
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007263# ifdef SIGTSTP
dbivolaruab16ad32021-12-29 19:41:47 +00007264 signal(SIGTSTP, restricted ? SIG_IGN : (RETSIGTYPE (*)())sig_tstp);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007265# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007266 return 1; // succeed
Bram Moolenaar071d4272004-06-13 20:20:40 +00007267 }
7268 if (gpm_fd == -2)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007269 Gpm_Close(); // We don't want to talk to xterm via gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007270 return 0;
7271 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007272 return 1; // already open
Bram Moolenaar071d4272004-06-13 20:20:40 +00007273}
7274
7275/*
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007276 * Returns TRUE if the GPM mouse is enabled.
7277 */
7278 int
7279gpm_enabled(void)
7280{
7281 return gpm_flag && gpm_fd >= 0;
7282}
7283
7284/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007285 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007286 */
7287 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007288gpm_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007289{
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007290 if (gpm_enabled())
Bram Moolenaar071d4272004-06-13 20:20:40 +00007291 Gpm_Close();
7292}
7293
Bram Moolenaarbedf0912019-05-04 16:58:45 +02007294/*
7295 * Reads gpm event and adds special keys to input buf. Returns length of
Bram Moolenaar071d4272004-06-13 20:20:40 +00007296 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02007297 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00007298 */
7299 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007300mch_gpm_process(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007301{
7302 int button;
7303 static Gpm_Event gpm_event;
7304 char_u string[6];
7305 int_u vim_modifiers;
7306 int row,col;
7307 unsigned char buttons_mask;
7308 unsigned char gpm_modifiers;
7309 static unsigned char old_buttons = 0;
7310
7311 Gpm_GetEvent(&gpm_event);
7312
7313#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007314 // Don't put events in the input queue now.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007315 if (hold_gui_events)
7316 return 0;
7317#endif
7318
7319 row = gpm_event.y - 1;
7320 col = gpm_event.x - 1;
7321
Bram Moolenaar0f873732019-12-05 20:28:46 +01007322 string[0] = ESC; // Our termcode
Bram Moolenaar071d4272004-06-13 20:20:40 +00007323 string[1] = 'M';
7324 string[2] = 'G';
7325 switch (GPM_BARE_EVENTS(gpm_event.type))
7326 {
7327 case GPM_DRAG:
7328 string[3] = MOUSE_DRAG;
7329 break;
7330 case GPM_DOWN:
7331 buttons_mask = gpm_event.buttons & ~old_buttons;
7332 old_buttons = gpm_event.buttons;
7333 switch (buttons_mask)
7334 {
7335 case GPM_B_LEFT:
7336 button = MOUSE_LEFT;
7337 break;
7338 case GPM_B_MIDDLE:
7339 button = MOUSE_MIDDLE;
7340 break;
7341 case GPM_B_RIGHT:
7342 button = MOUSE_RIGHT;
7343 break;
7344 default:
7345 return 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007346 // Don't know what to do. Can more than one button be
7347 // reported in one event?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007348 }
7349 string[3] = (char_u)(button | 0x20);
7350 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
7351 break;
7352 case GPM_UP:
7353 string[3] = MOUSE_RELEASE;
7354 old_buttons &= ~gpm_event.buttons;
7355 break;
7356 default:
7357 return 0;
7358 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007359 // This code is based on gui_x11_mouse_cb in gui_x11.c
Bram Moolenaar071d4272004-06-13 20:20:40 +00007360 gpm_modifiers = gpm_event.modifiers;
7361 vim_modifiers = 0x0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007362 // I ignore capslock stats. Aren't we all just hate capslock mixing with
7363 // Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
7364 // K_CAPSSHIFT is defined 8, so it probably isn't even reported
Bram Moolenaar071d4272004-06-13 20:20:40 +00007365 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
7366 vim_modifiers |= MOUSE_SHIFT;
7367
7368 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
7369 vim_modifiers |= MOUSE_CTRL;
7370 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
7371 vim_modifiers |= MOUSE_ALT;
7372 string[3] |= vim_modifiers;
7373 string[4] = (char_u)(col + ' ' + 1);
7374 string[5] = (char_u)(row + ' ' + 1);
7375 add_to_input_buf(string, 6);
7376 return 6;
7377}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007378#endif // FEAT_MOUSE_GPM
Bram Moolenaar071d4272004-06-13 20:20:40 +00007379
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007380#ifdef FEAT_SYSMOUSE
7381/*
7382 * Initialize connection with sysmouse.
7383 * Let virtual console inform us with SIGUSR2 for pending sysmouse
7384 * output, any sysmouse output than will be processed via sig_sysmouse().
7385 * Return OK if succeeded, FAIL if failed.
7386 */
7387 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007388sysmouse_open(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007389{
7390 struct mouse_info mouse;
7391
7392 mouse.operation = MOUSE_MODE;
7393 mouse.u.mode.mode = 0;
7394 mouse.u.mode.signal = SIGUSR2;
7395 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
7396 {
7397 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
7398 mouse.operation = MOUSE_SHOW;
7399 ioctl(1, CONS_MOUSECTL, &mouse);
7400 return OK;
7401 }
7402 return FAIL;
7403}
7404
7405/*
7406 * Stop processing SIGUSR2 signals, and also make sure that
7407 * virtual console do not send us any sysmouse related signal.
7408 */
7409 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007410sysmouse_close(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007411{
7412 struct mouse_info mouse;
7413
7414 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
7415 mouse.operation = MOUSE_MODE;
7416 mouse.u.mode.mode = 0;
7417 mouse.u.mode.signal = 0;
7418 ioctl(1, CONS_MOUSECTL, &mouse);
7419}
7420
7421/*
7422 * Gets info from sysmouse and adds special keys to input buf.
7423 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007424 static RETSIGTYPE
7425sig_sysmouse SIGDEFARG(sigarg)
7426{
7427 struct mouse_info mouse;
7428 struct video_info video;
7429 char_u string[6];
7430 int row, col;
7431 int button;
7432 int buttons;
7433 static int oldbuttons = 0;
7434
7435#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007436 // Don't put events in the input queue now.
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007437 if (hold_gui_events)
7438 return;
7439#endif
7440
7441 mouse.operation = MOUSE_GETINFO;
7442 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
7443 && ioctl(1, FBIO_MODEINFO, &video) != -1
7444 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
7445 && video.vi_cheight > 0 && video.vi_cwidth > 0)
7446 {
7447 row = mouse.u.data.y / video.vi_cheight;
7448 col = mouse.u.data.x / video.vi_cwidth;
7449 buttons = mouse.u.data.buttons;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007450 string[0] = ESC; // Our termcode
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007451 string[1] = 'M';
7452 string[2] = 'S';
7453 if (oldbuttons == buttons && buttons != 0)
7454 {
7455 button = MOUSE_DRAG;
7456 }
7457 else
7458 {
7459 switch (buttons)
7460 {
7461 case 0:
7462 button = MOUSE_RELEASE;
7463 break;
7464 case 1:
7465 button = MOUSE_LEFT;
7466 break;
7467 case 2:
7468 button = MOUSE_MIDDLE;
7469 break;
7470 case 4:
7471 button = MOUSE_RIGHT;
7472 break;
7473 default:
7474 return;
7475 }
7476 oldbuttons = buttons;
7477 }
7478 string[3] = (char_u)(button);
7479 string[4] = (char_u)(col + ' ' + 1);
7480 string[5] = (char_u)(row + ' ' + 1);
7481 add_to_input_buf(string, 6);
7482 }
7483 return;
7484}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007485#endif // FEAT_SYSMOUSE
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007486
Bram Moolenaar071d4272004-06-13 20:20:40 +00007487#if defined(FEAT_LIBCALL) || defined(PROTO)
Bram Moolenaard99df422016-01-29 23:20:40 +01007488typedef char_u * (*STRPROCSTR)(char_u *);
7489typedef char_u * (*INTPROCSTR)(int);
7490typedef int (*STRPROCINT)(char_u *);
7491typedef int (*INTPROCINT)(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007492
7493/*
7494 * Call a DLL routine which takes either a string or int param
7495 * and returns an allocated string.
7496 */
7497 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007498mch_libcall(
7499 char_u *libname,
7500 char_u *funcname,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007501 char_u *argstring, // NULL when using a argint
Bram Moolenaar05540972016-01-30 20:31:25 +01007502 int argint,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007503 char_u **string_result, // NULL when using number_result
Bram Moolenaar05540972016-01-30 20:31:25 +01007504 int *number_result)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007505{
7506# if defined(USE_DLOPEN)
7507 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007508 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007509# else
7510 shl_t hinstLib;
7511# endif
7512 STRPROCSTR ProcAdd;
7513 INTPROCSTR ProcAddI;
7514 char_u *retval_str = NULL;
7515 int retval_int = 0;
7516 int success = FALSE;
7517
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007518 /*
7519 * Get a handle to the DLL module.
7520 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007521# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007522 // First clear any error, it's not cleared by the dlopen() call.
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007523 (void)dlerror();
7524
Bram Moolenaar071d4272004-06-13 20:20:40 +00007525 hinstLib = dlopen((char *)libname, RTLD_LAZY
7526# ifdef RTLD_LOCAL
7527 | RTLD_LOCAL
7528# endif
7529 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007530 if (hinstLib == NULL)
7531 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007532 // "dlerr" must be used before dlclose()
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +00007533 dlerr = dlerror();
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007534 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007535 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007536 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007537# else
7538 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
7539# endif
7540
Bram Moolenaar0f873732019-12-05 20:28:46 +01007541 // If the handle is valid, try to get the function address.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007542 if (hinstLib != NULL)
7543 {
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007544# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007545 /*
7546 * Catch a crash when calling the library function. For example when
7547 * using a number where a string pointer is expected.
7548 */
7549 mch_startjmp();
7550 if (SETJMP(lc_jump_env) != 0)
7551 {
7552 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007553# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007554 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007555# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007556 mch_didjmp();
7557 }
7558 else
7559# endif
7560 {
7561 retval_str = NULL;
7562 retval_int = 0;
7563
7564 if (argstring != NULL)
7565 {
7566# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007567 *(void **)(&ProcAdd) = dlsym(hinstLib, (const char *)funcname);
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +00007568 dlerr = dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007569# else
7570 if (shl_findsym(&hinstLib, (const char *)funcname,
7571 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
7572 ProcAdd = NULL;
7573# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007574 if ((success = (ProcAdd != NULL
7575# if defined(USE_DLOPEN)
7576 && dlerr == NULL
7577# endif
7578 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007579 {
7580 if (string_result == NULL)
Bram Moolenaara4224862020-09-13 22:00:12 +02007581 retval_int = ((STRPROCINT)(void *)ProcAdd)(argstring);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007582 else
7583 retval_str = (ProcAdd)(argstring);
7584 }
7585 }
7586 else
7587 {
7588# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007589 *(void **)(&ProcAddI) = dlsym(hinstLib, (const char *)funcname);
=?UTF-8?q?Dundar=20G=C3=B6c?=420fabc2022-01-28 15:28:04 +00007590 dlerr = dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007591# else
7592 if (shl_findsym(&hinstLib, (const char *)funcname,
7593 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
7594 ProcAddI = NULL;
7595# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007596 if ((success = (ProcAddI != NULL
7597# if defined(USE_DLOPEN)
7598 && dlerr == NULL
7599# endif
7600 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007601 {
7602 if (string_result == NULL)
Bram Moolenaara4224862020-09-13 22:00:12 +02007603 retval_int = ((INTPROCINT)(void *)ProcAddI)(argint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007604 else
7605 retval_str = (ProcAddI)(argint);
7606 }
7607 }
7608
Bram Moolenaar0f873732019-12-05 20:28:46 +01007609 // Save the string before we free the library.
7610 // Assume that a "1" or "-1" result is an illegal pointer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007611 if (string_result == NULL)
7612 *number_result = retval_int;
7613 else if (retval_str != NULL
7614 && retval_str != (char_u *)1
7615 && retval_str != (char_u *)-1)
7616 *string_result = vim_strsave(retval_str);
7617 }
7618
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007619# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007620 mch_endjmp();
7621# ifdef SIGHASARG
7622 if (lc_signal != 0)
7623 {
7624 int i;
7625
Bram Moolenaar0f873732019-12-05 20:28:46 +01007626 // try to find the name of this signal
Bram Moolenaar071d4272004-06-13 20:20:40 +00007627 for (i = 0; signal_info[i].sig != -1; i++)
7628 if (lc_signal == signal_info[i].sig)
7629 break;
Bram Moolenaarac78dd42022-01-02 19:25:26 +00007630 semsg(e_got_sig_str_in_libcall, signal_info[i].name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007631 }
7632# endif
7633# endif
7634
Bram Moolenaar071d4272004-06-13 20:20:40 +00007635# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007636 // "dlerr" must be used before dlclose()
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007637 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007638 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007639
Bram Moolenaar0f873732019-12-05 20:28:46 +01007640 // Free the DLL module.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007641 (void)dlclose(hinstLib);
7642# else
7643 (void)shl_unload(hinstLib);
7644# endif
7645 }
7646
7647 if (!success)
7648 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00007649 semsg(_(e_library_call_failed_for_str), funcname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007650 return FAIL;
7651 }
7652
7653 return OK;
7654}
7655#endif
7656
7657#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007658static int xterm_trace = -1; // default: disabled
Bram Moolenaar071d4272004-06-13 20:20:40 +00007659static int xterm_button;
7660
7661/*
7662 * Setup a dummy window for X selections in a terminal.
7663 */
7664 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007665setup_term_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007666{
7667 int z = 0;
7668 char *strp = "";
7669 Widget AppShell;
7670
7671 if (!x_connect_to_server())
7672 return;
7673
7674 open_app_context();
7675 if (app_context != NULL && xterm_Shell == (Widget)0)
7676 {
7677 int (*oldhandler)();
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007678# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007679 int (*oldIOhandler)();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007680# endif
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007681# ifdef ELAPSED_FUNC
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01007682 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007683
7684 if (p_verbose > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007685 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007686# endif
7687
Bram Moolenaar0f873732019-12-05 20:28:46 +01007688 // Ignore X errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007689 oldhandler = XSetErrorHandler(x_error_check);
7690
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007691# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007692 // Ignore X IO errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007693 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
7694 mch_startjmp();
7695 if (SETJMP(lc_jump_env) != 0)
7696 {
7697 mch_didjmp();
7698 xterm_dpy = NULL;
7699 }
7700 else
Bram Moolenaaredce7422019-01-20 18:39:30 +01007701# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007702 {
7703 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
7704 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007705 if (xterm_dpy != NULL)
7706 xterm_dpy_retry_count = 0;
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007707# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007708 mch_endjmp();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007709# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007710 }
7711
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007712# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007713 // Now handle X IO errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007714 (void)XSetIOErrorHandler(oldIOhandler);
Bram Moolenaaredce7422019-01-20 18:39:30 +01007715# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007716 // Now handle X errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007717 (void)XSetErrorHandler(oldhandler);
7718
7719 if (xterm_dpy == NULL)
7720 {
7721 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01007722 verb_msg(_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007723 return;
7724 }
7725
Bram Moolenaar0f873732019-12-05 20:28:46 +01007726 // Catch terminating error of the X server connection.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007727 (void)XSetIOErrorHandler(x_IOerror_handler);
7728
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007729# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007730 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007731 {
7732 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007733 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007734 verbose_leave();
7735 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007736# endif
7737
Bram Moolenaar0f873732019-12-05 20:28:46 +01007738 // Create a Shell to make converters work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007739 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
7740 applicationShellWidgetClass, xterm_dpy,
7741 NULL);
7742 if (AppShell == (Widget)0)
7743 return;
7744 xterm_Shell = XtVaCreatePopupShell("VIM",
7745 topLevelShellWidgetClass, AppShell,
7746 XtNmappedWhenManaged, 0,
7747 XtNwidth, 1,
7748 XtNheight, 1,
7749 NULL);
7750 if (xterm_Shell == (Widget)0)
7751 return;
7752
7753 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02007754 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007755 if (x11_display == NULL)
7756 x11_display = xterm_dpy;
7757
7758 XtRealizeWidget(xterm_Shell);
7759 XSync(xterm_dpy, False);
7760 xterm_update();
7761 }
7762 if (xterm_Shell != (Widget)0)
7763 {
7764 clip_init(TRUE);
7765 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
7766 x11_window = (Window)atol(strp);
Bram Moolenaar0f873732019-12-05 20:28:46 +01007767 // Check if $WINDOWID is valid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007768 if (test_x11_window(xterm_dpy) == FAIL)
7769 x11_window = 0;
7770 if (x11_window != 0)
7771 xterm_trace = 0;
7772 }
7773}
7774
7775 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007776start_xterm_trace(int button)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007777{
7778 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
7779 return;
7780 xterm_trace = 1;
7781 xterm_button = button;
7782 do_xterm_trace();
7783}
7784
7785
7786 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007787stop_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007788{
7789 if (xterm_trace < 0)
7790 return;
7791 xterm_trace = 0;
7792}
7793
7794/*
7795 * Query the xterm pointer and generate mouse termcodes if necessary
7796 * return TRUE if dragging is active, else FALSE
7797 */
7798 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007799do_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007800{
7801 Window root, child;
7802 int root_x, root_y;
7803 int win_x, win_y;
7804 int row, col;
7805 int_u mask_return;
7806 char_u buf[50];
7807 char_u *strp;
7808 long got_hints;
7809 static char_u *mouse_code;
7810 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
7811 static int prev_row = 0, prev_col = 0;
7812 static XSizeHints xterm_hints;
7813
7814 if (xterm_trace <= 0)
7815 return FALSE;
7816
7817 if (xterm_trace == 1)
7818 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007819 // Get the hints just before tracking starts. The font size might
7820 // have changed recently.
Bram Moolenaara6c2c912008-01-13 15:31:00 +00007821 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
7822 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007823 || xterm_hints.width_inc <= 1
7824 || xterm_hints.height_inc <= 1)
7825 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007826 xterm_trace = -1; // Not enough data -- disable tracing
Bram Moolenaar071d4272004-06-13 20:20:40 +00007827 return FALSE;
7828 }
7829
Bram Moolenaar0f873732019-12-05 20:28:46 +01007830 // Rely on the same mouse code for the duration of this
Bram Moolenaar071d4272004-06-13 20:20:40 +00007831 mouse_code = find_termcode(mouse_name);
7832 prev_row = mouse_row;
Bram Moolenaarcde88542015-08-11 19:14:00 +02007833 prev_col = mouse_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007834 xterm_trace = 2;
7835
Bram Moolenaar0f873732019-12-05 20:28:46 +01007836 // Find the offset of the chars, there might be a scrollbar on the
7837 // left of the window and/or a menu on the top (eterm etc.)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007838 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7839 &win_x, &win_y, &mask_return);
7840 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
7841 - (xterm_hints.height_inc / 2);
7842 if (xterm_hints.y <= xterm_hints.height_inc / 2)
7843 xterm_hints.y = 2;
7844 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
7845 - (xterm_hints.width_inc / 2);
7846 if (xterm_hints.x <= xterm_hints.width_inc / 2)
7847 xterm_hints.x = 2;
7848 return TRUE;
7849 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02007850 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007851 {
7852 xterm_trace = 0;
7853 return FALSE;
7854 }
7855
7856 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7857 &win_x, &win_y, &mask_return);
7858
7859 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
7860 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
7861 if (row == prev_row && col == prev_col)
7862 return TRUE;
7863
7864 STRCPY(buf, mouse_code);
7865 strp = buf + STRLEN(buf);
7866 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
7867 *strp++ = (char_u)(col + ' ' + 1);
7868 *strp++ = (char_u)(row + ' ' + 1);
7869 *strp = 0;
7870 add_to_input_buf(buf, STRLEN(buf));
7871
7872 prev_row = row;
7873 prev_col = col;
7874 return TRUE;
7875}
7876
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02007877# if defined(FEAT_GUI) || defined(FEAT_XCLIPBOARD) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007878/*
7879 * Destroy the display, window and app_context. Required for GTK.
7880 */
7881 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007882clear_xterm_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007883{
7884 if (xterm_Shell != (Widget)0)
7885 {
7886 XtDestroyWidget(xterm_Shell);
7887 xterm_Shell = (Widget)0;
7888 }
7889 if (xterm_dpy != NULL)
7890 {
Bram Moolenaare8208012008-06-20 09:59:25 +00007891# if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01007892 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007893 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00007894# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007895 if (x11_display == xterm_dpy)
7896 x11_display = NULL;
7897 xterm_dpy = NULL;
7898 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007899# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007900 if (app_context != (XtAppContext)NULL)
7901 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007902 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007903 XtDestroyApplicationContext(app_context);
7904 app_context = (XtAppContext)NULL;
7905 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007906# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007907}
7908# endif
7909
7910/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007911 * Catch up with GUI or X events.
7912 */
7913 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007914clip_update(void)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007915{
7916# ifdef FEAT_GUI
7917 if (gui.in_use)
7918 gui_mch_update();
7919 else
7920# endif
7921 if (xterm_Shell != (Widget)0)
7922 xterm_update();
7923}
7924
7925/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007926 * Catch up with any queued X events. This may put keyboard input into the
7927 * input buffer, call resize call-backs, trigger timers etc. If there is
7928 * nothing in the X event queue (& no timers pending), then we return
7929 * immediately.
7930 */
7931 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007932xterm_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007933{
7934 XEvent event;
7935
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007936 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007937 {
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007938 XtInputMask mask = XtAppPending(app_context);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007939
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007940 if (mask == 0 || vim_is_input_buf_full())
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007941 break;
7942
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007943 if (mask & XtIMXEvent)
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007944 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007945 // There is an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007946 XtAppNextEvent(app_context, &event);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007947#ifdef FEAT_CLIENTSERVER
7948 {
7949 XPropertyEvent *e = (XPropertyEvent *)&event;
7950
7951 if (e->type == PropertyNotify && e->window == commWindow
Bram Moolenaar071d4272004-06-13 20:20:40 +00007952 && e->atom == commProperty && e->state == PropertyNewValue)
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007953 serverEventProc(xterm_dpy, &event, 0);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007954 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007955#endif
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007956 XtDispatchEvent(&event);
7957 }
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007958 else
7959 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007960 // There is something else than an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007961 XtAppProcessEvent(app_context, mask);
7962 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007963 }
7964}
7965
7966 int
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007967clip_xterm_own_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007968{
7969 if (xterm_Shell != (Widget)0)
7970 return clip_x11_own_selection(xterm_Shell, cbd);
7971 return FAIL;
7972}
7973
7974 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007975clip_xterm_lose_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007976{
7977 if (xterm_Shell != (Widget)0)
7978 clip_x11_lose_selection(xterm_Shell, cbd);
7979}
7980
7981 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007982clip_xterm_request_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007983{
7984 if (xterm_Shell != (Widget)0)
7985 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7986}
7987
7988 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007989clip_xterm_set_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007990{
7991 clip_x11_set_selection(cbd);
7992}
7993#endif
7994
7995
7996#if defined(USE_XSMP) || defined(PROTO)
7997/*
7998 * Code for X Session Management Protocol.
7999 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008000
8001# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008002/*
8003 * This is our chance to ask the user if they want to save,
8004 * or abort the logout
8005 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008006 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008007xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008008{
Bram Moolenaare1004402020-10-24 20:49:43 +02008009 int save_cmod_flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008010 int cancel_shutdown = False;
8011
Bram Moolenaare1004402020-10-24 20:49:43 +02008012 save_cmod_flags = cmdmod.cmod_flags;
8013 cmdmod.cmod_flags |= CMOD_CONFIRM;
Bram Moolenaar027387f2016-01-02 22:25:52 +01008014 if (check_changed_any(FALSE, FALSE))
Bram Moolenaar0f873732019-12-05 20:28:46 +01008015 // Mustn't logout
Bram Moolenaar071d4272004-06-13 20:20:40 +00008016 cancel_shutdown = True;
Bram Moolenaare1004402020-10-24 20:49:43 +02008017 cmdmod.cmod_flags = save_cmod_flags;
Bram Moolenaar0f873732019-12-05 20:28:46 +01008018 setcursor(); // position cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00008019 out_flush();
8020
Bram Moolenaar0f873732019-12-05 20:28:46 +01008021 // Done interaction
Bram Moolenaar071d4272004-06-13 20:20:40 +00008022 SmcInteractDone(smc_conn, cancel_shutdown);
8023
Bram Moolenaar0f873732019-12-05 20:28:46 +01008024 // Finish off
8025 // Only end save-yourself here if we're not cancelling shutdown;
8026 // we'll get a cancelled callback later in which we'll end it.
8027 // Hopefully get around glitchy SMs (like GNOME-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008028 if (!cancel_shutdown)
8029 {
8030 xsmp.save_yourself = False;
8031 SmcSaveYourselfDone(smc_conn, True);
8032 }
8033}
8034# endif
8035
8036/*
8037 * Callback that starts save-yourself.
8038 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008039 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008040xsmp_handle_save_yourself(
8041 SmcConn smc_conn,
8042 SmPointer client_data UNUSED,
8043 int save_type UNUSED,
8044 Bool shutdown,
8045 int interact_style UNUSED,
8046 Bool fast UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008047{
Bram Moolenaar0f873732019-12-05 20:28:46 +01008048 // Handle already being in saveyourself
Bram Moolenaar071d4272004-06-13 20:20:40 +00008049 if (xsmp.save_yourself)
8050 SmcSaveYourselfDone(smc_conn, True);
8051 xsmp.save_yourself = True;
8052 xsmp.shutdown = shutdown;
8053
Bram Moolenaar0f873732019-12-05 20:28:46 +01008054 // First up, preserve all files
Bram Moolenaar071d4272004-06-13 20:20:40 +00008055 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01008056 ml_sync_all(FALSE, FALSE); // preserve all swap files
Bram Moolenaar071d4272004-06-13 20:20:40 +00008057
8058 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008059 verb_msg(_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008060
8061# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01008062 // Now see if we can ask about unsaved files
Bram Moolenaar071d4272004-06-13 20:20:40 +00008063 if (shutdown && !fast && gui.in_use)
Bram Moolenaar0f873732019-12-05 20:28:46 +01008064 // Need to interact with user, but need SM's permission
Bram Moolenaar071d4272004-06-13 20:20:40 +00008065 SmcInteractRequest(smc_conn, SmDialogError,
8066 xsmp_handle_interaction, client_data);
8067 else
8068# endif
8069 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01008070 // Can stop the cycle here
Bram Moolenaar071d4272004-06-13 20:20:40 +00008071 SmcSaveYourselfDone(smc_conn, True);
8072 xsmp.save_yourself = False;
8073 }
8074}
8075
8076
8077/*
8078 * Callback to warn us of imminent death.
8079 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008080 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008081xsmp_die(SmcConn smc_conn UNUSED, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008082{
8083 xsmp_close();
8084
Bram Moolenaar0f873732019-12-05 20:28:46 +01008085 // quit quickly leaving swapfiles for modified buffers behind
Bram Moolenaar071d4272004-06-13 20:20:40 +00008086 getout_preserve_modified(0);
8087}
8088
8089
8090/*
8091 * Callback to tell us that save-yourself has completed.
8092 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008093 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008094xsmp_save_complete(
8095 SmcConn smc_conn UNUSED,
8096 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008097{
8098 xsmp.save_yourself = False;
8099}
8100
8101
8102/*
8103 * Callback to tell us that an instigated shutdown was cancelled
8104 * (maybe even by us)
8105 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008106 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008107xsmp_shutdown_cancelled(
8108 SmcConn smc_conn,
8109 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008110{
8111 if (xsmp.save_yourself)
8112 SmcSaveYourselfDone(smc_conn, True);
8113 xsmp.save_yourself = False;
8114 xsmp.shutdown = False;
8115}
8116
8117
8118/*
8119 * Callback to tell us that a new ICE connection has been established.
8120 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008121 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008122xsmp_ice_connection(
8123 IceConn iceConn,
8124 IcePointer clientData UNUSED,
8125 Bool opening,
8126 IcePointer *watchData UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008127{
Bram Moolenaar0f873732019-12-05 20:28:46 +01008128 // Intercept creation of ICE connection fd
Bram Moolenaar071d4272004-06-13 20:20:40 +00008129 if (opening)
8130 {
8131 xsmp_icefd = IceConnectionNumber(iceConn);
8132 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
8133 }
8134}
8135
8136
Bram Moolenaar0f873732019-12-05 20:28:46 +01008137// Handle any ICE processing that's required; return FAIL if SM lost
Bram Moolenaar071d4272004-06-13 20:20:40 +00008138 int
Bram Moolenaar05540972016-01-30 20:31:25 +01008139xsmp_handle_requests(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008140{
8141 Bool rep;
8142
8143 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
8144 == IceProcessMessagesIOError)
8145 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01008146 // Lost ICE
Bram Moolenaar071d4272004-06-13 20:20:40 +00008147 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008148 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008149 xsmp_close();
8150 return FAIL;
8151 }
8152 else
8153 return OK;
8154}
8155
8156static int dummy;
8157
Bram Moolenaar0f873732019-12-05 20:28:46 +01008158// Set up X Session Management Protocol
Bram Moolenaar071d4272004-06-13 20:20:40 +00008159 void
8160xsmp_init(void)
8161{
8162 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00008163 SmcCallbacks smcallbacks;
8164#if 0
8165 SmPropValue smname;
8166 SmProp smnameprop;
8167 SmProp *smprops[1];
8168#endif
8169
8170 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008171 verb_msg(_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008172
8173 xsmp.save_yourself = xsmp.shutdown = False;
8174
Bram Moolenaar0f873732019-12-05 20:28:46 +01008175 // Set up SM callbacks - must have all, even if they're not used
Bram Moolenaar071d4272004-06-13 20:20:40 +00008176 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
8177 smcallbacks.save_yourself.client_data = NULL;
8178 smcallbacks.die.callback = xsmp_die;
8179 smcallbacks.die.client_data = NULL;
8180 smcallbacks.save_complete.callback = xsmp_save_complete;
8181 smcallbacks.save_complete.client_data = NULL;
8182 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
8183 smcallbacks.shutdown_cancelled.client_data = NULL;
8184
Bram Moolenaar0f873732019-12-05 20:28:46 +01008185 // Set up a watch on ICE connection creations. The "dummy" argument is
8186 // apparently required for FreeBSD (we get a BUS error when using NULL).
Bram Moolenaar071d4272004-06-13 20:20:40 +00008187 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
8188 {
8189 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008190 verb_msg(_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008191 return;
8192 }
8193
Bram Moolenaar0f873732019-12-05 20:28:46 +01008194 // Create an SM connection
Bram Moolenaar071d4272004-06-13 20:20:40 +00008195 xsmp.smcconn = SmcOpenConnection(
8196 NULL,
8197 NULL,
8198 SmProtoMajor,
8199 SmProtoMinor,
8200 SmcSaveYourselfProcMask | SmcDieProcMask
8201 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
8202 &smcallbacks,
8203 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00008204 &xsmp.clientid,
Bram Moolenaar4841a7c2018-09-22 14:08:49 +02008205 sizeof(errorstring) - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00008206 errorstring);
8207 if (xsmp.smcconn == NULL)
8208 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00008209 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008210 {
Bram Moolenaare1be1182020-10-24 13:30:51 +02008211 char errorreport[132];
8212
8213 // If the message is too long it might not be NUL terminated. Add
8214 // a NUL at the end to make sure we don't go over the end.
8215 errorstring[sizeof(errorstring) - 1] = NUL;
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008216 vim_snprintf(errorreport, sizeof(errorreport),
8217 _("XSMP SmcOpenConnection failed: %s"), errorstring);
Bram Moolenaar32526b32019-01-19 17:43:09 +01008218 verb_msg(errorreport);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008219 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008220 return;
8221 }
8222 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
8223
8224#if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01008225 // ID ourselves
Bram Moolenaar071d4272004-06-13 20:20:40 +00008226 smname.value = "vim";
8227 smname.length = 3;
8228 smnameprop.name = "SmProgram";
8229 smnameprop.type = "SmARRAY8";
8230 smnameprop.num_vals = 1;
8231 smnameprop.vals = &smname;
8232
8233 smprops[0] = &smnameprop;
8234 SmcSetProperties(xsmp.smcconn, 1, smprops);
8235#endif
8236}
8237
8238
Bram Moolenaar0f873732019-12-05 20:28:46 +01008239// Shut down XSMP comms.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008240 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008241xsmp_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008242{
8243 if (xsmp_icefd != -1)
8244 {
8245 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00008246 if (xsmp.clientid != NULL)
8247 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00008248 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008249 xsmp_icefd = -1;
8250 }
8251}
Bram Moolenaar0f873732019-12-05 20:28:46 +01008252#endif // USE_XSMP