blob: e24c09f4aae831394a9a00430b10ea49f50d5d0e [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * OS/2 port by Paul Slootman
5 * VMS merge by Zoltan Arpadffy
6 *
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 * See README.txt for an overview of the Vim source code.
10 */
11
12/*
13 * os_unix.c -- code for all flavors of Unix (BSD, SYSV, SVR4, POSIX, ...)
14 * Also for OS/2, using the excellent EMX package!!!
Bram Moolenaar041c7102020-05-30 18:14:57 +020015 * Also for Atari MiNT.
Bram Moolenaar071d4272004-06-13 20:20:40 +000016 *
17 * A lot of this file was originally written by Juergen Weigert and later
18 * changed beyond recognition.
19 */
20
Bram Moolenaar071d4272004-06-13 20:20:40 +000021#include "vim.h"
22
Bram Moolenaar325b7a22004-07-05 15:58:32 +000023#ifdef FEAT_MZSCHEME
24# include "if_mzsch.h"
25#endif
26
Bram Moolenaar0f873732019-12-05 20:28:46 +010027#include "os_unixx.h" // unix includes for os_unix.c only
Bram Moolenaar071d4272004-06-13 20:20:40 +000028
29#ifdef USE_XSMP
30# include <X11/SM/SMlib.h>
31#endif
32
Bram Moolenaar588ebeb2008-05-07 17:09:24 +000033#ifdef HAVE_SELINUX
34# include <selinux/selinux.h>
35static int selinux_enabled = -1;
36#endif
37
Bram Moolenaar5bd32f42014-04-02 14:05:38 +020038#ifdef HAVE_SMACK
39# include <attr/xattr.h>
40# include <linux/xattr.h>
41# ifndef SMACK_LABEL_LEN
42# define SMACK_LABEL_LEN 1024
43# endif
44#endif
45
Bram Moolenaara2442432007-04-26 14:26:37 +000046#ifdef __CYGWIN__
Bram Moolenaar4f974752019-02-17 17:44:42 +010047# ifndef MSWIN
Bram Moolenaar0d1498e2008-06-29 12:00:49 +000048# include <cygwin/version.h>
Bram Moolenaar0f873732019-12-05 20:28:46 +010049# include <sys/cygwin.h> // for cygwin_conv_to_posix_path() and/or
50 // for cygwin_conv_path()
Bram Moolenaar693e40c2013-02-26 14:56:42 +010051# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
52# define WIN32_LEAN_AND_MEAN
53# include <windows.h>
54# include "winclip.pro"
55# endif
Bram Moolenaara2442432007-04-26 14:26:37 +000056# endif
57#endif
58
Bram Moolenaar071d4272004-06-13 20:20:40 +000059#ifdef FEAT_MOUSE_GPM
60# include <gpm.h>
Bram Moolenaar0f873732019-12-05 20:28:46 +010061// <linux/keyboard.h> contains defines conflicting with "keymap.h",
62// I just copied relevant defines here. A cleaner solution would be to put gpm
63// code into separate file and include there linux/keyboard.h
64// #include <linux/keyboard.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000065# define KG_SHIFT 0
66# define KG_CTRL 2
67# define KG_ALT 3
68# define KG_ALTGR 1
69# define KG_SHIFTL 4
70# define KG_SHIFTR 5
71# define KG_CTRLL 6
72# define KG_CTRLR 7
73# define KG_CAPSSHIFT 8
74
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010075static void gpm_close(void);
76static int gpm_open(void);
77static int mch_gpm_process(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000078#endif
79
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000080#ifdef FEAT_SYSMOUSE
81# include <sys/consio.h>
82# include <sys/fbio.h>
83
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010084static int sysmouse_open(void);
85static void sysmouse_close(void);
Bram Moolenaard99df422016-01-29 23:20:40 +010086static RETSIGTYPE sig_sysmouse SIGPROTOARG;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000087#endif
88
Bram Moolenaar071d4272004-06-13 20:20:40 +000089/*
90 * end of autoconf section. To be extended...
91 */
92
Bram Moolenaar0f873732019-12-05 20:28:46 +010093// Are the following #ifdefs still required? And why? Is that for X11?
Bram Moolenaar071d4272004-06-13 20:20:40 +000094
95#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
96# ifdef SIGWINCH
97# undef SIGWINCH
98# endif
99# ifdef TIOCGWINSZ
100# undef TIOCGWINSZ
101# endif
102#endif
103
Bram Moolenaar0f873732019-12-05 20:28:46 +0100104#if defined(SIGWINDOW) && !defined(SIGWINCH) // hpux 9.01 has it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000105# define SIGWINCH SIGWINDOW
106#endif
107
108#ifdef FEAT_X11
109# include <X11/Xlib.h>
110# include <X11/Xutil.h>
111# include <X11/Xatom.h>
112# ifdef FEAT_XCLIPBOARD
113# include <X11/Intrinsic.h>
114# include <X11/Shell.h>
115# include <X11/StringDefs.h>
116static Widget xterm_Shell = (Widget)0;
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100117static void clip_update(void);
118static void xterm_update(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119# endif
120
Bram Moolenaar071d4272004-06-13 20:20:40 +0000121Window x11_window = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000122Display *x11_display = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000123#endif
124
Bram Moolenaar5c3128e2020-05-11 20:54:42 +0200125static int ignore_sigtstp = FALSE;
126
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100127static int get_x11_title(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000128
129static char_u *oldtitle = NULL;
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200130static volatile sig_atomic_t oldtitle_outdated = FALSE;
Bram Moolenaardac13472019-09-16 21:06:21 +0200131static int unix_did_set_title = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000132static char_u *oldicon = NULL;
133static int did_set_icon = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000134
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100135static void may_core_dump(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000136
Bram Moolenaar205b8862011-09-07 15:04:31 +0200137#ifdef HAVE_UNION_WAIT
138typedef union wait waitstatus;
139#else
140typedef int waitstatus;
141#endif
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200142static int WaitForChar(long msec, int *interrupted, int ignore_input);
143static int WaitForCharOrMouse(long msec, int *interrupted, int ignore_input);
Bram Moolenaar041c7102020-05-30 18:14:57 +0200144#ifdef VMS
Bram Moolenaarcda77642016-06-04 13:32:35 +0200145int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146#else
Bram Moolenaarcda77642016-06-04 13:32:35 +0200147static int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148#endif
149
150#ifdef FEAT_XCLIPBOARD
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100151static int do_xterm_trace(void);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100152# define XT_TRACE_DELAY 50 // delay for xterm tracing
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153#endif
154
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100155static void handle_resize(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000156
157#if defined(SIGWINCH)
Bram Moolenaard99df422016-01-29 23:20:40 +0100158static RETSIGTYPE sig_winch SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000159#endif
dbivolaruab16ad32021-12-29 19:41:47 +0000160#if defined(SIGTSTP)
161static RETSIGTYPE sig_tstp SIGPROTOARG;
162// volatile because it is used in signal handler sig_tstp() and sigcont_handler().
163static volatile sig_atomic_t in_mch_suspend = FALSE;
164#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165#if defined(SIGINT)
Bram Moolenaard99df422016-01-29 23:20:40 +0100166static RETSIGTYPE catch_sigint SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167#endif
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200168#if defined(SIGUSR1)
169static RETSIGTYPE catch_sigusr1 SIGPROTOARG;
170#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171#if defined(SIGPWR)
Bram Moolenaard99df422016-01-29 23:20:40 +0100172static RETSIGTYPE catch_sigpwr SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000173#endif
Bram Moolenaar651fca82021-11-29 20:39:38 +0000174#if defined(SIGALRM) && defined(FEAT_X11) && !defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175# define SET_SIG_ALARM
Bram Moolenaard99df422016-01-29 23:20:40 +0100176static RETSIGTYPE sig_alarm SIGPROTOARG;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100177// volatile because it is used in signal handler sig_alarm().
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200178static volatile sig_atomic_t sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179#endif
Bram Moolenaard99df422016-01-29 23:20:40 +0100180static RETSIGTYPE deathtrap SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000181
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100182static void catch_int_signal(void);
183static void set_signals(void);
184static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)());
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +0200185#ifdef HAVE_SIGPROCMASK
186# define SIGSET_DECL(set) sigset_t set;
187# define BLOCK_SIGNALS(set) block_signals(set)
188# define UNBLOCK_SIGNALS(set) unblock_signals(set)
189#else
190# define SIGSET_DECL(set)
191# define BLOCK_SIGNALS(set) do { /**/ } while (0)
192# define UNBLOCK_SIGNALS(set) do { /**/ } while (0)
193#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100194static int have_wildcard(int, char_u **);
195static int have_dollars(int, char_u **);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100197static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198
199#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000200# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201#endif
202
Bram Moolenaar0f873732019-12-05 20:28:46 +0100203// volatile because it is used in signal handler sig_winch().
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200204static volatile sig_atomic_t do_resize = FALSE;
dbivolaruab16ad32021-12-29 19:41:47 +0000205// volatile because it is used in signal handler sig_tstp().
206static volatile sig_atomic_t got_tstp = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000207static char_u *extra_shell_arg = NULL;
208static int show_shell_mess = TRUE;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100209// volatile because it is used in signal handler deathtrap().
210static volatile sig_atomic_t deadly_signal = 0; // The signal we caught
211// volatile because it is used in signal handler deathtrap().
212static volatile sig_atomic_t in_mch_delay = FALSE; // sleeping in mch_delay()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000213
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +0100214#if defined(FEAT_JOB_CHANNEL) && !defined(USE_SYSTEM)
215static int dont_check_job_ended = 0;
216#endif
217
Bram Moolenaar26e86442020-05-17 14:06:16 +0200218// Current terminal mode from mch_settmode(). Can differ from cur_tmode.
219static tmode_T mch_cur_tmode = TMODE_COOK;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220
221#ifdef USE_XSMP
222typedef struct
223{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100224 SmcConn smcconn; // The SM connection ID
225 IceConn iceconn; // The ICE connection ID
226 char *clientid; // The client ID for the current smc session
227 Bool save_yourself; // If we're in the middle of a save_yourself
228 Bool shutdown; // If we're in shutdown mode
Bram Moolenaar071d4272004-06-13 20:20:40 +0000229} xsmp_config_T;
230
231static xsmp_config_T xsmp;
232#endif
233
234#ifdef SYS_SIGLIST_DECLARED
235/*
236 * I have seen
237 * extern char *_sys_siglist[NSIG];
238 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
239 * that describe the signals. That is nearly what we want here. But
240 * autoconf does only check for sys_siglist (without the underscore), I
241 * do not want to change everything today.... jw.
Bram Moolenaar3f7d0902016-11-12 21:13:42 +0100242 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.ac.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000243 */
244#endif
245
246static struct signalinfo
247{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100248 int sig; // Signal number, eg. SIGSEGV etc
249 char *name; // Signal name (not char_u!).
250 char deadly; // Catch as a deadly signal?
Bram Moolenaar071d4272004-06-13 20:20:40 +0000251} signal_info[] =
252{
253#ifdef SIGHUP
254 {SIGHUP, "HUP", TRUE},
255#endif
256#ifdef SIGQUIT
257 {SIGQUIT, "QUIT", TRUE},
258#endif
259#ifdef SIGILL
260 {SIGILL, "ILL", TRUE},
261#endif
262#ifdef SIGTRAP
263 {SIGTRAP, "TRAP", TRUE},
264#endif
265#ifdef SIGABRT
266 {SIGABRT, "ABRT", TRUE},
267#endif
268#ifdef SIGEMT
269 {SIGEMT, "EMT", TRUE},
270#endif
271#ifdef SIGFPE
272 {SIGFPE, "FPE", TRUE},
273#endif
274#ifdef SIGBUS
275 {SIGBUS, "BUS", TRUE},
276#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100277#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100278 // MzScheme uses SEGV in its garbage collector
Bram Moolenaar071d4272004-06-13 20:20:40 +0000279 {SIGSEGV, "SEGV", TRUE},
280#endif
281#ifdef SIGSYS
282 {SIGSYS, "SYS", TRUE},
283#endif
284#ifdef SIGALRM
Bram Moolenaar0f873732019-12-05 20:28:46 +0100285 {SIGALRM, "ALRM", FALSE}, // Perl's alarm() can trigger it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000286#endif
287#ifdef SIGTERM
288 {SIGTERM, "TERM", TRUE},
289#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100290#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000291 {SIGVTALRM, "VTALRM", TRUE},
292#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000293#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100294 // MzScheme uses SIGPROF for its own needs; On Linux with profiling
295 // this makes Vim exit. WE_ARE_PROFILING is defined in Makefile.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000296 {SIGPROF, "PROF", TRUE},
297#endif
298#ifdef SIGXCPU
299 {SIGXCPU, "XCPU", TRUE},
300#endif
301#ifdef SIGXFSZ
302 {SIGXFSZ, "XFSZ", TRUE},
303#endif
304#ifdef SIGUSR1
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200305 {SIGUSR1, "USR1", FALSE},
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000307#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100308 // Used for sysmouse handling
Bram Moolenaar071d4272004-06-13 20:20:40 +0000309 {SIGUSR2, "USR2", TRUE},
310#endif
311#ifdef SIGINT
312 {SIGINT, "INT", FALSE},
313#endif
314#ifdef SIGWINCH
315 {SIGWINCH, "WINCH", FALSE},
316#endif
317#ifdef SIGTSTP
318 {SIGTSTP, "TSTP", FALSE},
319#endif
320#ifdef SIGPIPE
321 {SIGPIPE, "PIPE", FALSE},
322#endif
323 {-1, "Unknown!", FALSE}
324};
325
Bram Moolenaar25724922009-07-14 15:38:41 +0000326 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100327mch_chdir(char *path)
Bram Moolenaar25724922009-07-14 15:38:41 +0000328{
329 if (p_verbose >= 5)
330 {
331 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100332 smsg("chdir(%s)", path);
Bram Moolenaar25724922009-07-14 15:38:41 +0000333 verbose_leave();
334 }
335# ifdef VMS
336 return chdir(vms_fixfilename(path));
337# else
338 return chdir(path);
339# endif
340}
341
Bram Moolenaar0f873732019-12-05 20:28:46 +0100342// Why is NeXT excluded here (and not in os_unixx.h)?
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +0100343#if defined(ECHOE) && defined(ICANON) \
344 && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) \
345 && !defined(__NeXT__)
Bram Moolenaar4f44b882017-08-13 20:06:18 +0200346# define NEW_TTY_SYSTEM
347#endif
348
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000349/*
Bram Moolenaard23a8232018-02-10 18:45:26 +0100350 * Write s[len] to the screen (stdout).
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000351 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100353mch_write(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354{
Bram Moolenaar42335f52018-09-13 15:33:43 +0200355 vim_ignored = (int)write(1, (char *)s, len);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100356 if (p_wd) // Unix is too fast, slow down a bit more
Bram Moolenaar8fdd7212016-03-26 19:41:48 +0100357 RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000358}
359
360/*
Bram Moolenaare40b9d42019-01-27 16:55:47 +0100361 * Function passed to inchar_loop() to handle window resizing.
362 * If "check_only" is TRUE: Return whether there was a resize.
363 * If "check_only" is FALSE: Deal with the window resized.
364 */
365 static int
366resize_func(int check_only)
367{
368 if (check_only)
369 return do_resize;
370 while (do_resize)
371 handle_resize();
372 return FALSE;
373}
374
375/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000376 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377 * Get a characters from the keyboard.
378 * Return the number of characters that are available.
379 * If wtime == 0 do not wait for characters.
380 * If wtime == n wait a short time for characters.
381 * If wtime == -1 wait forever for characters.
382 */
383 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100384mch_inchar(
385 char_u *buf,
386 int maxlen,
Bram Moolenaar0f873732019-12-05 20:28:46 +0100387 long wtime, // don't use "time", MIPS cannot handle it
Bram Moolenaar05540972016-01-30 20:31:25 +0100388 int tb_change_cnt)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389{
Bram Moolenaare40b9d42019-01-27 16:55:47 +0100390 return inchar_loop(buf, maxlen, wtime, tb_change_cnt,
391 WaitForChar, resize_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392}
393
394 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100395handle_resize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000396{
397 do_resize = FALSE;
398 shell_resized();
399}
400
401/*
Bram Moolenaar40b1b542016-04-20 20:18:23 +0200402 * Return non-zero if a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000403 */
404 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100405mch_char_avail(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406{
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200407 return WaitForChar(0L, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408}
409
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200410#if defined(FEAT_TERMINAL) || defined(PROTO)
411/*
412 * Check for any pending input or messages.
413 */
414 int
415mch_check_messages(void)
416{
417 return WaitForChar(0L, NULL, TRUE);
418}
419#endif
420
Bram Moolenaar071d4272004-06-13 20:20:40 +0000421#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
422# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000423# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424# endif
425# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
426# include <sys/sysctl.h>
427# endif
428# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
429# include <sys/sysinfo.h>
430# endif
Bram Moolenaar362dc332018-03-05 21:59:37 +0100431# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100432# include <mach/mach_host.h>
433# include <mach/mach_port.h>
Bram Moolenaar988615f2018-02-27 17:58:20 +0100434# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000435
436/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000437 * Return total amount of memory available in Kbyte.
438 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000440 long_u
Bram Moolenaar05540972016-01-30 20:31:25 +0100441mch_total_mem(int special UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000442{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443 long_u mem = 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100444 long_u shiftright = 10; // how much to shift "mem" right for Kbyte
Bram Moolenaar071d4272004-06-13 20:20:40 +0000445
Bram Moolenaar362dc332018-03-05 21:59:37 +0100446# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100447 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100448 // Mac (Darwin) way of getting the amount of RAM available
Bram Moolenaar988615f2018-02-27 17:58:20 +0100449 mach_port_t host = mach_host_self();
450 kern_return_t kret;
451# ifdef HOST_VM_INFO64
452 struct vm_statistics64 vm_stat;
453 natural_t count = HOST_VM_INFO64_COUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000454
Bram Moolenaar988615f2018-02-27 17:58:20 +0100455 kret = host_statistics64(host, HOST_VM_INFO64,
456 (host_info64_t)&vm_stat, &count);
457# else
458 struct vm_statistics vm_stat;
459 natural_t count = HOST_VM_INFO_COUNT;
460
461 kret = host_statistics(host, HOST_VM_INFO,
462 (host_info_t)&vm_stat, &count);
463# endif
464 if (kret == KERN_SUCCESS)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100465 // get the amount of user memory by summing each usage
Bram Moolenaar988615f2018-02-27 17:58:20 +0100466 mem = (long_u)(vm_stat.free_count + vm_stat.active_count
467 + vm_stat.inactive_count
468# ifdef MAC_OS_X_VERSION_10_9
469 + vm_stat.compressor_page_count
470# endif
Bram Moolenaar62b7f6a2018-03-22 21:44:07 +0100471 ) * sysconf(_SC_PAGESIZE);
Bram Moolenaar988615f2018-02-27 17:58:20 +0100472 mach_port_deallocate(mach_task_self(), host);
473 }
474# endif
475
476# ifdef HAVE_SYSCTL
477 if (mem == 0)
478 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100479 // BSD way of getting the amount of RAM available.
Bram Moolenaar988615f2018-02-27 17:58:20 +0100480 int mib[2];
481 size_t len = sizeof(long_u);
482# ifdef HW_USERMEM64
483 long_u physmem;
484# else
Bram Moolenaar0f873732019-12-05 20:28:46 +0100485 // sysctl() may return 32 bit or 64 bit, accept both
Bram Moolenaar988615f2018-02-27 17:58:20 +0100486 union {
487 int_u u32;
488 long_u u64;
489 } physmem;
490# endif
491
492 mib[0] = CTL_HW;
493# ifdef HW_USERMEM64
494 mib[1] = HW_USERMEM64;
495# else
496 mib[1] = HW_USERMEM;
497# endif
498 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
499 {
500# ifdef HW_USERMEM64
501 mem = (long_u)physmem;
502# else
503 if (len == sizeof(physmem.u64))
504 mem = (long_u)physmem.u64;
505 else
506 mem = (long_u)physmem.u32;
507# endif
508 }
509 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200510# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200512# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513 if (mem == 0)
514 {
515 struct sysinfo sinfo;
516
Bram Moolenaar0f873732019-12-05 20:28:46 +0100517 // Linux way of getting amount of RAM available
Bram Moolenaar071d4272004-06-13 20:20:40 +0000518 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000519 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200520# ifdef HAVE_SYSINFO_MEM_UNIT
Bram Moolenaar0f873732019-12-05 20:28:46 +0100521 // avoid overflow as much as possible
Bram Moolenaar914572a2007-05-01 11:37:47 +0000522 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
523 {
524 sinfo.mem_unit = sinfo.mem_unit >> 1;
525 --shiftright;
526 }
527 mem = sinfo.totalram * sinfo.mem_unit;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200528# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529 mem = sinfo.totalram;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200530# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000531 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200533# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200535# ifdef HAVE_SYSCONF
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536 if (mem == 0)
537 {
538 long pagesize, pagecount;
539
Bram Moolenaar0f873732019-12-05 20:28:46 +0100540 // Solaris way of getting amount of RAM available
Bram Moolenaar071d4272004-06-13 20:20:40 +0000541 pagesize = sysconf(_SC_PAGESIZE);
542 pagecount = sysconf(_SC_PHYS_PAGES);
543 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000544 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100545 // avoid overflow as much as possible
Bram Moolenaar914572a2007-05-01 11:37:47 +0000546 while (shiftright > 0 && (pagesize & 1) == 0)
547 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000548 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000549 --shiftright;
550 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000552 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200554# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555
Bram Moolenaar0f873732019-12-05 20:28:46 +0100556 // Return the minimum of the physical memory and the user limit, because
557 // using more than the user limit may cause Vim to be terminated.
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200558# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000559 {
560 struct rlimit rlp;
561
562 if (getrlimit(RLIMIT_DATA, &rlp) == 0
563 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200564# ifdef RLIM_INFINITY
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565 && rlp.rlim_cur != RLIM_INFINITY
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200566# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000567 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000569 {
570 mem = (long_u)rlp.rlim_cur;
571 shiftright = 10;
572 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000573 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200574# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575
576 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000577 return mem >> shiftright;
578 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579}
580#endif
581
Bram Moolenaar0981c872020-08-23 14:28:37 +0200582/*
583 * "flags": MCH_DELAY_IGNOREINPUT - don't read input
584 * MCH_DELAY_SETTMODE - use settmode() even for short delays
585 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000586 void
Bram Moolenaar0981c872020-08-23 14:28:37 +0200587mch_delay(long msec, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000588{
Bram Moolenaar26e86442020-05-17 14:06:16 +0200589 tmode_T old_tmode;
Bram Moolenaar80361a52020-10-05 21:39:25 +0200590 int call_settmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000591#ifdef FEAT_MZSCHEME
Bram Moolenaar0f873732019-12-05 20:28:46 +0100592 long total = msec; // remember original value
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000593#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594
Bram Moolenaar0981c872020-08-23 14:28:37 +0200595 if (flags & MCH_DELAY_IGNOREINPUT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100597 // Go to cooked mode without echo, to allow SIGINT interrupting us
598 // here. But we don't want QUIT to kill us (CTRL-\ used in a
599 // shell may produce SIGQUIT).
Bram Moolenaar26e86442020-05-17 14:06:16 +0200600 // Only do this if sleeping for more than half a second.
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000601 in_mch_delay = TRUE;
Bram Moolenaar80361a52020-10-05 21:39:25 +0200602 call_settmode = mch_cur_tmode == TMODE_RAW
603 && (msec > 500 || (flags & MCH_DELAY_SETTMODE));
604 if (call_settmode)
605 {
606 old_tmode = mch_cur_tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607 settmode(TMODE_SLEEP);
Bram Moolenaar80361a52020-10-05 21:39:25 +0200608 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609
610 /*
611 * Everybody sleeps in a different way...
612 * Prefer nanosleep(), some versions of usleep() can only sleep up to
613 * one second.
614 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000615#ifdef FEAT_MZSCHEME
616 do
617 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100618 // if total is large enough, wait by portions in p_mzq
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000619 if (total > p_mzq)
620 msec = p_mzq;
621 else
622 msec = total;
623 total -= msec;
624#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625#ifdef HAVE_NANOSLEEP
626 {
627 struct timespec ts;
628
629 ts.tv_sec = msec / 1000;
630 ts.tv_nsec = (msec % 1000) * 1000000;
631 (void)nanosleep(&ts, NULL);
632 }
633#else
634# ifdef HAVE_USLEEP
635 while (msec >= 1000)
636 {
637 usleep((unsigned int)(999 * 1000));
638 msec -= 999;
639 }
640 usleep((unsigned int)(msec * 1000));
641# else
642# ifndef HAVE_SELECT
643 poll(NULL, 0, (int)msec);
644# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645 {
646 struct timeval tv;
647
648 tv.tv_sec = msec / 1000;
649 tv.tv_usec = (msec % 1000) * 1000;
Bram Moolenaar0981c872020-08-23 14:28:37 +0200650 // NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
651 // a patch from Sun to fix this. Reported by Gunnar Pedersen.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000652 select(0, NULL, NULL, NULL, &tv);
653 }
Bram Moolenaar0f873732019-12-05 20:28:46 +0100654# endif // HAVE_SELECT
655# endif // HAVE_NANOSLEEP
656#endif // HAVE_USLEEP
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000657#ifdef FEAT_MZSCHEME
658 }
659 while (total > 0);
660#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661
Bram Moolenaar80361a52020-10-05 21:39:25 +0200662 if (call_settmode)
Bram Moolenaar26e86442020-05-17 14:06:16 +0200663 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000664 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665 }
666 else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200667 WaitForChar(msec, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668}
669
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000670#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000671 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
672# define HAVE_CHECK_STACK_GROWTH
673/*
674 * Support for checking for an almost-out-of-stack-space situation.
675 */
676
677/*
678 * Return a pointer to an item on the stack. Used to find out if the stack
679 * grows up or down.
680 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681static int stack_grows_downwards;
682
683/*
684 * Find out if the stack grows upwards or downwards.
685 * "p" points to a variable on the stack of the caller.
686 */
687 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100688check_stack_growth(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000689{
690 int i;
691
692 stack_grows_downwards = (p > (char *)&i);
693}
694#endif
695
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000696#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000697static char *stack_limit = NULL;
698
699#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
700# include <pthread.h>
701# include <pthread_np.h>
702#endif
703
704/*
705 * Find out until how var the stack can grow without getting into trouble.
706 * Called when starting up and when switching to the signal stack in
707 * deathtrap().
708 */
709 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100710get_stack_limit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711{
712 struct rlimit rlp;
713 int i;
714 long lim;
715
Bram Moolenaar0f873732019-12-05 20:28:46 +0100716 // Set the stack limit to 15/16 of the allowable size. Skip this when the
717 // limit doesn't fit in a long (rlim_cur might be "long long").
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 if (getrlimit(RLIMIT_STACK, &rlp) == 0
719 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
720# ifdef RLIM_INFINITY
721 && rlp.rlim_cur != RLIM_INFINITY
722# endif
723 )
724 {
725 lim = (long)rlp.rlim_cur;
726#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
727 {
728 pthread_attr_t attr;
729 size_t size;
730
Bram Moolenaar0f873732019-12-05 20:28:46 +0100731 // On FreeBSD the initial thread always has a fixed stack size, no
732 // matter what the limits are set to. Normally it's 1 Mbyte.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000733 pthread_attr_init(&attr);
734 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
735 {
736 pthread_attr_getstacksize(&attr, &size);
737 if (lim > (long)size)
738 lim = (long)size;
739 }
740 pthread_attr_destroy(&attr);
741 }
742#endif
743 if (stack_grows_downwards)
744 {
745 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
746 if (stack_limit >= (char *)&i)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100747 // overflow, set to 1/16 of current stack position
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 stack_limit = (char *)((long)&i / 16L);
749 }
750 else
751 {
752 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
753 if (stack_limit <= (char *)&i)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100754 stack_limit = NULL; // overflow
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755 }
756 }
757}
758
759/*
760 * Return FAIL when running out of stack space.
761 * "p" must point to any variable local to the caller that's on the stack.
762 */
763 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100764mch_stackcheck(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765{
766 if (stack_limit != NULL)
767 {
768 if (stack_grows_downwards)
769 {
770 if (p < stack_limit)
771 return FAIL;
772 }
773 else if (p > stack_limit)
774 return FAIL;
775 }
776 return OK;
777}
778#endif
779
780#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
781/*
782 * Support for using the signal stack.
783 * This helps when we run out of stack space, which causes a SIGSEGV. The
784 * signal handler then must run on another stack, since the normal stack is
785 * completely full.
786 */
787
Bram Moolenaar071d4272004-06-13 20:20:40 +0000788# ifdef HAVE_SIGALTSTACK
Bram Moolenaar0f873732019-12-05 20:28:46 +0100789static stack_t sigstk; // for sigaltstack()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790# else
Bram Moolenaar0f873732019-12-05 20:28:46 +0100791static struct sigstack sigstk; // for sigstack()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792# endif
793
Zdenek Dohnalba9c23e2021-08-11 14:20:05 +0200794/*
795 * Get a size of signal stack.
796 * Preference (if available): sysconf > SIGSTKSZ > guessed size
797 */
798static long int get_signal_stack_size()
799{
800# ifdef HAVE_SYSCONF_SIGSTKSZ
801 long int size = -1;
802
803 // return size only if sysconf doesn't return an error
804 if ((size = sysconf(_SC_SIGSTKSZ)) > -1)
805 return size;
806# endif
807
808# ifdef SIGSTKSZ
809 // if sysconf() isn't available or gives error, return SIGSTKSZ
810 // if defined
811 return SIGSTKSZ;
812# endif
813
814 // otherwise guess the size
815 return 8000;
816}
817
Bram Moolenaar071d4272004-06-13 20:20:40 +0000818static char *signal_stack;
819
820 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100821init_signal_stack(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822{
823 if (signal_stack != NULL)
824 {
825# ifdef HAVE_SIGALTSTACK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826# ifdef HAVE_SS_BASE
827 sigstk.ss_base = signal_stack;
828# else
829 sigstk.ss_sp = signal_stack;
830# endif
Zdenek Dohnalba9c23e2021-08-11 14:20:05 +0200831 sigstk.ss_size = get_signal_stack_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832 sigstk.ss_flags = 0;
833 (void)sigaltstack(&sigstk, NULL);
834# else
835 sigstk.ss_sp = signal_stack;
836 if (stack_grows_downwards)
Zdenek Dohnalba9c23e2021-08-11 14:20:05 +0200837 sigstk.ss_sp += get_signal_stack_size() - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838 sigstk.ss_onstack = 0;
839 (void)sigstack(&sigstk, NULL);
840# endif
841 }
842}
843#endif
844
845/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000846 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847 * will barf when the second argument to signal() is ``wrong''.
848 * Let me try it with a few tricky defines from my own osdef.h (jw).
849 */
850#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000851 static RETSIGTYPE
852sig_winch SIGDEFARG(sigarg)
853{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100854 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
856 do_resize = TRUE;
857 SIGRETURN;
858}
859#endif
860
dbivolaruab16ad32021-12-29 19:41:47 +0000861#if defined(SIGTSTP)
862 static RETSIGTYPE
863sig_tstp SIGDEFARG(sigarg)
864{
865 // Second time we get called we actually need to suspend
866 if (in_mch_suspend)
867 {
868 signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL);
869 raise(sigarg);
870 }
871
872 // this is not required on all systems, but it doesn't hurt anybody
873 signal(SIGTSTP, (RETSIGTYPE (*)())sig_tstp);
874 got_tstp = TRUE;
875 SIGRETURN;
876}
877#endif
878
Bram Moolenaar071d4272004-06-13 20:20:40 +0000879#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 static RETSIGTYPE
881catch_sigint SIGDEFARG(sigarg)
882{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100883 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
885 got_int = TRUE;
886 SIGRETURN;
887}
888#endif
889
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200890#if defined(SIGUSR1)
891 static RETSIGTYPE
892catch_sigusr1 SIGDEFARG(sigarg)
893{
894 // this is not required on all systems, but it doesn't hurt anybody
895 signal(SIGUSR1, (RETSIGTYPE (*)())catch_sigusr1);
896 got_sigusr1 = TRUE;
897 SIGRETURN;
898}
899#endif
900
Bram Moolenaar071d4272004-06-13 20:20:40 +0000901#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902 static RETSIGTYPE
903catch_sigpwr SIGDEFARG(sigarg)
904{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100905 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000906 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907 /*
908 * I'm not sure we get the SIGPWR signal when the system is really going
909 * down or when the batteries are almost empty. Just preserve the swap
910 * files and don't exit, that can't do any harm.
911 */
912 ml_sync_all(FALSE, FALSE);
913 SIGRETURN;
914}
915#endif
916
917#ifdef SET_SIG_ALARM
918/*
919 * signal function for alarm().
920 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000921 static RETSIGTYPE
922sig_alarm SIGDEFARG(sigarg)
923{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100924 // doesn't do anything, just to break a system call
Bram Moolenaar071d4272004-06-13 20:20:40 +0000925 sig_alarm_called = TRUE;
926 SIGRETURN;
927}
928#endif
929
Bram Moolenaaredce7422019-01-20 18:39:30 +0100930#if (defined(HAVE_SETJMP_H) \
931 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
932 || defined(FEAT_LIBCALL))) \
933 || defined(PROTO)
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100934# define USING_SETJMP 1
Bram Moolenaaredce7422019-01-20 18:39:30 +0100935
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100936// argument to SETJMP()
937static JMP_BUF lc_jump_env;
938
939# ifdef SIGHASARG
Bram Moolenaar32aa1022019-11-02 22:54:41 +0100940// Caught signal number, 0 when no signal was caught; used for mch_libcall().
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100941// Volatile because it is used in signal handlers.
942static volatile sig_atomic_t lc_signal;
943# endif
944
945// TRUE when lc_jump_env is valid.
946// Volatile because it is used in signal handler deathtrap().
947static volatile sig_atomic_t lc_active INIT(= FALSE);
948
Bram Moolenaar071d4272004-06-13 20:20:40 +0000949/*
950 * A simplistic version of setjmp() that only allows one level of using.
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100951 * Used to protect areas where we could crash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952 * Don't call twice before calling mch_endjmp()!.
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100953 *
Bram Moolenaar071d4272004-06-13 20:20:40 +0000954 * Usage:
955 * mch_startjmp();
956 * if (SETJMP(lc_jump_env) != 0)
957 * {
958 * mch_didjmp();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100959 * emsg("crash!");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000960 * }
961 * else
962 * {
963 * do_the_work;
964 * mch_endjmp();
965 * }
966 * Note: Can't move SETJMP() here, because a function calling setjmp() must
967 * not return before the saved environment is used.
968 * Returns OK for normal return, FAIL when the protected code caused a
969 * problem and LONGJMP() was used.
970 */
Bram Moolenaar113e1072019-01-20 15:30:40 +0100971 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100972mch_startjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000973{
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100974# ifdef SIGHASARG
Bram Moolenaar071d4272004-06-13 20:20:40 +0000975 lc_signal = 0;
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100976# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000977 lc_active = TRUE;
978}
979
Bram Moolenaar113e1072019-01-20 15:30:40 +0100980 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100981mch_endjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000982{
983 lc_active = FALSE;
984}
985
Bram Moolenaar113e1072019-01-20 15:30:40 +0100986 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100987mch_didjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988{
989# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100990 // On FreeBSD the signal stack has to be reset after using siglongjmp(),
991 // otherwise catching the signal only works once.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000992 init_signal_stack();
993# endif
994}
995#endif
996
997/*
998 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200999 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001000 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001001 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
1002 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001003 */
1004 static RETSIGTYPE
1005deathtrap SIGDEFARG(sigarg)
1006{
Bram Moolenaar0f873732019-12-05 20:28:46 +01001007 static int entered = 0; // count the number of times we got here.
1008 // Note: when memory has been corrupted
1009 // this may get an arbitrary value!
Bram Moolenaar071d4272004-06-13 20:20:40 +00001010#ifdef SIGHASARG
1011 int i;
1012#endif
1013
Bram Moolenaarb2148f52019-01-20 23:43:57 +01001014#if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001015 /*
1016 * Catch a crash in protected code.
1017 * Restores the environment saved in lc_jump_env, which looks like
1018 * SETJMP() returns 1.
1019 */
1020 if (lc_active)
1021 {
1022# if defined(SIGHASARG)
1023 lc_signal = sigarg;
1024# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01001025 lc_active = FALSE; // don't jump again
Bram Moolenaar071d4272004-06-13 20:20:40 +00001026 LONGJMP(lc_jump_env, 1);
Bram Moolenaar0f873732019-12-05 20:28:46 +01001027 // NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +00001028 }
1029#endif
1030
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001031#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +00001032# ifdef SIGQUIT
Bram Moolenaar0f873732019-12-05 20:28:46 +01001033 // While in mch_delay() we go to cooked mode to allow a CTRL-C to
1034 // interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
1035 // pressing CTRL-\, but we don't want Vim to exit then.
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +00001036 if (in_mch_delay && sigarg == SIGQUIT)
1037 SIGRETURN;
1038# endif
1039
Bram Moolenaar0f873732019-12-05 20:28:46 +01001040 // When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
1041 // here. This avoids that a non-reentrant function is interrupted, e.g.,
1042 // free(). Calling free() again may then cause a crash.
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001043 if (entered == 0
1044 && (0
1045# ifdef SIGHUP
1046 || sigarg == SIGHUP
1047# endif
1048# ifdef SIGQUIT
1049 || sigarg == SIGQUIT
1050# endif
1051# ifdef SIGTERM
1052 || sigarg == SIGTERM
1053# endif
1054# ifdef SIGPWR
1055 || sigarg == SIGPWR
1056# endif
1057# ifdef SIGUSR1
1058 || sigarg == SIGUSR1
1059# endif
1060# ifdef SIGUSR2
1061 || sigarg == SIGUSR2
1062# endif
1063 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001064 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001065 SIGRETURN;
1066#endif
1067
Bram Moolenaar0f873732019-12-05 20:28:46 +01001068 // Remember how often we have been called.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069 ++entered;
1070
Bram Moolenaar0f873732019-12-05 20:28:46 +01001071 // Executing autocommands is likely to use more stack space than we have
1072 // available in the signal stack.
Bram Moolenaare429e702016-06-10 19:49:14 +02001073 block_autocmds();
Bram Moolenaare429e702016-06-10 19:49:14 +02001074
Bram Moolenaar071d4272004-06-13 20:20:40 +00001075#ifdef FEAT_EVAL
Bram Moolenaar0f873732019-12-05 20:28:46 +01001076 // Set the v:dying variable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001077 set_vim_var_nr(VV_DYING, (long)entered);
1078#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001079 v_dying = entered;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001080
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001081#ifdef HAVE_STACK_LIMIT
Bram Moolenaar0f873732019-12-05 20:28:46 +01001082 // Since we are now using the signal stack, need to reset the stack
1083 // limit. Otherwise using a regexp will fail.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001084 get_stack_limit();
1085#endif
1086
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001087#if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01001088 // This is for opening gdb the moment Vim crashes.
1089 // You need to manually adjust the file name and Vim executable name.
1090 // Suggested by SungHyun Nam.
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001091 {
1092# define VI_GDB_FILE "/tmp/vimgdb"
1093# define VIM_NAME "/usr/bin/vim"
1094 FILE *fp = fopen(VI_GDB_FILE, "w");
1095 if (fp)
1096 {
1097 fprintf(fp,
1098 "file %s\n"
1099 "attach %d\n"
1100 "set height 1000\n"
1101 "bt full\n"
1102 , VIM_NAME, getpid());
1103 fclose(fp);
1104 system("xterm -e gdb -x "VI_GDB_FILE);
1105 unlink(VI_GDB_FILE);
1106 }
1107 }
1108#endif
1109
Bram Moolenaar071d4272004-06-13 20:20:40 +00001110#ifdef SIGHASARG
Bram Moolenaar0f873732019-12-05 20:28:46 +01001111 // try to find the name of this signal
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 for (i = 0; signal_info[i].sig != -1; i++)
1113 if (sigarg == signal_info[i].sig)
1114 break;
1115 deadly_signal = sigarg;
1116#endif
1117
Bram Moolenaar0f873732019-12-05 20:28:46 +01001118 full_screen = FALSE; // don't write message to the GUI, it might be
1119 // part of the problem...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001120 /*
1121 * If something goes wrong after entering here, we may get here again.
1122 * When this happens, give a message and try to exit nicely (resetting the
1123 * terminal mode, etc.)
1124 * When this happens twice, just exit, don't even try to give a message,
1125 * stack may be corrupt or something weird.
1126 * When this still happens again (or memory was corrupted in such a way
1127 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1128 */
1129 if (entered >= 3)
1130 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001131 reset_signals(); // don't catch any signals anymore
Bram Moolenaar071d4272004-06-13 20:20:40 +00001132 may_core_dump();
1133 if (entered >= 4)
1134 _exit(8);
1135 exit(7);
1136 }
1137 if (entered == 2)
1138 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001139 // No translation, it may call malloc().
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001140 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001141 out_flush();
1142 getout(1);
1143 }
1144
Bram Moolenaar0f873732019-12-05 20:28:46 +01001145 // No translation, it may call malloc().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146#ifdef SIGHASARG
Bram Moolenaar69212b12020-05-10 14:14:03 +02001147 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\r\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001148 signal_info[i].name);
1149#else
Bram Moolenaar69212b12020-05-10 14:14:03 +02001150 sprintf((char *)IObuff, "Vim: Caught deadly signal\r\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001151#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001152
Bram Moolenaar0f873732019-12-05 20:28:46 +01001153 // Preserve files and exit. This sets the really_exiting flag to prevent
1154 // calling free().
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001155 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001156
Bram Moolenaar0f873732019-12-05 20:28:46 +01001157 // NOTREACHED
Bram Moolenaare429e702016-06-10 19:49:14 +02001158
Bram Moolenaar009b2592004-10-24 19:18:58 +00001159#ifdef NBDEBUG
1160 reset_signals();
1161 may_core_dump();
1162 abort();
1163#endif
1164
Bram Moolenaar071d4272004-06-13 20:20:40 +00001165 SIGRETURN;
1166}
1167
Bram Moolenaar071d4272004-06-13 20:20:40 +00001168/*
Bram Moolenaar2e310482018-08-21 13:09:10 +02001169 * Invoked after receiving SIGCONT. We don't know what happened while
1170 * sleeping, deal with part of that.
1171 */
1172 static void
1173after_sigcont(void)
1174{
Bram Moolenaar2e310482018-08-21 13:09:10 +02001175 // Don't change "oldtitle" in a signal handler, set a flag to obtain it
1176 // again later.
1177 oldtitle_outdated = TRUE;
Bram Moolenaar651fca82021-11-29 20:39:38 +00001178
Bram Moolenaar2e310482018-08-21 13:09:10 +02001179 settmode(TMODE_RAW);
1180 need_check_timestamps = TRUE;
1181 did_check_timestamps = FALSE;
1182}
1183
1184#if defined(SIGCONT)
1185static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001186
1187/*
1188 * With multi-threading, suspending might not work immediately. Catch the
1189 * SIGCONT signal, which will be used as an indication whether the suspending
1190 * has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001191 *
1192 * On Linux, signal is not always handled immediately either.
1193 * See https://bugs.launchpad.net/bugs/291373
Bram Moolenaar2e310482018-08-21 13:09:10 +02001194 * Probably because the signal is handled in another thread.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001195 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001196 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001197 */
Bram Moolenaar8e82c052018-08-21 19:47:48 +02001198static volatile sig_atomic_t sigcont_received;
Bram Moolenaarf1883472018-08-20 21:58:57 +02001199static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001200
1201/*
1202 * signal handler for SIGCONT
1203 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204 static RETSIGTYPE
1205sigcont_handler SIGDEFARG(sigarg)
1206{
Bram Moolenaar2e310482018-08-21 13:09:10 +02001207 if (in_mch_suspend)
1208 {
1209 sigcont_received = TRUE;
1210 }
1211 else
1212 {
1213 // We didn't suspend ourselves, assume we were stopped by a SIGSTOP
1214 // signal (which can't be intercepted) and get a SIGCONT. Need to get
1215 // back to a sane mode. We should redraw, but we can't really do that
1216 // in a signal handler, do a redraw later.
1217 after_sigcont();
1218 redraw_later(CLEAR);
1219 cursor_on_force();
1220 out_flush();
1221 }
1222
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223 SIGRETURN;
1224}
1225#endif
1226
Bram Moolenaar6dff58f2018-09-30 21:43:26 +02001227#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001228# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001229static void *clip_star_save = NULL;
1230static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001231# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001232
1233/*
1234 * Called when Vim is going to sleep or execute a shell command.
1235 * We can't respond to requests for the X selections. Lose them, otherwise
1236 * other applications will hang. But first copy the text to cut buffer 0.
1237 */
1238 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001239loose_clipboard(void)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001240{
1241 if (clip_star.owned || clip_plus.owned)
1242 {
1243 x11_export_final_selection();
1244 if (clip_star.owned)
1245 clip_lose_selection(&clip_star);
1246 if (clip_plus.owned)
1247 clip_lose_selection(&clip_plus);
1248 if (x11_display != NULL)
1249 XFlush(x11_display);
1250 }
1251}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001252
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001253# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001254/*
1255 * Save clipboard text to restore later.
1256 */
1257 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001258save_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001259{
1260 if (clip_star.owned)
1261 clip_star_save = get_register('*', TRUE);
1262 if (clip_plus.owned)
1263 clip_plus_save = get_register('+', TRUE);
1264}
1265
1266/*
1267 * Restore clipboard text if no one own the X selection.
1268 */
1269 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001270restore_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001271{
1272 if (clip_star_save != NULL)
1273 {
1274 if (!clip_gen_owner_exists(&clip_star))
1275 put_register('*', clip_star_save);
1276 else
1277 free_register(clip_star_save);
1278 clip_star_save = NULL;
1279 }
1280 if (clip_plus_save != NULL)
1281 {
1282 if (!clip_gen_owner_exists(&clip_plus))
1283 put_register('+', clip_plus_save);
1284 else
1285 free_register(clip_plus_save);
1286 clip_plus_save = NULL;
1287 }
1288}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001289# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001290#endif
1291
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292/*
1293 * If the machine has job control, use it to suspend the program,
1294 * otherwise fake it by starting a new shell.
1295 */
1296 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001297mch_suspend(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001298{
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001299 if (ignore_sigtstp)
1300 return;
1301
Bram Moolenaar041c7102020-05-30 18:14:57 +02001302#if defined(SIGTSTP)
Bram Moolenaar2e310482018-08-21 13:09:10 +02001303 in_mch_suspend = TRUE;
1304
Bram Moolenaar0f873732019-12-05 20:28:46 +01001305 out_flush(); // needed to make cursor visible on some systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00001306 settmode(TMODE_COOK);
Bram Moolenaar0f873732019-12-05 20:28:46 +01001307 out_flush(); // needed to disable mouse on some systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308
1309# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001310 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001311# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001312# if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313 sigcont_received = FALSE;
1314# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001315
Bram Moolenaar0f873732019-12-05 20:28:46 +01001316 kill(0, SIGTSTP); // send ourselves a STOP signal
Bram Moolenaar2e310482018-08-21 13:09:10 +02001317
1318# if defined(SIGCONT)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001319 /*
1320 * Wait for the SIGCONT signal to be handled. It generally happens
Bram Moolenaar2e310482018-08-21 13:09:10 +02001321 * immediately, but somehow not all the time, probably because it's handled
1322 * in another thread. Do not call pause() because there would be race
1323 * condition which would hang Vim if signal happened in between the test of
1324 * sigcont_received and the call to pause(). If signal is not yet received,
1325 * sleep 0, 1, 2, 3 ms. Don't bother waiting further if signal is not
1326 * received after 1+2+3 ms (not expected to happen).
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001327 */
1328 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001329 long wait_time;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001330
Bram Moolenaar262735e2009-07-14 10:20:22 +00001331 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar0981c872020-08-23 14:28:37 +02001332 mch_delay(wait_time, 0);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001333 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001334# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001335 in_mch_suspend = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001336
Bram Moolenaar2e310482018-08-21 13:09:10 +02001337 after_sigcont();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001338#else
1339 suspend_shell();
1340#endif
1341}
1342
1343 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001344mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001345{
1346 Columns = 80;
1347 Rows = 24;
1348
1349 out_flush();
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001350
1351#ifdef SIGTSTP
1352 // Check whether we were invoked with SIGTSTP set to be ignored. If it is
1353 // that indicates the shell (or program) that launched us does not support
1354 // tty job control and thus we should ignore that signal. If invoked as a
1355 // restricted editor (e.g., as "rvim") SIGTSTP is always ignored.
1356 ignore_sigtstp = restricted || SIG_IGN == signal(SIGTSTP, SIG_ERR);
1357#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001358 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001359
Bram Moolenaar56718732006-03-15 22:53:57 +00001360#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001361 mac_conv_init();
1362#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001363#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1364 win_clip_init();
1365#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001366}
1367
1368 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001369set_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001370{
1371#if defined(SIGWINCH)
1372 /*
1373 * WINDOW CHANGE signal is handled with sig_winch().
1374 */
1375 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1376#endif
1377
Bram Moolenaar071d4272004-06-13 20:20:40 +00001378#ifdef SIGTSTP
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001379 // See mch_init() for the conditions under which we ignore SIGTSTP.
dbivolaruab16ad32021-12-29 19:41:47 +00001380 signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : (RETSIGTYPE (*)())sig_tstp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001381#endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001382#if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383 signal(SIGCONT, sigcont_handler);
1384#endif
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001385#ifdef SIGPIPE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001386 /*
1387 * We want to ignore breaking of PIPEs.
1388 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001389 signal(SIGPIPE, SIG_IGN);
1390#endif
1391
Bram Moolenaar071d4272004-06-13 20:20:40 +00001392#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001393 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001394#endif
1395
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001396#ifdef SIGUSR1
1397 /*
1398 * Call user's handler on SIGUSR1
1399 */
1400 signal(SIGUSR1, (RETSIGTYPE (*)())catch_sigusr1);
1401#endif
1402
Bram Moolenaar071d4272004-06-13 20:20:40 +00001403 /*
1404 * Ignore alarm signals (Perl's alarm() generates it).
1405 */
1406#ifdef SIGALRM
1407 signal(SIGALRM, SIG_IGN);
1408#endif
1409
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001410#ifdef SIGPWR
Bram Moolenaar071d4272004-06-13 20:20:40 +00001411 /*
1412 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1413 * work will be lost.
1414 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001415 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1416#endif
1417
1418 /*
1419 * Arrange for other signals to gracefully shutdown Vim.
1420 */
1421 catch_signals(deathtrap, SIG_ERR);
1422
1423#if defined(FEAT_GUI) && defined(SIGHUP)
1424 /*
1425 * When the GUI is running, ignore the hangup signal.
1426 */
1427 if (gui.in_use)
1428 signal(SIGHUP, SIG_IGN);
1429#endif
1430}
1431
Bram Moolenaardf177f62005-02-22 08:39:57 +00001432#if defined(SIGINT) || defined(PROTO)
1433/*
1434 * Catch CTRL-C (only works while in Cooked mode).
1435 */
1436 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001437catch_int_signal(void)
Bram Moolenaardf177f62005-02-22 08:39:57 +00001438{
1439 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1440}
1441#endif
1442
Bram Moolenaar071d4272004-06-13 20:20:40 +00001443 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001444reset_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001445{
1446 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar2e310482018-08-21 13:09:10 +02001447#if defined(SIGCONT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001448 // SIGCONT isn't in the list, because its default action is ignore
Bram Moolenaar071d4272004-06-13 20:20:40 +00001449 signal(SIGCONT, SIG_DFL);
1450#endif
1451}
1452
1453 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001454catch_signals(
1455 RETSIGTYPE (*func_deadly)(),
1456 RETSIGTYPE (*func_other)())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001457{
1458 int i;
1459
1460 for (i = 0; signal_info[i].sig != -1; i++)
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001461 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001462 if (signal_info[i].deadly)
1463 {
1464#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1465 struct sigaction sa;
1466
Bram Moolenaar0f873732019-12-05 20:28:46 +01001467 // Setup to use the alternate stack for the signal function.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001468 sa.sa_handler = func_deadly;
1469 sigemptyset(&sa.sa_mask);
1470# if defined(__linux__) && defined(_REENTRANT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001471 // On Linux, with glibc compiled for kernel 2.2, there is a bug in
1472 // thread handling in combination with using the alternate stack:
1473 // pthread library functions try to use the stack pointer to
1474 // identify the current thread, causing a SEGV signal, which
1475 // recursively calls deathtrap() and hangs.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001476 sa.sa_flags = 0;
1477# else
1478 sa.sa_flags = SA_ONSTACK;
1479# endif
1480 sigaction(signal_info[i].sig, &sa, NULL);
1481#else
1482# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1483 struct sigvec sv;
1484
Bram Moolenaar0f873732019-12-05 20:28:46 +01001485 // Setup to use the alternate stack for the signal function.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001486 sv.sv_handler = func_deadly;
1487 sv.sv_mask = 0;
1488 sv.sv_flags = SV_ONSTACK;
1489 sigvec(signal_info[i].sig, &sv, NULL);
1490# else
1491 signal(signal_info[i].sig, func_deadly);
1492# endif
1493#endif
1494 }
1495 else if (func_other != SIG_ERR)
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001496 {
1497 // Deal with non-deadly signals.
1498#ifdef SIGTSTP
1499 signal(signal_info[i].sig,
1500 signal_info[i].sig == SIGTSTP && ignore_sigtstp
1501 ? SIG_IGN : func_other);
1502#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001503 signal(signal_info[i].sig, func_other);
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001504#endif
1505 }
1506 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001507}
1508
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001509#ifdef HAVE_SIGPROCMASK
1510 static void
1511block_signals(sigset_t *set)
1512{
1513 sigset_t newset;
1514 int i;
1515
1516 sigemptyset(&newset);
1517
1518 for (i = 0; signal_info[i].sig != -1; i++)
1519 sigaddset(&newset, signal_info[i].sig);
1520
Bram Moolenaar2e310482018-08-21 13:09:10 +02001521# if defined(SIGCONT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001522 // SIGCONT isn't in the list, because its default action is ignore
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001523 sigaddset(&newset, SIGCONT);
1524# endif
1525
1526 sigprocmask(SIG_BLOCK, &newset, set);
1527}
1528
1529 static void
1530unblock_signals(sigset_t *set)
1531{
1532 sigprocmask(SIG_SETMASK, set, NULL);
1533}
1534#endif
1535
Bram Moolenaar071d4272004-06-13 20:20:40 +00001536/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001537 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001538 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1539 * return TRUE
1540 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1541 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001542 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001543 * Returns TRUE when Vim should exit.
1544 */
1545 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001546vim_handle_signal(int sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001547{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001548 static int got_signal = 0;
1549 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001550
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001551 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001552 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001553 case SIGNAL_BLOCK: blocked = TRUE;
1554 break;
1555
1556 case SIGNAL_UNBLOCK: blocked = FALSE;
1557 if (got_signal != 0)
1558 {
1559 kill(getpid(), got_signal);
1560 got_signal = 0;
1561 }
1562 break;
1563
1564 default: if (!blocked)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001565 return TRUE; // exit!
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001566 got_signal = sig;
1567#ifdef SIGPWR
1568 if (sig != SIGPWR)
1569#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01001570 got_int = TRUE; // break any loops
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001571 break;
1572 }
1573 return FALSE;
1574}
1575
1576/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001577 * Check_win checks whether we have an interactive stdout.
1578 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001579 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001580mch_check_win(int argc UNUSED, char **argv UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001581{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001582 if (isatty(1))
1583 return OK;
1584 return FAIL;
1585}
1586
1587/*
1588 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1589 */
1590 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001591mch_input_isatty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001592{
1593 if (isatty(read_cmd_fd))
1594 return TRUE;
1595 return FALSE;
1596}
1597
1598#ifdef FEAT_X11
1599
Bram Moolenaar651fca82021-11-29 20:39:38 +00001600# if defined(ELAPSED_TIMEVAL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001601
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602/*
1603 * Give a message about the elapsed time for opening the X window.
1604 */
1605 static void
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001606xopen_message(long elapsed_msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001607{
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001608 smsg(_("Opening the X display took %ld msec"), elapsed_msec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001609}
1610# endif
1611#endif
1612
Bram Moolenaar651fca82021-11-29 20:39:38 +00001613#if defined(FEAT_X11)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001614/*
1615 * A few functions shared by X11 title and clipboard code.
1616 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617
1618static int got_x_error = FALSE;
1619
1620/*
1621 * X Error handler, otherwise X just exits! (very rude) -- webb
1622 */
1623 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001624x_error_handler(Display *dpy, XErrorEvent *error_event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001625{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001626 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001627 STRCAT(IObuff, _("\nVim: Got X error\n"));
1628
Bram Moolenaarb1062eb2020-05-09 16:11:33 +02001629 // In the GUI we cannot print a message and continue, because no X calls
1630 // are allowed here (causes my system to hang). Silently continuing seems
1631 // like the best alternative. Do preserve files, in case we crash.
1632 ml_sync_all(FALSE, FALSE);
1633
1634#ifdef FEAT_GUI
1635 if (!gui.in_use)
1636#endif
1637 msg((char *)IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001638
Bram Moolenaar0f873732019-12-05 20:28:46 +01001639 return 0; // NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +00001640}
1641
1642/*
1643 * Another X Error handler, just used to check for errors.
1644 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001645 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001646x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001647{
1648 got_x_error = TRUE;
1649 return 0;
1650}
1651
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001652/*
1653 * Return TRUE when connection to the X server is desired.
1654 */
1655 static int
1656x_connect_to_server(void)
1657{
1658 // No point in connecting if we are exiting or dying.
1659 if (exiting || v_dying)
1660 return FALSE;
1661
1662#if defined(FEAT_CLIENTSERVER)
1663 if (x_force_connect)
1664 return TRUE;
1665#endif
1666 if (x_no_connect)
1667 return FALSE;
1668
Bram Moolenaara8bfa172018-12-29 22:28:46 +01001669 // Check for a match with "exclude:" from 'clipboard'.
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001670 if (clip_exclude_prog != NULL)
1671 {
Bram Moolenaara8bfa172018-12-29 22:28:46 +01001672 // Just in case we get called recursively, return FALSE. This could
1673 // happen if vpeekc() is used while executing the prog and it causes a
1674 // related callback to be invoked.
1675 if (regprog_in_use(clip_exclude_prog))
1676 return FALSE;
1677
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001678 if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
1679 return FALSE;
1680 }
1681 return TRUE;
1682}
1683
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaarb2148f52019-01-20 23:43:57 +01001685# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686/*
1687 * An X IO Error handler, used to catch error while opening the display.
1688 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001689 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001690x_IOerror_check(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001691{
Bram Moolenaar0f873732019-12-05 20:28:46 +01001692 // This function should not return, it causes exit(). Longjump instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001693 LONGJMP(lc_jump_env, 1);
Bram Moolenaar1eed5322019-02-26 17:03:54 +01001694# if defined(VMS) || defined(__CYGWIN__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001695 return 0; // avoid the compiler complains about missing return value
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001696# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697}
1698# endif
1699
1700/*
1701 * An X IO Error handler, used to catch terminal errors.
1702 */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001703static int xterm_dpy_retry_count = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001704
Bram Moolenaar071d4272004-06-13 20:20:40 +00001705 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001706x_IOerror_handler(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001707{
1708 xterm_dpy = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001709 xterm_dpy_retry_count = 5; // Try reconnecting five times
Bram Moolenaar071d4272004-06-13 20:20:40 +00001710 x11_window = 0;
1711 x11_display = NULL;
1712 xterm_Shell = (Widget)0;
1713
Bram Moolenaar0f873732019-12-05 20:28:46 +01001714 // This function should not return, it causes exit(). Longjump instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001715 LONGJMP(x_jump_env, 1);
Bram Moolenaar1eed5322019-02-26 17:03:54 +01001716# if defined(VMS) || defined(__CYGWIN__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001717 return 0; // avoid the compiler complains about missing return value
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001718# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719}
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001720
1721/*
1722 * If the X11 connection was lost try to restore it.
1723 * Helps when the X11 server was stopped and restarted while Vim was inactive
Bram Moolenaarcaad4f02014-12-17 14:36:14 +01001724 * (e.g. through tmux).
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001725 */
1726 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001727may_restore_clipboard(void)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001728{
Bram Moolenaar01e51e52018-12-29 13:09:46 +01001729 // No point in restoring the connecting if we are exiting or dying.
1730 if (!exiting && !v_dying && xterm_dpy_retry_count > 0)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001731 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001732 --xterm_dpy_retry_count;
Bram Moolenaar527a6782014-12-17 17:59:31 +01001733
1734# ifndef LESSTIF_VERSION
Bram Moolenaar0f873732019-12-05 20:28:46 +01001735 // This has been reported to avoid Vim getting stuck.
Bram Moolenaar527a6782014-12-17 17:59:31 +01001736 if (app_context != (XtAppContext)NULL)
1737 {
1738 XtDestroyApplicationContext(app_context);
1739 app_context = (XtAppContext)NULL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01001740 x11_display = NULL; // freed by XtDestroyApplicationContext()
Bram Moolenaar527a6782014-12-17 17:59:31 +01001741 }
1742# endif
1743
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001744 setup_term_clip();
1745 get_x11_title(FALSE);
1746 }
1747}
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001748
1749 void
1750ex_xrestore(exarg_T *eap)
1751{
1752 if (eap->arg != NULL && STRLEN(eap->arg) > 0)
1753 {
1754 if (xterm_display_allocated)
1755 vim_free(xterm_display);
1756 xterm_display = (char *)vim_strsave(eap->arg);
1757 xterm_display_allocated = TRUE;
1758 }
1759 smsg(_("restoring display %s"), xterm_display == NULL
Bram Moolenaar0c5c3fa2019-11-30 22:38:16 +01001760 ? (char *)mch_getenv((char_u *)"DISPLAY") : xterm_display);
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001761
1762 clear_xterm_clip();
1763 x11_window = 0;
1764 xterm_dpy_retry_count = 5; // Try reconnecting five times
1765 may_restore_clipboard();
1766}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767#endif
1768
1769/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001770 * Test if "dpy" and x11_window are valid by getting the window title.
1771 * I don't actually want it yet, so there may be a simpler call to use, but
1772 * this will cause the error handler x_error_check() to be called if anything
1773 * is wrong, such as the window pointer being invalid (as can happen when the
1774 * user changes his DISPLAY, but not his WINDOWID) -- webb
1775 */
1776 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001777test_x11_window(Display *dpy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001778{
1779 int (*old_handler)();
1780 XTextProperty text_prop;
1781
1782 old_handler = XSetErrorHandler(x_error_check);
1783 got_x_error = FALSE;
1784 if (XGetWMName(dpy, x11_window, &text_prop))
1785 XFree((void *)text_prop.value);
1786 XSync(dpy, False);
1787 (void)XSetErrorHandler(old_handler);
1788
1789 if (p_verbose > 0 && got_x_error)
Bram Moolenaar32526b32019-01-19 17:43:09 +01001790 verb_msg(_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791
1792 return (got_x_error ? FAIL : OK);
1793}
1794#endif
1795
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796
1797#ifdef FEAT_X11
1798
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001799static int get_x11_thing(int get_title, int test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001800
1801/*
1802 * try to get x11 window and display
1803 *
1804 * return FAIL for failure, OK otherwise
1805 */
1806 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001807get_x11_windis(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808{
1809 char *winid;
1810 static int result = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01001811#define XD_NONE 0 // x11_display not set here
1812#define XD_HERE 1 // x11_display opened here
1813#define XD_GUI 2 // x11_display used from gui.dpy
1814#define XD_XTERM 3 // x11_display used from xterm_dpy
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815 static int x11_display_from = XD_NONE;
1816 static int did_set_error_handler = FALSE;
1817
1818 if (!did_set_error_handler)
1819 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001820 // X just exits if it finds an error otherwise!
Bram Moolenaar071d4272004-06-13 20:20:40 +00001821 (void)XSetErrorHandler(x_error_handler);
1822 did_set_error_handler = TRUE;
1823 }
1824
Bram Moolenaar9372a112005-12-06 19:59:18 +00001825#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826 if (gui.in_use)
1827 {
1828 /*
1829 * If the X11 display was opened here before, for the window where Vim
1830 * was started, close that one now to avoid a memory leak.
1831 */
1832 if (x11_display_from == XD_HERE && x11_display != NULL)
1833 {
1834 XCloseDisplay(x11_display);
1835 x11_display_from = XD_NONE;
1836 }
1837 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1838 {
1839 x11_display_from = XD_GUI;
1840 return OK;
1841 }
1842 x11_display = NULL;
1843 return FAIL;
1844 }
1845 else if (x11_display_from == XD_GUI)
1846 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001847 // GUI must have stopped somehow, clear x11_display
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848 x11_window = 0;
1849 x11_display = NULL;
1850 x11_display_from = XD_NONE;
1851 }
1852#endif
1853
Bram Moolenaar0f873732019-12-05 20:28:46 +01001854 // When started with the "-X" argument, don't try connecting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001855 if (!x_connect_to_server())
1856 return FAIL;
1857
1858 /*
1859 * If WINDOWID not set, should try another method to find out
1860 * what the current window number is. The only code I know for
1861 * this is very complicated.
1862 * We assume that zero is invalid for WINDOWID.
1863 */
1864 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1865 x11_window = (Window)atol(winid);
1866
1867#ifdef FEAT_XCLIPBOARD
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001868 if (xterm_dpy == x11_display)
1869 // x11_display may have been set to xterm_dpy elsewhere
1870 x11_display_from = XD_XTERM;
1871
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872 if (xterm_dpy != NULL && x11_window != 0)
1873 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001874 // We may have checked it already, but Gnome terminal can move us to
1875 // another window, so we need to check every time.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001876 if (x11_display_from != XD_XTERM)
1877 {
1878 /*
1879 * If the X11 display was opened here before, for the window where
1880 * Vim was started, close that one now to avoid a memory leak.
1881 */
1882 if (x11_display_from == XD_HERE && x11_display != NULL)
1883 XCloseDisplay(x11_display);
1884 x11_display = xterm_dpy;
1885 x11_display_from = XD_XTERM;
1886 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887 if (test_x11_window(x11_display) == FAIL)
1888 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001889 // probably bad $WINDOWID
Bram Moolenaar071d4272004-06-13 20:20:40 +00001890 x11_window = 0;
1891 x11_display = NULL;
1892 x11_display_from = XD_NONE;
1893 return FAIL;
1894 }
1895 return OK;
1896 }
1897#endif
1898
1899 if (x11_window == 0 || x11_display == NULL)
1900 result = -1;
1901
Bram Moolenaar0f873732019-12-05 20:28:46 +01001902 if (result != -1) // Have already been here and set this
1903 return result; // Don't do all these X calls again
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904
1905 if (x11_window != 0 && x11_display == NULL)
1906 {
1907#ifdef SET_SIG_ALARM
1908 RETSIGTYPE (*sig_save)();
1909#endif
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01001910#ifdef ELAPSED_FUNC
1911 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912
1913 if (p_verbose > 0)
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01001914 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001915#endif
1916
1917#ifdef SET_SIG_ALARM
1918 /*
1919 * Opening the Display may hang if the DISPLAY setting is wrong, or
1920 * the network connection is bad. Set an alarm timer to get out.
1921 */
1922 sig_alarm_called = FALSE;
1923 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1924 (RETSIGTYPE (*)())sig_alarm);
1925 alarm(2);
1926#endif
1927 x11_display = XOpenDisplay(NULL);
1928
1929#ifdef SET_SIG_ALARM
1930 alarm(0);
1931 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1932 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaar563bbea2019-01-22 21:45:40 +01001933 verb_msg(_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934#endif
1935 if (x11_display != NULL)
1936 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001937# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001939 {
1940 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001941 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001942 verbose_leave();
1943 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944# endif
1945 if (test_x11_window(x11_display) == FAIL)
1946 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001947 // Maybe window id is bad
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 x11_window = 0;
1949 XCloseDisplay(x11_display);
1950 x11_display = NULL;
1951 }
1952 else
1953 x11_display_from = XD_HERE;
1954 }
1955 }
1956 if (x11_window == 0 || x11_display == NULL)
1957 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001958
1959# ifdef FEAT_EVAL
1960 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1961# endif
1962
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963 return (result = OK);
1964}
1965
1966/*
1967 * Determine original x11 Window Title
1968 */
1969 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001970get_x11_title(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001972 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001973}
1974
1975/*
1976 * Determine original x11 Window icon
1977 */
1978 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001979get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001980{
1981 int retval = FALSE;
1982
1983 retval = get_x11_thing(FALSE, test_only);
1984
Bram Moolenaar0f873732019-12-05 20:28:46 +01001985 // could not get old icon, use terminal name
Bram Moolenaar071d4272004-06-13 20:20:40 +00001986 if (oldicon == NULL && !test_only)
1987 {
1988 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001989 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001990 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001991 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992 }
1993
1994 return retval;
1995}
1996
1997 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001998get_x11_thing(
Bram Moolenaar0f873732019-12-05 20:28:46 +01001999 int get_title, // get title string
Bram Moolenaar05540972016-01-30 20:31:25 +01002000 int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002001{
2002 XTextProperty text_prop;
2003 int retval = FALSE;
2004 Status status;
2005
2006 if (get_x11_windis() == OK)
2007 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002008 // Get window/icon name if any
Bram Moolenaar071d4272004-06-13 20:20:40 +00002009 if (get_title)
2010 status = XGetWMName(x11_display, x11_window, &text_prop);
2011 else
2012 status = XGetWMIconName(x11_display, x11_window, &text_prop);
2013
2014 /*
2015 * If terminal is xterm, then x11_window may be a child window of the
2016 * outer xterm window that actually contains the window/icon name, so
2017 * keep traversing up the tree until a window with a title/icon is
2018 * found.
2019 */
Bram Moolenaar4b96df52020-01-26 22:00:26 +01002020 // Previously this was only done for xterm and alike. I don't see a
Bram Moolenaar0f873732019-12-05 20:28:46 +01002021 // reason why it would fail for other terminal emulators.
2022 // if (term_is_xterm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023 {
2024 Window root;
2025 Window parent;
2026 Window win = x11_window;
2027 Window *children;
2028 unsigned int num_children;
2029
2030 while (!status || text_prop.value == NULL)
2031 {
2032 if (!XQueryTree(x11_display, win, &root, &parent, &children,
2033 &num_children))
2034 break;
2035 if (children)
2036 XFree((void *)children);
2037 if (parent == root || parent == 0)
2038 break;
2039
2040 win = parent;
2041 if (get_title)
2042 status = XGetWMName(x11_display, win, &text_prop);
2043 else
2044 status = XGetWMIconName(x11_display, win, &text_prop);
2045 }
2046 }
2047 if (status && text_prop.value != NULL)
2048 {
2049 retval = TRUE;
2050 if (!test_only)
2051 {
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002052 if (get_title)
2053 vim_free(oldtitle);
2054 else
2055 vim_free(oldicon);
Bram Moolenaara12a1612019-01-24 16:39:02 +01002056 if (text_prop.encoding == XA_STRING && !has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002058 if (get_title)
2059 oldtitle = vim_strsave((char_u *)text_prop.value);
2060 else
2061 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002062 }
2063 else
2064 {
2065 char **cl;
2066 Status transform_status;
2067 int n = 0;
2068
2069 transform_status = XmbTextPropertyToTextList(x11_display,
2070 &text_prop,
2071 &cl, &n);
2072 if (transform_status >= Success && n > 0 && cl[0])
2073 {
2074 if (get_title)
2075 oldtitle = vim_strsave((char_u *) cl[0]);
2076 else
2077 oldicon = vim_strsave((char_u *) cl[0]);
2078 XFreeStringList(cl);
2079 }
2080 else
2081 {
2082 if (get_title)
2083 oldtitle = vim_strsave((char_u *)text_prop.value);
2084 else
2085 oldicon = vim_strsave((char_u *)text_prop.value);
2086 }
2087 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088 }
2089 XFree((void *)text_prop.value);
2090 }
2091 }
2092 return retval;
2093}
2094
Bram Moolenaar0f873732019-12-05 20:28:46 +01002095// Xutf8 functions are not available on older systems. Note that on some
2096// systems X_HAVE_UTF8_STRING may be defined in a header file but
2097// Xutf8SetWMProperties() is not in the X11 library. Configure checks for
2098// that and defines HAVE_XUTF8SETWMPROPERTIES.
Bram Moolenaara12a1612019-01-24 16:39:02 +01002099#if defined(X_HAVE_UTF8_STRING)
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002100# if X_HAVE_UTF8_STRING && HAVE_XUTF8SETWMPROPERTIES
Bram Moolenaar071d4272004-06-13 20:20:40 +00002101# define USE_UTF8_STRING
2102# endif
2103#endif
2104
2105/*
2106 * Set x11 Window Title
2107 *
2108 * get_x11_windis() must be called before this and have returned OK
2109 */
2110 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002111set_x11_title(char_u *title)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112{
Bram Moolenaar0f873732019-12-05 20:28:46 +01002113 // XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
2114 // when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
2115 // supported everywhere and STRING doesn't work for multi-byte titles.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116#ifdef USE_UTF8_STRING
2117 if (enc_utf8)
2118 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
2119 NULL, NULL, 0, NULL, NULL, NULL);
2120 else
2121#endif
2122 {
2123#if XtSpecificationRelease >= 4
2124# ifdef FEAT_XFONTSET
2125 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
2126 NULL, NULL, 0, NULL, NULL, NULL);
2127# else
2128 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002129 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002130
Bram Moolenaar0f873732019-12-05 20:28:46 +01002131 // directly from example 3-18 "basicwin" of Xlib Programming Manual
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002132 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002133 XSetWMProperties(x11_display, x11_window, &text_prop,
2134 NULL, NULL, 0, NULL, NULL, NULL);
2135# endif
2136#else
2137 XStoreName(x11_display, x11_window, (char *)title);
2138#endif
2139 }
2140 XFlush(x11_display);
2141}
2142
2143/*
2144 * Set x11 Window icon
2145 *
2146 * get_x11_windis() must be called before this and have returned OK
2147 */
2148 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002149set_x11_icon(char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002150{
Bram Moolenaar0f873732019-12-05 20:28:46 +01002151 // See above for comments about using X*SetWMProperties().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002152#ifdef USE_UTF8_STRING
2153 if (enc_utf8)
2154 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2155 NULL, 0, NULL, NULL, NULL);
2156 else
2157#endif
2158 {
2159#if XtSpecificationRelease >= 4
2160# ifdef FEAT_XFONTSET
2161 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2162 NULL, 0, NULL, NULL, NULL);
2163# else
2164 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002165 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002166
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002167 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002168 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2169 NULL, 0, NULL, NULL, NULL);
2170# endif
2171#else
2172 XSetIconName(x11_display, x11_window, (char *)icon);
2173#endif
2174 }
2175 XFlush(x11_display);
2176}
2177
Bram Moolenaar0f873732019-12-05 20:28:46 +01002178#else // FEAT_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002179
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002181get_x11_title(int test_only UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002182{
2183 return FALSE;
2184}
2185
2186 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002187get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002188{
2189 if (!test_only)
2190 {
2191 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002192 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002193 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002194 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002195 }
2196 return FALSE;
2197}
2198
Bram Moolenaar0f873732019-12-05 20:28:46 +01002199#endif // FEAT_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200
2201 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002202mch_can_restore_title(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002203{
2204 return get_x11_title(TRUE);
2205}
2206
2207 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002208mch_can_restore_icon(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002209{
2210 return get_x11_icon(TRUE);
2211}
2212
2213/*
2214 * Set the window title and icon.
2215 */
2216 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002217mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002218{
2219 int type = 0;
2220 static int recursive = 0;
2221
Bram Moolenaar0f873732019-12-05 20:28:46 +01002222 if (T_NAME == NULL) // no terminal name (yet)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002223 return;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002224 if (title == NULL && icon == NULL) // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00002225 return;
2226
Bram Moolenaar0f873732019-12-05 20:28:46 +01002227 // When one of the X11 functions causes a deadly signal, we get here again
2228 // recursively. Avoid hanging then (something is probably locked).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002229 if (recursive)
2230 return;
2231 ++recursive;
2232
2233 /*
2234 * if the window ID and the display is known, we may use X11 calls
2235 */
2236#ifdef FEAT_X11
2237 if (get_x11_windis() == OK)
2238 type = 1;
2239#else
Bram Moolenaar097148e2020-08-11 21:58:20 +02002240# if defined(FEAT_GUI_PHOTON) \
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002241 || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002242 if (gui.in_use)
2243 type = 1;
2244# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002245#endif
2246
2247 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002248 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249 * than x11 calls, because the x11 calls don't always work
2250 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002251 if ((type || *T_TS != NUL) && title != NULL)
2252 {
Bram Moolenaard8f0cef2018-08-19 22:20:16 +02002253 if (oldtitle_outdated)
2254 {
2255 oldtitle_outdated = FALSE;
2256 VIM_CLEAR(oldtitle);
2257 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002258 if (oldtitle == NULL
2259#ifdef FEAT_GUI
2260 && !gui.in_use
2261#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002262 ) // first call but not in GUI, save title
Bram Moolenaar071d4272004-06-13 20:20:40 +00002263 (void)get_x11_title(FALSE);
2264
Bram Moolenaar0f873732019-12-05 20:28:46 +01002265 if (*T_TS != NUL) // it's OK if t_fs is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 term_settitle(title);
2267#ifdef FEAT_X11
2268 else
2269# ifdef FEAT_GUI_GTK
Bram Moolenaar0f873732019-12-05 20:28:46 +01002270 if (!gui.in_use) // don't do this if GTK+ is running
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002272 set_x11_title(title); // x11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002273#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002274#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) \
Bram Moolenaar097148e2020-08-11 21:58:20 +02002275 || defined(FEAT_GUI_PHOTON)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 else
2277 gui_mch_settitle(title, icon);
2278#endif
Bram Moolenaardac13472019-09-16 21:06:21 +02002279 unix_did_set_title = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002280 }
2281
2282 if ((type || *T_CIS != NUL) && icon != NULL)
2283 {
2284 if (oldicon == NULL
2285#ifdef FEAT_GUI
2286 && !gui.in_use
2287#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002288 ) // first call, save icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002289 get_x11_icon(FALSE);
2290
2291 if (*T_CIS != NUL)
2292 {
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02002293 out_str(T_CIS); // set icon start
Bram Moolenaar071d4272004-06-13 20:20:40 +00002294 out_str_nf(icon);
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02002295 out_str(T_CIE); // set icon end
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296 out_flush();
2297 }
2298#ifdef FEAT_X11
2299 else
2300# ifdef FEAT_GUI_GTK
Bram Moolenaar0f873732019-12-05 20:28:46 +01002301 if (!gui.in_use) // don't do this if GTK+ is running
Bram Moolenaar071d4272004-06-13 20:20:40 +00002302# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002303 set_x11_icon(icon); // x11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002304#endif
2305 did_set_icon = TRUE;
2306 }
2307 --recursive;
2308}
2309
2310/*
2311 * Restore the window/icon title.
2312 * "which" is one of:
Bram Moolenaar40385db2018-08-07 22:31:44 +02002313 * SAVE_RESTORE_TITLE only restore title
2314 * SAVE_RESTORE_ICON only restore icon
2315 * SAVE_RESTORE_BOTH restore title and icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002316 */
2317 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002318mch_restore_title(int which)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319{
Bram Moolenaardac13472019-09-16 21:06:21 +02002320 int do_push_pop = unix_did_set_title || did_set_icon;
Bram Moolenaare5c83282019-05-03 23:15:37 +02002321
Bram Moolenaar0f873732019-12-05 20:28:46 +01002322 // only restore the title or icon when it has been set
Bram Moolenaardac13472019-09-16 21:06:21 +02002323 mch_settitle(((which & SAVE_RESTORE_TITLE) && unix_did_set_title) ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324 (oldtitle ? oldtitle : p_titleold) : NULL,
Bram Moolenaar40385db2018-08-07 22:31:44 +02002325 ((which & SAVE_RESTORE_ICON) && did_set_icon) ? oldicon : NULL);
2326
Bram Moolenaare5c83282019-05-03 23:15:37 +02002327 if (do_push_pop)
2328 {
2329 // pop and push from/to the stack
2330 term_pop_title(which);
2331 term_push_title(which);
2332 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333}
2334
Bram Moolenaar071d4272004-06-13 20:20:40 +00002335
2336/*
2337 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002338 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339 */
2340 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002341vim_is_xterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342{
2343 if (name == NULL)
2344 return FALSE;
2345 return (STRNICMP(name, "xterm", 5) == 0
2346 || STRNICMP(name, "nxterm", 6) == 0
2347 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002348 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349 || STRNICMP(name, "rxvt", 4) == 0
Bram Moolenaar995e4af2017-09-01 20:24:03 +02002350 || STRNICMP(name, "screen.xterm", 12) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002351 || STRCMP(name, "builtin_xterm") == 0);
2352}
2353
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002354#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2355/*
2356 * Return TRUE if "name" appears to be that of a terminal
2357 * known to support the xterm-style mouse protocol.
2358 * Relies on term_is_xterm having been set to its correct value.
2359 */
2360 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002361use_xterm_like_mouse(char_u *name)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002362{
2363 return (name != NULL
Bram Moolenaare56132b2016-08-14 18:23:21 +02002364 && (term_is_xterm
2365 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002366 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaar48873ae2021-12-08 21:00:24 +00002367 || STRNICMP(name, "gnome", 5) == 0
Bram Moolenaare56132b2016-08-14 18:23:21 +02002368 || STRICMP(name, "st") == 0
2369 || STRNICMP(name, "st-", 3) == 0
2370 || STRNICMP(name, "stterm", 6) == 0));
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002371}
2372#endif
2373
Bram Moolenaar071d4272004-06-13 20:20:40 +00002374/*
2375 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2376 * Return 1 for "xterm".
2377 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002378 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002379 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002380 */
2381 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002382use_xterm_mouse(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002384 if (ttym_flags == TTYM_SGR)
2385 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002386 if (ttym_flags == TTYM_URXVT)
2387 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 if (ttym_flags == TTYM_XTERM2)
2389 return 2;
2390 if (ttym_flags == TTYM_XTERM)
2391 return 1;
2392 return 0;
2393}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394
2395 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002396vim_is_iris(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002397{
2398 if (name == NULL)
2399 return FALSE;
2400 return (STRNICMP(name, "iris-ansi", 9) == 0
2401 || STRCMP(name, "builtin_iris-ansi") == 0);
2402}
2403
2404 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002405vim_is_vt300(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002406{
2407 if (name == NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01002408 return FALSE; // actually all ANSI comp. terminals should be here
2409 // catch VT100 - VT5xx
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002410 return ((STRNICMP(name, "vt", 2) == 0
2411 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002412 || STRCMP(name, "builtin_vt320") == 0);
2413}
2414
2415/*
2416 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2417 * This should include all windowed terminal emulators.
2418 */
2419 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002420vim_is_fastterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002421{
2422 if (name == NULL)
2423 return FALSE;
2424 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2425 return TRUE;
2426 return ( STRNICMP(name, "hpterm", 6) == 0
2427 || STRNICMP(name, "sun-cmd", 7) == 0
2428 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002429 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002430 || STRNICMP(name, "dtterm", 6) == 0);
2431}
2432
2433/*
2434 * Insert user name in s[len].
2435 * Return OK if a name found.
2436 */
2437 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002438mch_get_user_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439{
2440#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002441 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002442 return OK;
2443#else
2444 return mch_get_uname(getuid(), s, len);
2445#endif
2446}
2447
2448/*
2449 * Insert user name for "uid" in s[len].
2450 * Return OK if a name found.
2451 */
2452 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002453mch_get_uname(uid_t uid, char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454{
2455#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2456 struct passwd *pw;
2457
2458 if ((pw = getpwuid(uid)) != NULL
2459 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2460 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002461 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002462 return OK;
2463 }
2464#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002465 sprintf((char *)s, "%d", (int)uid); // assumes s is long enough
2466 return FAIL; // a number is not a name
Bram Moolenaar071d4272004-06-13 20:20:40 +00002467}
2468
2469/*
2470 * Insert host name is s[len].
2471 */
2472
2473#ifdef HAVE_SYS_UTSNAME_H
2474 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002475mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002476{
2477 struct utsname vutsname;
2478
2479 if (uname(&vutsname) < 0)
2480 *s = NUL;
2481 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002482 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002483}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002484#else // HAVE_SYS_UTSNAME_H
Bram Moolenaar071d4272004-06-13 20:20:40 +00002485
2486# ifdef HAVE_SYS_SYSTEMINFO_H
2487# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2488# endif
2489
2490 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002491mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002492{
2493# ifdef VAXC
2494 vaxc$gethostname((char *)s, len);
2495# else
2496 gethostname((char *)s, len);
2497# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002498 s[len - 1] = NUL; // make sure it's terminated
Bram Moolenaar071d4272004-06-13 20:20:40 +00002499}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002500#endif // HAVE_SYS_UTSNAME_H
Bram Moolenaar071d4272004-06-13 20:20:40 +00002501
2502/*
2503 * return process ID
2504 */
2505 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002506mch_get_pid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507{
2508 return (long)getpid();
2509}
2510
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002511/*
2512 * return TRUE if process "pid" is still running
2513 */
2514 int
Bram Moolenaar1b243ea2019-04-28 22:50:40 +02002515mch_process_running(long pid)
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002516{
Bram Moolenaar44dea9d2021-06-23 21:13:20 +02002517 // If there is no error the process must be running.
2518 if (kill(pid, 0) == 0)
2519 return TRUE;
2520#ifdef ESRCH
2521 // If the error is ESRCH then the process is not running.
2522 if (errno == ESRCH)
2523 return FALSE;
2524#endif
2525 // If the process is running and owned by another user we get EPERM. With
2526 // other errors the process might be running, assuming it is then.
2527 return TRUE;
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002528}
2529
Bram Moolenaar071d4272004-06-13 20:20:40 +00002530#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531 static char *
Bram Moolenaar05540972016-01-30 20:31:25 +01002532strerror(int err)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002533{
2534 extern int sys_nerr;
2535 extern char *sys_errlist[];
2536 static char er[20];
2537
2538 if (err > 0 && err < sys_nerr)
2539 return (sys_errlist[err]);
2540 sprintf(er, "Error %d", err);
2541 return er;
2542}
2543#endif
2544
2545/*
Bram Moolenaar964b3742019-05-24 18:54:09 +02002546 * Get name of current directory into buffer "buf" of length "len" bytes.
2547 * "len" must be at least PATH_MAX.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548 * Return OK for success, FAIL for failure.
2549 */
2550 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002551mch_dirname(char_u *buf, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002552{
2553#if defined(USE_GETCWD)
2554 if (getcwd((char *)buf, len) == NULL)
2555 {
2556 STRCPY(buf, strerror(errno));
2557 return FAIL;
2558 }
2559 return OK;
2560#else
2561 return (getwd((char *)buf) != NULL ? OK : FAIL);
2562#endif
2563}
2564
Bram Moolenaar071d4272004-06-13 20:20:40 +00002565/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002566 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002567 *
2568 * return FAIL for failure, OK for success
2569 */
2570 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002571mch_FullName(
2572 char_u *fname,
2573 char_u *buf,
2574 int len,
Bram Moolenaar0f873732019-12-05 20:28:46 +01002575 int force) // also expand when already absolute path
Bram Moolenaar071d4272004-06-13 20:20:40 +00002576{
2577 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002578#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002579 int fd = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002580 static int dont_fchdir = FALSE; // TRUE when fchdir() doesn't work
Bram Moolenaar38323e42007-03-06 19:22:53 +00002581#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002582 char_u olddir[MAXPATHL];
2583 char_u *p;
2584 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002585#ifdef __CYGWIN__
Bram Moolenaar0f873732019-12-05 20:28:46 +01002586 char_u posix_fname[MAXPATHL]; // Cygwin docs mention MAX_PATH, but
2587 // it's not always defined
Bram Moolenaarbf820722008-06-21 11:12:49 +00002588#endif
2589
Bram Moolenaar38323e42007-03-06 19:22:53 +00002590#ifdef VMS
2591 fname = vms_fixfilename(fname);
2592#endif
2593
Bram Moolenaara2442432007-04-26 14:26:37 +00002594#ifdef __CYGWIN__
2595 /*
2596 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2597 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002598# if CYGWIN_VERSION_DLL_MAJOR >= 1007
Bram Moolenaar0f873732019-12-05 20:28:46 +01002599 // Use CCP_RELATIVE to avoid that it sometimes returns a path that ends in
2600 // a forward slash.
Bram Moolenaar06b07342015-12-31 22:26:28 +01002601 cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE,
2602 fname, posix_fname, MAXPATHL);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002603# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002604 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002605# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002606 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002607#endif
2608
Bram Moolenaar0f873732019-12-05 20:28:46 +01002609 // Expand it if forced or not an absolute path.
2610 // Do not do it for "/file", the result is always "/".
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002611 if ((force || !mch_isFullName(fname))
2612 && ((p = vim_strrchr(fname, '/')) == NULL || p != fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002613 {
2614 /*
2615 * If the file name has a path, change to that directory for a moment,
Bram Moolenaar964b3742019-05-24 18:54:09 +02002616 * and then get the directory (and get back to where we were).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002617 * This will get the correct path name with "../" things.
2618 */
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002619 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620 {
Bram Moolenaar4eaef992021-08-30 21:26:16 +02002621 if (STRCMP(p, "/..") == 0)
2622 // for "/path/dir/.." include the "/.."
2623 p += 3;
2624
Bram Moolenaar38323e42007-03-06 19:22:53 +00002625#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 /*
2627 * Use fchdir() if possible, it's said to be faster and more
2628 * reliable. But on SunOS 4 it might not work. Check this by
2629 * doing a fchdir() right now.
2630 */
2631 if (!dont_fchdir)
2632 {
2633 fd = open(".", O_RDONLY | O_EXTRA, 0);
2634 if (fd >= 0 && fchdir(fd) < 0)
2635 {
2636 close(fd);
2637 fd = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002638 dont_fchdir = TRUE; // don't try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00002639 }
2640 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002641#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002642
Bram Moolenaar0f873732019-12-05 20:28:46 +01002643 // Only change directory when we are sure we can return to where
2644 // we are now. After doing "su" chdir(".") might not work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002645 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002646#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002647 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002648#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649 (mch_dirname(olddir, MAXPATHL) == FAIL
2650 || mch_chdir((char *)olddir) != 0))
2651 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002652 p = NULL; // can't get current dir: don't chdir
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653 retval = FAIL;
2654 }
2655 else
2656 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002657 // The directory is copied into buf[], to be able to remove
2658 // the file name without changing it (could be a string in
2659 // read-only memory)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002660 if (p - fname >= len)
2661 retval = FAIL;
2662 else
2663 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002664 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002665 if (mch_chdir((char *)buf))
Bram Moolenaarc6376c72021-10-03 19:29:48 +01002666 {
2667 // Path does not exist (yet). For a full path fail,
2668 // will use the path as-is. For a relative path use
2669 // the current directory and append the file name.
2670 if (mch_isFullName(fname))
2671 retval = FAIL;
2672 else
2673 p = NULL;
2674 }
Bram Moolenaar4eaef992021-08-30 21:26:16 +02002675 else if (*p == '/')
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676 fname = p + 1;
Bram Moolenaar4eaef992021-08-30 21:26:16 +02002677 else
2678 fname = p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679 *buf = NUL;
2680 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681 }
2682 }
2683 if (mch_dirname(buf, len) == FAIL)
2684 {
2685 retval = FAIL;
2686 *buf = NUL;
2687 }
2688 if (p != NULL)
2689 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002690#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002691 if (fd >= 0)
2692 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002693 if (p_verbose >= 5)
2694 {
2695 verbose_enter();
Bram Moolenaar32526b32019-01-19 17:43:09 +01002696 msg("fchdir() to previous dir");
Bram Moolenaar25724922009-07-14 15:38:41 +00002697 verbose_leave();
2698 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002699 l = fchdir(fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 }
2701 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002702#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002703 l = mch_chdir((char *)olddir);
2704 if (l != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002705 emsg(_(e_prev_dir));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002706 }
itchyny051a40c2021-10-20 10:00:05 +01002707#ifdef HAVE_FCHDIR
2708 if (fd >= 0)
2709 close(fd);
2710#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002711
2712 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002713 if (l >= len - 1)
Bram Moolenaar0f873732019-12-05 20:28:46 +01002714 retval = FAIL; // no space for trailing "/"
Bram Moolenaar38323e42007-03-06 19:22:53 +00002715#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002716 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002718 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002719#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002721
Bram Moolenaar0f873732019-12-05 20:28:46 +01002722 // Catch file names which are too long.
Bram Moolenaar78a15312009-05-15 19:33:18 +00002723 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 return FAIL;
2725
Bram Moolenaar0f873732019-12-05 20:28:46 +01002726 // Do not append ".", "/dir/." is equal to "/dir".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002727 if (STRCMP(fname, ".") != 0)
2728 STRCAT(buf, fname);
2729
2730 return OK;
2731}
2732
2733/*
2734 * Return TRUE if "fname" does not depend on the current directory.
2735 */
2736 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002737mch_isFullName(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002738{
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002739#ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002740 return ( fname[0] == '/' || fname[0] == '.' ||
2741 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2742 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2743 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002744#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745 return (*fname == '/' || *fname == '~');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746#endif
2747}
2748
Bram Moolenaar24552be2005-12-10 20:17:30 +00002749#if defined(USE_FNAME_CASE) || defined(PROTO)
2750/*
2751 * Set the case of the file name, if it already exists. This will cause the
2752 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002753 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002754 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002755 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002756fname_case(
2757 char_u *name,
Bram Moolenaar0f873732019-12-05 20:28:46 +01002758 int len UNUSED) // buffer size, only used when name gets longer
Bram Moolenaar24552be2005-12-10 20:17:30 +00002759{
2760 struct stat st;
2761 char_u *slash, *tail;
2762 DIR *dirp;
2763 struct dirent *dp;
2764
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002765 if (mch_lstat((char *)name, &st) >= 0)
Bram Moolenaar24552be2005-12-10 20:17:30 +00002766 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002767 // Open the directory where the file is located.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002768 slash = vim_strrchr(name, '/');
2769 if (slash == NULL)
2770 {
2771 dirp = opendir(".");
2772 tail = name;
2773 }
2774 else
2775 {
2776 *slash = NUL;
2777 dirp = opendir((char *)name);
2778 *slash = '/';
2779 tail = slash + 1;
2780 }
2781
2782 if (dirp != NULL)
2783 {
2784 while ((dp = readdir(dirp)) != NULL)
2785 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002786 // Only accept names that differ in case and are the same byte
2787 // length. TODO: accept different length name.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002788 if (STRICMP(tail, dp->d_name) == 0
2789 && STRLEN(tail) == STRLEN(dp->d_name))
2790 {
2791 char_u newname[MAXPATHL + 1];
2792 struct stat st2;
2793
Bram Moolenaar0f873732019-12-05 20:28:46 +01002794 // Verify the inode is equal.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002795 vim_strncpy(newname, name, MAXPATHL);
2796 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2797 MAXPATHL - (tail - name));
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002798 if (mch_lstat((char *)newname, &st2) >= 0
Bram Moolenaar24552be2005-12-10 20:17:30 +00002799 && st.st_ino == st2.st_ino
2800 && st.st_dev == st2.st_dev)
2801 {
2802 STRCPY(tail, dp->d_name);
2803 break;
2804 }
2805 }
2806 }
2807
2808 closedir(dirp);
2809 }
2810 }
2811}
2812#endif
2813
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814/*
2815 * Get file permissions for 'name'.
2816 * Returns -1 when it doesn't exist.
2817 */
2818 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002819mch_getperm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002820{
2821 struct stat statb;
2822
Bram Moolenaar0f873732019-12-05 20:28:46 +01002823 // Keep the #ifdef outside of stat(), it may be a macro.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002824#ifdef VMS
2825 if (stat((char *)vms_fixfilename(name), &statb))
2826#else
2827 if (stat((char *)name, &statb))
2828#endif
2829 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002830#ifdef __INTERIX
Bram Moolenaar0f873732019-12-05 20:28:46 +01002831 // The top bit makes the value negative, which means the file doesn't
2832 // exist. Remove the bit, we don't use it.
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002833 return statb.st_mode & ~S_ADDACE;
2834#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002835 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002836#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837}
2838
2839/*
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002840 * Set file permission for "name" to "perm".
2841 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002842 */
2843 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002844mch_setperm(char_u *name, long perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002845{
2846 return (chmod((char *)
2847#ifdef VMS
2848 vms_fixfilename(name),
2849#else
2850 name,
2851#endif
2852 (mode_t)perm) == 0 ? OK : FAIL);
2853}
2854
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002855#if defined(HAVE_FCHMOD) || defined(PROTO)
2856/*
2857 * Set file permission for open file "fd" to "perm".
2858 * Return FAIL for failure, OK otherwise.
2859 */
2860 int
2861mch_fsetperm(int fd, long perm)
2862{
2863 return (fchmod(fd, (mode_t)perm) == 0 ? OK : FAIL);
2864}
2865#endif
2866
Bram Moolenaar071d4272004-06-13 20:20:40 +00002867#if defined(HAVE_ACL) || defined(PROTO)
2868# ifdef HAVE_SYS_ACL_H
2869# include <sys/acl.h>
2870# endif
2871# ifdef HAVE_SYS_ACCESS_H
2872# include <sys/access.h>
2873# endif
2874
2875# ifdef HAVE_SOLARIS_ACL
2876typedef struct vim_acl_solaris_T {
2877 int acl_cnt;
2878 aclent_t *acl_entry;
2879} vim_acl_solaris_T;
2880# endif
2881
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002882#if defined(HAVE_SELINUX) || defined(PROTO)
2883/*
2884 * Copy security info from "from_file" to "to_file".
2885 */
2886 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002887mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002888{
2889 if (from_file == NULL)
2890 return;
2891
2892 if (selinux_enabled == -1)
2893 selinux_enabled = is_selinux_enabled();
2894
2895 if (selinux_enabled > 0)
2896 {
Bram Moolenaar89560232020-10-09 23:04:47 +02002897 // Use "char *" instead of "security_context_t" to avoid a deprecation
2898 // warning.
2899 char *from_context = NULL;
2900 char *to_context = NULL;
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002901
2902 if (getfilecon((char *)from_file, &from_context) < 0)
2903 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002904 // If the filesystem doesn't support extended attributes,
2905 // the original had no special security context and the
2906 // target cannot have one either.
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002907 if (errno == EOPNOTSUPP)
2908 return;
2909
Bram Moolenaar32526b32019-01-19 17:43:09 +01002910 msg_puts(_("\nCould not get security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002911 msg_outtrans(from_file);
2912 msg_putchar('\n');
2913 return;
2914 }
2915 if (getfilecon((char *)to_file, &to_context) < 0)
2916 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01002917 msg_puts(_("\nCould not get security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002918 msg_outtrans(to_file);
2919 msg_putchar('\n');
2920 freecon (from_context);
2921 return ;
2922 }
2923 if (strcmp(from_context, to_context) != 0)
2924 {
2925 if (setfilecon((char *)to_file, from_context) < 0)
2926 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01002927 msg_puts(_("\nCould not set security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002928 msg_outtrans(to_file);
2929 msg_putchar('\n');
2930 }
2931 }
2932 freecon(to_context);
2933 freecon(from_context);
2934 }
2935}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002936#endif // HAVE_SELINUX
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002937
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002938#if defined(HAVE_SMACK) && !defined(PROTO)
2939/*
2940 * Copy security info from "from_file" to "to_file".
2941 */
2942 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002943mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002944{
Bram Moolenaar62f167f2014-04-23 12:52:40 +02002945 static const char * const smack_copied_attributes[] =
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002946 {
2947 XATTR_NAME_SMACK,
2948 XATTR_NAME_SMACKEXEC,
2949 XATTR_NAME_SMACKMMAP
2950 };
2951
2952 char buffer[SMACK_LABEL_LEN];
2953 const char *name;
2954 int index;
2955 int ret;
2956 ssize_t size;
2957
2958 if (from_file == NULL)
2959 return;
2960
2961 for (index = 0 ; index < (int)(sizeof(smack_copied_attributes)
2962 / sizeof(smack_copied_attributes)[0]) ; index++)
2963 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002964 // get the name of the attribute to copy
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002965 name = smack_copied_attributes[index];
2966
Bram Moolenaar0f873732019-12-05 20:28:46 +01002967 // get the value of the attribute in buffer
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002968 size = getxattr((char*)from_file, name, buffer, sizeof(buffer));
2969 if (size >= 0)
2970 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002971 // copy the attribute value of buffer
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002972 ret = setxattr((char*)to_file, name, buffer, (size_t)size, 0);
2973 if (ret < 0)
2974 {
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002975 vim_snprintf((char *)IObuff, IOSIZE,
2976 _("Could not set security context %s for %s"),
2977 name, to_file);
2978 msg_outtrans(IObuff);
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002979 msg_putchar('\n');
2980 }
2981 }
2982 else
2983 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002984 // what reason of not having the attribute value?
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002985 switch (errno)
2986 {
2987 case ENOTSUP:
Bram Moolenaar0f873732019-12-05 20:28:46 +01002988 // extended attributes aren't supported or enabled
2989 // should a message be echoed? not sure...
2990 return; // leave because it isn't useful to continue
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002991
2992 case ERANGE:
2993 default:
Bram Moolenaar0f873732019-12-05 20:28:46 +01002994 // no enough size OR unexpected error
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002995 vim_snprintf((char *)IObuff, IOSIZE,
2996 _("Could not get security context %s for %s. Removing it!"),
2997 name, from_file);
Bram Moolenaar32526b32019-01-19 17:43:09 +01002998 msg_puts((char *)IObuff);
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002999 msg_putchar('\n');
Bram Moolenaar0f873732019-12-05 20:28:46 +01003000 // FALLTHROUGH to remove the attribute
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003001
3002 case ENODATA:
Bram Moolenaar0f873732019-12-05 20:28:46 +01003003 // no attribute of this name
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003004 ret = removexattr((char*)to_file, name);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003005 // Silently ignore errors, apparently this happens when
3006 // smack is not actually being used.
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003007 break;
3008 }
3009 }
3010 }
3011}
Bram Moolenaar0f873732019-12-05 20:28:46 +01003012#endif // HAVE_SMACK
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02003013
Bram Moolenaar071d4272004-06-13 20:20:40 +00003014/*
3015 * Return a pointer to the ACL of file "fname" in allocated memory.
3016 * Return NULL if the ACL is not available for whatever reason.
3017 */
3018 vim_acl_T
Bram Moolenaar05540972016-01-30 20:31:25 +01003019mch_get_acl(char_u *fname UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020{
3021 vim_acl_T ret = NULL;
3022#ifdef HAVE_POSIX_ACL
3023 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
3024#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003025#ifdef HAVE_SOLARIS_ZFS_ACL
3026 acl_t *aclent;
3027
3028 if (acl_get((char *)fname, 0, &aclent) < 0)
3029 return NULL;
3030 ret = (vim_acl_T)aclent;
3031#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003032#ifdef HAVE_SOLARIS_ACL
3033 vim_acl_solaris_T *aclent;
3034
3035 aclent = malloc(sizeof(vim_acl_solaris_T));
3036 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
3037 {
3038 free(aclent);
3039 return NULL;
3040 }
3041 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
3042 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
3043 {
3044 free(aclent->acl_entry);
3045 free(aclent);
3046 return NULL;
3047 }
3048 ret = (vim_acl_T)aclent;
3049#else
3050#if defined(HAVE_AIX_ACL)
3051 int aclsize;
3052 struct acl *aclent;
3053
3054 aclsize = sizeof(struct acl);
3055 aclent = malloc(aclsize);
3056 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
3057 {
3058 if (errno == ENOSPC)
3059 {
3060 aclsize = aclent->acl_len;
3061 aclent = realloc(aclent, aclsize);
3062 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
3063 {
3064 free(aclent);
3065 return NULL;
3066 }
3067 }
3068 else
3069 {
3070 free(aclent);
3071 return NULL;
3072 }
3073 }
3074 ret = (vim_acl_T)aclent;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003075#endif // HAVE_AIX_ACL
3076#endif // HAVE_SOLARIS_ACL
3077#endif // HAVE_SOLARIS_ZFS_ACL
3078#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003079 return ret;
3080}
3081
3082/*
3083 * Set the ACL of file "fname" to "acl" (unless it's NULL).
3084 */
3085 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003086mch_set_acl(char_u *fname UNUSED, vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003087{
3088 if (aclent == NULL)
3089 return;
3090#ifdef HAVE_POSIX_ACL
3091 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
3092#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003093#ifdef HAVE_SOLARIS_ZFS_ACL
3094 acl_set((char *)fname, (acl_t *)aclent);
3095#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003096#ifdef HAVE_SOLARIS_ACL
3097 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
3098 ((vim_acl_solaris_T *)aclent)->acl_entry);
3099#else
3100#ifdef HAVE_AIX_ACL
3101 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003102#endif // HAVE_AIX_ACL
3103#endif // HAVE_SOLARIS_ACL
3104#endif // HAVE_SOLARIS_ZFS_ACL
3105#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106}
3107
3108 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003109mch_free_acl(vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003110{
3111 if (aclent == NULL)
3112 return;
3113#ifdef HAVE_POSIX_ACL
3114 acl_free((acl_t)aclent);
3115#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003116#ifdef HAVE_SOLARIS_ZFS_ACL
3117 acl_free((acl_t *)aclent);
3118#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003119#ifdef HAVE_SOLARIS_ACL
3120 free(((vim_acl_solaris_T *)aclent)->acl_entry);
3121 free(aclent);
3122#else
3123#ifdef HAVE_AIX_ACL
3124 free(aclent);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003125#endif // HAVE_AIX_ACL
3126#endif // HAVE_SOLARIS_ACL
3127#endif // HAVE_SOLARIS_ZFS_ACL
3128#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003129}
3130#endif
3131
3132/*
3133 * Set hidden flag for "name".
3134 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003136mch_hide(char_u *name UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003137{
Bram Moolenaar0f873732019-12-05 20:28:46 +01003138 // can't hide a file
Bram Moolenaar071d4272004-06-13 20:20:40 +00003139}
3140
3141/*
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003142 * return TRUE if "name" is a directory or a symlink to a directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143 * return FALSE if "name" is not a directory
3144 * return FALSE for error
3145 */
3146 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003147mch_isdir(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003148{
3149 struct stat statb;
3150
Bram Moolenaar0f873732019-12-05 20:28:46 +01003151 if (*name == NUL) // Some stat()s don't flag "" as an error.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003152 return FALSE;
3153 if (stat((char *)name, &statb))
3154 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003155 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003156}
3157
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003158/*
3159 * return TRUE if "name" is a directory, NOT a symlink to a directory
3160 * return FALSE if "name" is not a directory
3161 * return FALSE for error
3162 */
3163 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003164mch_isrealdir(char_u *name)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003165{
3166 struct stat statb;
3167
Bram Moolenaar0f873732019-12-05 20:28:46 +01003168 if (*name == NUL) // Some stat()s don't flag "" as an error.
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003169 return FALSE;
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01003170 if (mch_lstat((char *)name, &statb))
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003171 return FALSE;
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003172 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003173}
3174
Bram Moolenaar071d4272004-06-13 20:20:40 +00003175/*
3176 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
3177 */
3178 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003179executable_file(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003180{
3181 struct stat st;
3182
3183 if (stat((char *)name, &st))
3184 return 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003185#ifdef VMS
Bram Moolenaar0f873732019-12-05 20:28:46 +01003186 // Like on Unix system file can have executable rights but not necessarily
3187 // be an executable, but on Unix is not a default for an ordinary file to
3188 // have an executable flag - on VMS it is in most cases.
3189 // Therefore, this check does not have any sense - let keep us to the
3190 // conventions instead:
3191 // *.COM and *.EXE files are the executables - the rest are not. This is
Dominique Pelleaf4a61a2021-12-27 17:21:41 +00003192 // not ideal but better than it was.
Bram Moolenaar206f0112014-03-12 16:51:55 +01003193 int vms_executable = 0;
3194 if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
3195 {
3196 if (strstr(vms_tolower((char*)name),".exe") != NULL
3197 || strstr(vms_tolower((char*)name),".com")!= NULL)
3198 vms_executable = 1;
3199 }
3200 return vms_executable;
3201#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003202 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003203#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204}
3205
3206/*
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01003207 * Return TRUE if "name" can be found in $PATH and executed, FALSE if not.
Bram Moolenaarb5971142015-03-21 17:32:19 +01003208 * If "use_path" is FALSE only check if "name" is executable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003209 * Return -1 if unknown.
3210 */
3211 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003212mch_can_exe(char_u *name, char_u **path, int use_path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213{
3214 char_u *buf;
3215 char_u *p, *e;
3216 int retval;
3217
Bram Moolenaar0f873732019-12-05 20:28:46 +01003218 // When "use_path" is false and if it's an absolute or relative path don't
3219 // need to use $PATH.
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003220 if (!use_path || gettail(name) != name)
Bram Moolenaar206f0112014-03-12 16:51:55 +01003221 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003222 // There must be a path separator, files in the current directory
3223 // can't be executed.
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003224 if ((use_path || gettail(name) != name) && executable_file(name))
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003225 {
3226 if (path != NULL)
3227 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003228 if (name[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003229 *path = FullName_save(name, TRUE);
3230 else
3231 *path = vim_strsave(name);
3232 }
3233 return TRUE;
3234 }
3235 return FALSE;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003236 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237
3238 p = (char_u *)getenv("PATH");
3239 if (p == NULL || *p == NUL)
3240 return -1;
Bram Moolenaar964b3742019-05-24 18:54:09 +02003241 buf = alloc(STRLEN(name) + STRLEN(p) + 2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003242 if (buf == NULL)
3243 return -1;
3244
3245 /*
3246 * Walk through all entries in $PATH to check if "name" exists there and
3247 * is an executable file.
3248 */
3249 for (;;)
3250 {
3251 e = (char_u *)strchr((char *)p, ':');
3252 if (e == NULL)
3253 e = p + STRLEN(p);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003254 if (e - p <= 1) // empty entry means current dir
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255 STRCPY(buf, "./");
3256 else
3257 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003258 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003259 add_pathsep(buf);
3260 }
3261 STRCAT(buf, name);
3262 retval = executable_file(buf);
3263 if (retval == 1)
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003264 {
3265 if (path != NULL)
3266 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003267 if (buf[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003268 *path = FullName_save(buf, TRUE);
3269 else
3270 *path = vim_strsave(buf);
3271 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272 break;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003273 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003274
3275 if (*e != ':')
3276 break;
3277 p = e + 1;
3278 }
3279
3280 vim_free(buf);
3281 return retval;
3282}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003283
3284/*
3285 * Check what "name" is:
3286 * NODE_NORMAL: file or directory (or doesn't exist)
3287 * NODE_WRITABLE: writable device, socket, fifo, etc.
3288 * NODE_OTHER: non-writable things
3289 */
3290 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003291mch_nodetype(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003292{
3293 struct stat st;
3294
3295 if (stat((char *)name, &st))
3296 return NODE_NORMAL;
3297 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3298 return NODE_NORMAL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003299 if (S_ISBLK(st.st_mode)) // block device isn't writable
Bram Moolenaar071d4272004-06-13 20:20:40 +00003300 return NODE_OTHER;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003301 // Everything else is writable?
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302 return NODE_WRITABLE;
3303}
3304
3305 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003306mch_early_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003307{
3308#ifdef HAVE_CHECK_STACK_GROWTH
3309 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003310
Bram Moolenaar071d4272004-06-13 20:20:40 +00003311 check_stack_growth((char *)&i);
3312
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003313# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314 get_stack_limit();
3315# endif
3316
3317#endif
3318
3319 /*
3320 * Setup an alternative stack for signals. Helps to catch signals when
3321 * running out of stack space.
3322 * Use of sigaltstack() is preferred, it's more portable.
3323 * Ignore any errors.
3324 */
3325#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Zdenek Dohnalba9c23e2021-08-11 14:20:05 +02003326 signal_stack = alloc(get_signal_stack_size());
Bram Moolenaar071d4272004-06-13 20:20:40 +00003327 init_signal_stack();
3328#endif
3329}
3330
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003331#if defined(EXITFREE) || defined(PROTO)
3332 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003333mch_free_mem(void)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003334{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003335# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3336 if (clip_star.owned)
3337 clip_lose_selection(&clip_star);
3338 if (clip_plus.owned)
3339 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003340# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003341# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003342 if (xterm_Shell != (Widget)0)
3343 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003344# ifndef LESSTIF_VERSION
Bram Moolenaar0f873732019-12-05 20:28:46 +01003345 // Lesstif crashes here, lose some memory
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003346 if (xterm_dpy != NULL)
3347 XtCloseDisplay(xterm_dpy);
3348 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003349 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003350 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003351# ifdef FEAT_X11
Bram Moolenaar0f873732019-12-05 20:28:46 +01003352 x11_display = NULL; // freed by XtDestroyApplicationContext()
Bram Moolenaare8208012008-06-20 09:59:25 +00003353# endif
3354 }
3355# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003356# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003357# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003358 if (x11_display != NULL
3359# ifdef FEAT_XCLIPBOARD
3360 && x11_display != xterm_dpy
3361# endif
3362 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003363 XCloseDisplay(x11_display);
3364# endif
3365# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaard23a8232018-02-10 18:45:26 +01003366 VIM_CLEAR(signal_stack);
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003367# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003368 vim_free(oldtitle);
3369 vim_free(oldicon);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003370}
3371#endif
3372
Bram Moolenaar071d4272004-06-13 20:20:40 +00003373/*
3374 * Output a newline when exiting.
3375 * Make sure the newline goes to the same stream as the text.
3376 */
3377 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003378exit_scroll(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003379{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003380 if (silent_mode)
3381 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003382 if (newline_on_exit || msg_didout)
3383 {
3384 if (msg_use_printf())
3385 {
3386 if (info_message)
3387 mch_msg("\n");
3388 else
3389 mch_errmsg("\r\n");
3390 }
3391 else
3392 out_char('\n');
3393 }
Bram Moolenaar7007e312021-03-27 12:11:33 +01003394 else if (!is_not_a_term())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003395 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003396 restore_cterm_colors(); // get original colors back
3397 msg_clr_eos_force(); // clear the rest of the display
3398 windgoto((int)Rows - 1, 0); // may have moved the cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00003399 }
3400}
3401
Bram Moolenaarb4151682020-05-11 22:13:28 +02003402#ifdef USE_GCOV_FLUSH
ichizokdee78e12021-12-09 21:08:01 +00003403# if (defined(__GNUC__) \
3404 && ((__GNUC__ == 11 && __GNUC_MINOR__ >= 1) || (__GNUC__ >= 12))) \
3405 || (defined(__clang__) && (__clang_major__ >= 12))
3406extern void __gcov_dump(void);
3407extern void __gcov_reset(void);
3408# define __gcov_flush() do { __gcov_dump(); __gcov_reset(); } while (0)
3409# else
3410extern void __gcov_flush(void);
3411# endif
Bram Moolenaarb4151682020-05-11 22:13:28 +02003412#endif
3413
Bram Moolenaar071d4272004-06-13 20:20:40 +00003414 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003415mch_exit(int r)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003416{
3417 exiting = TRUE;
3418
3419#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3420 x11_export_final_selection();
3421#endif
3422
3423#ifdef FEAT_GUI
3424 if (!gui.in_use)
3425#endif
3426 {
3427 settmode(TMODE_COOK);
Bram Moolenaar7007e312021-03-27 12:11:33 +01003428 if (!is_not_a_term())
3429 {
3430 // restore xterm title and icon name
3431 mch_restore_title(SAVE_RESTORE_BOTH);
3432 term_pop_title(SAVE_RESTORE_BOTH);
3433 }
Bram Moolenaar651fca82021-11-29 20:39:38 +00003434
Bram Moolenaar071d4272004-06-13 20:20:40 +00003435 /*
3436 * When t_ti is not empty but it doesn't cause swapping terminal
3437 * pages, need to output a newline when msg_didout is set. But when
3438 * t_ti does swap pages it should not go to the shell page. Do this
3439 * before stoptermcap().
3440 */
3441 if (swapping_screen() && !newline_on_exit)
3442 exit_scroll();
3443
Bram Moolenaar0f873732019-12-05 20:28:46 +01003444 // Stop termcap: May need to check for T_CRV response, which
3445 // requires RAW mode.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003446 stoptermcap();
3447
3448 /*
3449 * A newline is only required after a message in the alternate screen.
3450 * This is set to TRUE by wait_return().
3451 */
3452 if (!swapping_screen() || newline_on_exit)
3453 exit_scroll();
3454
Bram Moolenaar0f873732019-12-05 20:28:46 +01003455 // Cursor may have been switched off without calling starttermcap()
3456 // when doing "vim -u vimrc" and vimrc contains ":q".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003457 if (full_screen)
3458 cursor_on();
3459 }
3460 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01003461 ml_close_all(TRUE); // remove all memfiles
Bram Moolenaarb4151682020-05-11 22:13:28 +02003462
3463#ifdef USE_GCOV_FLUSH
3464 // Flush coverage info before possibly being killed by a deadly signal.
3465 __gcov_flush();
3466#endif
3467
Bram Moolenaar071d4272004-06-13 20:20:40 +00003468 may_core_dump();
3469#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471 gui_exit(r);
3472#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003473
Bram Moolenaar56718732006-03-15 22:53:57 +00003474#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003475 mac_conv_cleanup();
3476#endif
3477
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478#ifdef __QNX__
Bram Moolenaar0f873732019-12-05 20:28:46 +01003479 // A core dump won't be created if the signal handler
3480 // doesn't return, so we can't call exit()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003481 if (deadly_signal != 0)
3482 return;
3483#endif
3484
Bram Moolenaar009b2592004-10-24 19:18:58 +00003485#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003486 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003487#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003488
3489#ifdef EXITFREE
3490 free_all_mem();
3491#endif
3492
Bram Moolenaar071d4272004-06-13 20:20:40 +00003493 exit(r);
3494}
3495
3496 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003497may_core_dump(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498{
3499 if (deadly_signal != 0)
3500 {
3501 signal(deadly_signal, SIG_DFL);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003502 kill(getpid(), deadly_signal); // Die using the signal we caught
Bram Moolenaar071d4272004-06-13 20:20:40 +00003503 }
3504}
3505
3506#ifndef VMS
3507
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003508/*
3509 * Get the file descriptor to use for tty operations.
3510 */
3511 static int
3512get_tty_fd(int fd)
3513{
3514 int tty_fd = fd;
3515
3516#if defined(HAVE_SVR4_PTYS) && defined(SUN_SYSTEM)
3517 // On SunOS: Get the terminal parameters from "fd", or the slave device of
3518 // "fd" when it is a master device.
3519 if (mch_isatty(fd) > 1)
3520 {
3521 char *name;
3522
3523 name = ptsname(fd);
3524 if (name == NULL)
3525 return -1;
3526
3527 tty_fd = open(name, O_RDONLY | O_NOCTTY | O_EXTRA, 0);
3528 if (tty_fd < 0)
3529 return -1;
3530 }
3531#endif
3532 return tty_fd;
3533}
3534
3535 static int
3536mch_tcgetattr(int fd, void *term)
3537{
3538 int tty_fd;
3539 int retval = -1;
3540
3541 tty_fd = get_tty_fd(fd);
3542 if (tty_fd >= 0)
3543 {
3544#ifdef NEW_TTY_SYSTEM
3545# ifdef HAVE_TERMIOS_H
3546 retval = tcgetattr(tty_fd, (struct termios *)term);
3547# else
3548 retval = ioctl(tty_fd, TCGETA, (struct termio *)term);
3549# endif
3550#else
3551 // for "old" tty systems
3552 retval = ioctl(tty_fd, TIOCGETP, (struct sgttyb *)term);
3553#endif
3554 if (tty_fd != fd)
3555 close(tty_fd);
3556 }
3557 return retval;
3558}
3559
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560 void
Bram Moolenaar26e86442020-05-17 14:06:16 +02003561mch_settmode(tmode_T tmode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003562{
3563 static int first = TRUE;
3564
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003565#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003566# ifdef HAVE_TERMIOS_H
3567 static struct termios told;
3568 struct termios tnew;
3569# else
3570 static struct termio told;
3571 struct termio tnew;
3572# endif
3573
3574 if (first)
3575 {
3576 first = FALSE;
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003577 mch_tcgetattr(read_cmd_fd, &told);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578 }
3579
3580 tnew = told;
3581 if (tmode == TMODE_RAW)
3582 {
Bram Moolenaar041c7102020-05-30 18:14:57 +02003583 // ~ICRNL enables typing ^V^M
Bram Moolenaar928eec62020-05-31 13:09:47 +02003584 // ~IXON disables CTRL-S stopping output, so that it can be mapped.
3585 tnew.c_iflag &= ~(ICRNL | IXON);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
Bram Moolenaare3f915d2020-07-14 23:02:44 +02003587# if defined(IEXTEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01003588 | IEXTEN // IEXTEN enables typing ^V on SOLARIS
Bram Moolenaar071d4272004-06-13 20:20:40 +00003589# endif
3590 );
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003591# ifdef ONLCR
3592 // Don't map NL -> CR NL, we do it ourselves.
3593 // Also disable expanding tabs if possible.
3594# ifdef XTABS
3595 tnew.c_oflag &= ~(ONLCR | XTABS);
3596# else
3597# ifdef TAB3
3598 tnew.c_oflag &= ~(ONLCR | TAB3);
3599# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003600 tnew.c_oflag &= ~ONLCR;
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003601# endif
3602# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003603# endif
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003604 tnew.c_cc[VMIN] = 1; // return after 1 char
3605 tnew.c_cc[VTIME] = 0; // don't wait
Bram Moolenaar071d4272004-06-13 20:20:40 +00003606 }
3607 else if (tmode == TMODE_SLEEP)
Bram Moolenaar40de4562016-07-01 15:03:46 +02003608 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003609 // Also reset ICANON here, otherwise on Solaris select() won't see
3610 // typeahead characters.
Bram Moolenaar40de4562016-07-01 15:03:46 +02003611 tnew.c_lflag &= ~(ICANON | ECHO);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003612 tnew.c_cc[VMIN] = 1; // return after 1 char
3613 tnew.c_cc[VTIME] = 0; // don't wait
Bram Moolenaar40de4562016-07-01 15:03:46 +02003614 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003615
3616# if defined(HAVE_TERMIOS_H)
3617 {
3618 int n = 10;
3619
Bram Moolenaar0f873732019-12-05 20:28:46 +01003620 // A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3621 // few times.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003622 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3623 && errno == EINTR && n > 0)
3624 --n;
3625 }
3626# else
3627 ioctl(read_cmd_fd, TCSETA, &tnew);
3628# endif
3629
3630#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003631 /*
3632 * for "old" tty systems
3633 */
3634# ifndef TIOCSETN
Bram Moolenaar0f873732019-12-05 20:28:46 +01003635# define TIOCSETN TIOCSETP // for hpux 9.0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003636# endif
3637 static struct sgttyb ttybold;
3638 struct sgttyb ttybnew;
3639
3640 if (first)
3641 {
3642 first = FALSE;
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003643 mch_tcgetattr(read_cmd_fd, &ttybold);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003644 }
3645
3646 ttybnew = ttybold;
3647 if (tmode == TMODE_RAW)
3648 {
3649 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3650 ttybnew.sg_flags |= RAW;
3651 }
3652 else if (tmode == TMODE_SLEEP)
3653 ttybnew.sg_flags &= ~(ECHO);
3654 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3655#endif
Bram Moolenaar26e86442020-05-17 14:06:16 +02003656 mch_cur_tmode = tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003657}
3658
3659/*
3660 * Try to get the code for "t_kb" from the stty setting
3661 *
3662 * Even if termcap claims a backspace key, the user's setting *should*
3663 * prevail. stty knows more about reality than termcap does, and if
3664 * somebody's usual erase key is DEL (which, for most BSD users, it will
3665 * be), they're going to get really annoyed if their erase key starts
3666 * doing forward deletes for no reason. (Eric Fischer)
3667 */
3668 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003669get_stty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003670{
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003671 ttyinfo_T info;
3672 char_u buf[2];
3673 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003674
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003675 if (get_tty_info(read_cmd_fd, &info) == OK)
3676 {
3677 intr_char = info.interrupt;
3678 buf[0] = info.backspace;
3679 buf[1] = NUL;
3680 add_termcode((char_u *)"kb", buf, FALSE);
3681
Bram Moolenaar0f873732019-12-05 20:28:46 +01003682 // If <BS> and <DEL> are now the same, redefine <DEL>.
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003683 p = find_termcode((char_u *)"kD");
3684 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3685 do_fixdel(NULL);
3686 }
3687}
3688
3689/*
3690 * Obtain the characters that Backspace and Enter produce on "fd".
3691 * Returns OK or FAIL.
3692 */
3693 int
3694get_tty_info(int fd, ttyinfo_T *info)
3695{
3696#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003697# ifdef HAVE_TERMIOS_H
3698 struct termios keys;
3699# else
3700 struct termio keys;
3701# endif
3702
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003703 if (mch_tcgetattr(fd, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003704 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003705 info->backspace = keys.c_cc[VERASE];
3706 info->interrupt = keys.c_cc[VINTR];
3707 if (keys.c_iflag & ICRNL)
3708 info->enter = NL;
3709 else
3710 info->enter = CAR;
3711 if (keys.c_oflag & ONLCR)
3712 info->nl_does_cr = TRUE;
3713 else
3714 info->nl_does_cr = FALSE;
3715 return OK;
3716 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003717#else
Bram Moolenaar0f873732019-12-05 20:28:46 +01003718 // for "old" tty systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00003719 struct sgttyb keys;
3720
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003721 if (mch_tcgetattr(fd, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003722 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003723 info->backspace = keys.sg_erase;
3724 info->interrupt = keys.sg_kill;
3725 info->enter = CAR;
3726 info->nl_does_cr = TRUE;
3727 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003728 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729#endif
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003730 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003731}
3732
Bram Moolenaar0f873732019-12-05 20:28:46 +01003733#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00003734
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003735static int mouse_ison = FALSE;
3736
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737/*
3738 * Set mouse clicks on or off.
3739 */
3740 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003741mch_setmouse(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003742{
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003743#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003744 static int bevalterm_ison = FALSE;
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003745#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746 int xterm_mouse_vers;
3747
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003748#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaara06afc72018-08-27 23:24:16 +02003749 if (!on)
3750 // Make sure not tracing mouse movements. Important when a button-down
3751 // was received but no release yet.
3752 stop_xterm_trace();
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003753#endif
Bram Moolenaara06afc72018-08-27 23:24:16 +02003754
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003755 if (on == mouse_ison
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003756#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003757 && p_bevalterm == bevalterm_ison
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003758#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003759 )
Bram Moolenaar0f873732019-12-05 20:28:46 +01003760 // return quickly if nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00003761 return;
3762
3763 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003764
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003765#ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003766 if (ttym_flags == TTYM_URXVT)
3767 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003768 out_str_nf((char_u *)
3769 (on
3770 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3771 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003772 mouse_ison = on;
Bram Moolenaarc8427482011-10-20 21:09:35 +02003773 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003774#endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003775
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003776 if (ttym_flags == TTYM_SGR)
3777 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003778 // SGR mode supports columns above 223
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003779 out_str_nf((char_u *)
3780 (on
3781 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3782 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003783 mouse_ison = on;
3784 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003785
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003786#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003787 if (bevalterm_ison != (p_bevalterm && on))
3788 {
3789 bevalterm_ison = (p_bevalterm && on);
3790 if (xterm_mouse_vers > 1 && !bevalterm_ison)
Bram Moolenaar0f873732019-12-05 20:28:46 +01003791 // disable mouse movement events, enabling is below
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003792 out_str_nf((char_u *)
3793 (IF_EB("\033[?1003l", ESC_STR "[?1003l")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003794 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003795#endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003796
Bram Moolenaar071d4272004-06-13 20:20:40 +00003797 if (xterm_mouse_vers > 0)
3798 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003799 if (on) // enable mouse events, use mouse tracking if available
Bram Moolenaar071d4272004-06-13 20:20:40 +00003800 out_str_nf((char_u *)
3801 (xterm_mouse_vers > 1
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003802 ? (
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003803#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003804 bevalterm_ison
3805 ? IF_EB("\033[?1003h", ESC_STR "[?1003h") :
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003806#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003807 IF_EB("\033[?1002h", ESC_STR "[?1002h"))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
Bram Moolenaar0f873732019-12-05 20:28:46 +01003809 else // disable mouse events, could probably always send the same
Bram Moolenaar071d4272004-06-13 20:20:40 +00003810 out_str_nf((char_u *)
3811 (xterm_mouse_vers > 1
3812 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3813 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003814 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815 }
3816
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003817#ifdef FEAT_MOUSE_DEC
Bram Moolenaar071d4272004-06-13 20:20:40 +00003818 else if (ttym_flags == TTYM_DEC)
3819 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003820 if (on) // enable mouse events
Bram Moolenaar071d4272004-06-13 20:20:40 +00003821 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
Bram Moolenaar0f873732019-12-05 20:28:46 +01003822 else // disable mouse events
Bram Moolenaar071d4272004-06-13 20:20:40 +00003823 out_str_nf((char_u *)"\033['z");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003824 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003825 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003826#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003827
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003828#ifdef FEAT_MOUSE_GPM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829 else
3830 {
3831 if (on)
3832 {
3833 if (gpm_open())
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003834 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 }
3836 else
3837 {
3838 gpm_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003839 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003840 }
3841 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003842#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003843
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003844#ifdef FEAT_SYSMOUSE
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003845 else
3846 {
3847 if (on)
3848 {
3849 if (sysmouse_open() == OK)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003850 mouse_ison = TRUE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003851 }
3852 else
3853 {
3854 sysmouse_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003855 mouse_ison = FALSE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003856 }
3857 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003858#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003859
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003860#ifdef FEAT_MOUSE_JSB
Bram Moolenaar071d4272004-06-13 20:20:40 +00003861 else
3862 {
3863 if (on)
3864 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003865 // D - Enable Mouse up/down messages
3866 // L - Enable Left Button Reporting
3867 // M - Enable Middle Button Reporting
3868 // R - Enable Right Button Reporting
3869 // K - Enable SHIFT and CTRL key Reporting
3870 // + - Enable Advanced messaging of mouse moves and up/down messages
3871 // Q - Quiet No Ack
3872 // # - Numeric value of mouse pointer required
3873 // 0 = Multiview 2000 cursor, used as standard
3874 // 1 = Windows Arrow
3875 // 2 = Windows I Beam
3876 // 3 = Windows Hour Glass
3877 // 4 = Windows Cross Hair
3878 // 5 = Windows UP Arrow
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003879# ifdef JSBTERM_MOUSE_NONADVANCED
Bram Moolenaar0f873732019-12-05 20:28:46 +01003880 // Disables full feedback of pointer movements
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3882 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003883# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003884 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3885 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003886# endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003887 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888 }
3889 else
3890 {
3891 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3892 ESC_STR "[0~ZwQ" ESC_STR "\\"));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003893 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003894 }
3895 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003896#endif
3897#ifdef FEAT_MOUSE_PTERM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003898 else
3899 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003900 // 1 = button press, 6 = release, 7 = drag, 1h...9l = right button
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901 if (on)
3902 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3903 else
3904 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003905 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003907#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908}
3909
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003910#if defined(FEAT_BEVAL_TERM) || defined(PROTO)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003911/*
3912 * Called when 'balloonevalterm' changed.
3913 */
3914 void
3915mch_bevalterm_changed(void)
3916{
3917 mch_setmouse(mouse_ison);
3918}
3919#endif
3920
Bram Moolenaar071d4272004-06-13 20:20:40 +00003921/*
3922 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3923 */
3924 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003925check_mouse_termcode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003926{
3927# ifdef FEAT_MOUSE_XTERM
3928 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003929# ifdef FEAT_MOUSE_URXVT
3930 && use_xterm_mouse() != 3
3931# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003932# ifdef FEAT_GUI
3933 && !gui.in_use
3934# endif
3935 )
3936 {
3937 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003938 ? IF_EB("\233M", CSI_STR "M")
3939 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003940 if (*p_mouse != NUL)
3941 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003942 // force mouse off and maybe on to send possibly new mouse
3943 // activation sequence to the xterm, with(out) drag tracing.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003944 mch_setmouse(FALSE);
3945 setmouse();
3946 }
3947 }
3948 else
3949 del_mouse_termcode(KS_MOUSE);
3950# endif
3951
3952# ifdef FEAT_MOUSE_GPM
3953 if (!use_xterm_mouse()
3954# ifdef FEAT_GUI
3955 && !gui.in_use
3956# endif
3957 )
Bram Moolenaarbedf0912019-05-04 16:58:45 +02003958 set_mouse_termcode(KS_GPM_MOUSE,
3959 (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3960 else
3961 del_mouse_termcode(KS_GPM_MOUSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003962# endif
3963
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003964# ifdef FEAT_SYSMOUSE
3965 if (!use_xterm_mouse()
3966# ifdef FEAT_GUI
3967 && !gui.in_use
3968# endif
3969 )
3970 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3971# endif
3972
Bram Moolenaar071d4272004-06-13 20:20:40 +00003973# ifdef FEAT_MOUSE_JSB
Bram Moolenaar0f873732019-12-05 20:28:46 +01003974 // Conflicts with xterm mouse: "\033[" and "\033[M" ???
Bram Moolenaar071d4272004-06-13 20:20:40 +00003975 if (!use_xterm_mouse()
3976# ifdef FEAT_GUI
3977 && !gui.in_use
3978# endif
3979 )
3980 set_mouse_termcode(KS_JSBTERM_MOUSE,
3981 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3982 else
3983 del_mouse_termcode(KS_JSBTERM_MOUSE);
3984# endif
3985
3986# ifdef FEAT_MOUSE_NET
Bram Moolenaar0f873732019-12-05 20:28:46 +01003987 // There is no conflict, but one may type "ESC }" from Insert mode. Don't
3988 // define it in the GUI or when using an xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003989 if (!use_xterm_mouse()
3990# ifdef FEAT_GUI
3991 && !gui.in_use
3992# endif
3993 )
3994 set_mouse_termcode(KS_NETTERM_MOUSE,
3995 (char_u *)IF_EB("\033}", ESC_STR "}"));
3996 else
3997 del_mouse_termcode(KS_NETTERM_MOUSE);
3998# endif
3999
4000# ifdef FEAT_MOUSE_DEC
Bram Moolenaar0f873732019-12-05 20:28:46 +01004001 // Conflicts with xterm mouse: "\033[" and "\033[M"
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02004002 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00004003# ifdef FEAT_GUI
4004 && !gui.in_use
4005# endif
4006 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00004007 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
4008 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004009 else
4010 del_mouse_termcode(KS_DEC_MOUSE);
4011# endif
4012# ifdef FEAT_MOUSE_PTERM
Bram Moolenaar0f873732019-12-05 20:28:46 +01004013 // same conflict as the dec mouse
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02004014 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00004015# ifdef FEAT_GUI
4016 && !gui.in_use
4017# endif
4018 )
4019 set_mouse_termcode(KS_PTERM_MOUSE,
4020 (char_u *) IF_EB("\033[", ESC_STR "["));
4021 else
4022 del_mouse_termcode(KS_PTERM_MOUSE);
4023# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02004024# ifdef FEAT_MOUSE_URXVT
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02004025 if (use_xterm_mouse() == 3
Bram Moolenaarc8427482011-10-20 21:09:35 +02004026# ifdef FEAT_GUI
4027 && !gui.in_use
4028# endif
4029 )
4030 {
4031 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02004032 ? IF_EB("\233*M", CSI_STR "*M")
4033 : IF_EB("\033[*M", ESC_STR "[*M")));
Bram Moolenaarc8427482011-10-20 21:09:35 +02004034
4035 if (*p_mouse != NUL)
4036 {
4037 mch_setmouse(FALSE);
4038 setmouse();
4039 }
4040 }
4041 else
4042 del_mouse_termcode(KS_URXVT_MOUSE);
4043# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004044 if (use_xterm_mouse() == 4
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01004045# ifdef FEAT_GUI
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004046 && !gui.in_use
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01004047# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004048 )
4049 {
4050 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02004051 ? IF_EB("\233<*M", CSI_STR "<*M")
4052 : IF_EB("\033[<*M", ESC_STR "[<*M")));
4053
4054 set_mouse_termcode(KS_SGR_MOUSE_RELEASE, (char_u *)(term_is_8bit(T_NAME)
4055 ? IF_EB("\233<*m", CSI_STR "<*m")
4056 : IF_EB("\033[<*m", ESC_STR "[<*m")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004057
4058 if (*p_mouse != NUL)
4059 {
4060 mch_setmouse(FALSE);
4061 setmouse();
4062 }
4063 }
4064 else
Bram Moolenaara529ce02017-06-22 22:37:57 +02004065 {
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004066 del_mouse_termcode(KS_SGR_MOUSE);
Bram Moolenaara529ce02017-06-22 22:37:57 +02004067 del_mouse_termcode(KS_SGR_MOUSE_RELEASE);
4068 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004069}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004070
Bram Moolenaar071d4272004-06-13 20:20:40 +00004071#ifndef VMS
4072
4073/*
4074 * Try to get the current window size:
4075 * 1. with an ioctl(), most accurate method
4076 * 2. from the environment variables LINES and COLUMNS
4077 * 3. from the termcap
4078 * 4. keep using the old values
4079 * Return OK when size could be determined, FAIL otherwise.
4080 */
4081 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004082mch_get_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004083{
4084 long rows = 0;
4085 long columns = 0;
4086 char_u *p;
4087
4088 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004089 * 1. try using an ioctl. It is the most accurate method.
4090 *
4091 * Try using TIOCGWINSZ first, some systems that have it also define
4092 * TIOCGSIZE but don't have a struct ttysize.
4093 */
4094# ifdef TIOCGWINSZ
4095 {
4096 struct winsize ws;
4097 int fd = 1;
4098
Bram Moolenaar0f873732019-12-05 20:28:46 +01004099 // When stdout is not a tty, use stdin for the ioctl().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004100 if (!isatty(fd) && isatty(read_cmd_fd))
4101 fd = read_cmd_fd;
4102 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
4103 {
4104 columns = ws.ws_col;
4105 rows = ws.ws_row;
4106 }
4107 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004108# else // TIOCGWINSZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00004109# ifdef TIOCGSIZE
4110 {
4111 struct ttysize ts;
4112 int fd = 1;
4113
Bram Moolenaar0f873732019-12-05 20:28:46 +01004114 // When stdout is not a tty, use stdin for the ioctl().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115 if (!isatty(fd) && isatty(read_cmd_fd))
4116 fd = read_cmd_fd;
4117 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
4118 {
4119 columns = ts.ts_cols;
4120 rows = ts.ts_lines;
4121 }
4122 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004123# endif // TIOCGSIZE
4124# endif // TIOCGWINSZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00004125
4126 /*
4127 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004128 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
4129 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004130 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004131 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004132 {
4133 if ((p = (char_u *)getenv("LINES")))
4134 rows = atoi((char *)p);
4135 if ((p = (char_u *)getenv("COLUMNS")))
4136 columns = atoi((char *)p);
4137 }
4138
4139#ifdef HAVE_TGETENT
4140 /*
4141 * 3. try reading "co" and "li" entries from termcap
4142 */
4143 if (columns == 0 || rows == 0)
4144 getlinecol(&columns, &rows);
4145#endif
4146
4147 /*
4148 * 4. If everything fails, use the old values
4149 */
4150 if (columns <= 0 || rows <= 0)
4151 return FAIL;
4152
4153 Rows = rows;
4154 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02004155 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004156 return OK;
4157}
4158
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004159#if defined(FEAT_TERMINAL) || defined(PROTO)
4160/*
4161 * Report the windows size "rows" and "cols" to tty "fd".
4162 */
4163 int
4164mch_report_winsize(int fd, int rows, int cols)
4165{
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004166 int tty_fd;
4167 int retval = -1;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004168
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004169 tty_fd = get_tty_fd(fd);
4170 if (tty_fd >= 0)
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004171 {
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004172# if defined(TIOCSWINSZ)
4173 struct winsize ws;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004174
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004175 ws.ws_col = cols;
4176 ws.ws_row = rows;
4177 ws.ws_xpixel = cols * 5;
4178 ws.ws_ypixel = rows * 10;
4179 retval = ioctl(tty_fd, TIOCSWINSZ, &ws);
4180 ch_log(NULL, "ioctl(TIOCSWINSZ) %s",
4181 retval == 0 ? "success" : "failed");
4182# elif defined(TIOCSSIZE)
4183 struct ttysize ts;
4184
4185 ts.ts_cols = cols;
4186 ts.ts_lines = rows;
4187 retval = ioctl(tty_fd, TIOCSSIZE, &ts);
4188 ch_log(NULL, "ioctl(TIOCSSIZE) %s",
4189 retval == 0 ? "success" : "failed");
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004190# endif
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004191 if (tty_fd != fd)
4192 close(tty_fd);
4193 }
4194 return retval == 0 ? OK : FAIL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004195}
4196#endif
4197
Bram Moolenaar071d4272004-06-13 20:20:40 +00004198/*
4199 * Try to set the window size to Rows and Columns.
4200 */
4201 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004202mch_set_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004203{
4204 if (*T_CWS)
4205 {
4206 /*
4207 * NOTE: if you get an error here that term_set_winsize() is
4208 * undefined, check the output of configure. It could probably not
4209 * find a ncurses, termcap or termlib library.
4210 */
4211 term_set_winsize((int)Rows, (int)Columns);
4212 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01004213 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004214 }
4215}
4216
Bram Moolenaar0f873732019-12-05 20:28:46 +01004217#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004218
4219/*
4220 * Rows and/or Columns has changed.
4221 */
4222 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004223mch_new_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004224{
Bram Moolenaar0f873732019-12-05 20:28:46 +01004225 // Nothing to do.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004226}
4227
Bram Moolenaar205b8862011-09-07 15:04:31 +02004228/*
4229 * Wait for process "child" to end.
4230 * Return "child" if it exited properly, <= 0 on error.
4231 */
4232 static pid_t
Bram Moolenaar05540972016-01-30 20:31:25 +01004233wait4pid(pid_t child, waitstatus *status)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004234{
4235 pid_t wait_pid = 0;
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004236 long delay_msec = 1;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004237
4238 while (wait_pid != child)
4239 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004240 // When compiled with Python threads are probably used, in which case
4241 // wait() sometimes hangs for no obvious reason. Use waitpid()
4242 // instead and loop (like the GUI). Also needed for other interfaces,
4243 // they might call system().
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004244# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004245 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004246# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02004247 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004248# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02004249 if (wait_pid == 0)
4250 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004251 // Wait for 1 to 10 msec before trying again.
Bram Moolenaar0981c872020-08-23 14:28:37 +02004252 mch_delay(delay_msec, MCH_DELAY_IGNOREINPUT | MCH_DELAY_SETTMODE);
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004253 if (++delay_msec > 10)
4254 delay_msec = 10;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004255 continue;
4256 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004257 if (wait_pid <= 0
4258# ifdef ECHILD
4259 && errno == ECHILD
4260# endif
4261 )
4262 break;
4263 }
4264 return wait_pid;
4265}
4266
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01004267#if !defined(USE_SYSTEM) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar7da34602017-08-01 17:14:21 +02004268/*
4269 * Set the environment for a child process.
4270 */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004271 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004272set_child_environment(
4273 long rows,
4274 long columns,
4275 char *term,
4276 int is_terminal UNUSED)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004277{
4278# ifdef HAVE_SETENV
4279 char envbuf[50];
4280# else
Bram Moolenaar5f7e7bd2017-07-22 14:08:43 +02004281 static char envbuf_Term[30];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004282 static char envbuf_Rows[20];
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004283 static char envbuf_Lines[20];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004284 static char envbuf_Columns[20];
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004285 static char envbuf_Colors[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004286# ifdef FEAT_TERMINAL
Bram Moolenaard7a137f2018-06-12 18:05:24 +02004287 static char envbuf_Version[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004288# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004289# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004290 static char envbuf_Servername[60];
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004291# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004292# endif
4293
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004294# ifdef HAVE_SETENV
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004295 setenv("TERM", term, 1);
4296 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004297 setenv("ROWS", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004298 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004299 setenv("LINES", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004300 sprintf((char *)envbuf, "%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004301 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaar759d8152020-04-26 16:52:49 +02004302 sprintf((char *)envbuf, "%d", t_colors);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004303 setenv("COLORS", (char *)envbuf, 1);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004304# ifdef FEAT_TERMINAL
4305 if (is_terminal)
4306 {
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004307 sprintf((char *)envbuf, "%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004308 setenv("VIM_TERMINAL", (char *)envbuf, 1);
4309 }
4310# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004311# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004312 setenv("VIM_SERVERNAME", serverName == NULL ? "" : (char *)serverName, 1);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004313# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004314# else
4315 /*
4316 * Putenv does not copy the string, it has to remain valid.
4317 * Use a static array to avoid losing allocated memory.
Bram Moolenaar7da34602017-08-01 17:14:21 +02004318 * This won't work well when running multiple children...
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004319 */
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004320 vim_snprintf(envbuf_Term, sizeof(envbuf_Term), "TERM=%s", term);
4321 putenv(envbuf_Term);
4322 vim_snprintf(envbuf_Rows, sizeof(envbuf_Rows), "ROWS=%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004323 putenv(envbuf_Rows);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004324 vim_snprintf(envbuf_Lines, sizeof(envbuf_Lines), "LINES=%ld", rows);
4325 putenv(envbuf_Lines);
4326 vim_snprintf(envbuf_Columns, sizeof(envbuf_Columns),
4327 "COLUMNS=%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004328 putenv(envbuf_Columns);
Bram Moolenaaraffc8fd2020-04-28 21:58:29 +02004329 vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", t_colors);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004330 putenv(envbuf_Colors);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004331# ifdef FEAT_TERMINAL
4332 if (is_terminal)
4333 {
4334 vim_snprintf(envbuf_Version, sizeof(envbuf_Version),
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004335 "VIM_TERMINAL=%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004336 putenv(envbuf_Version);
4337 }
4338# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004339# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004340 vim_snprintf(envbuf_Servername, sizeof(envbuf_Servername),
4341 "VIM_SERVERNAME=%s", serverName == NULL ? "" : (char *)serverName);
4342 putenv(envbuf_Servername);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004343# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004344# endif
4345}
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004346
4347 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004348set_default_child_environment(int is_terminal)
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004349{
Bram Moolenaar493359e2018-06-12 20:25:52 +02004350 set_child_environment(Rows, Columns, "dumb", is_terminal);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004351}
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004352#endif
4353
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004354#if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004355/*
4356 * Open a PTY, with FD for the master and slave side.
4357 * When failing "pty_master_fd" and "pty_slave_fd" are -1.
Bram Moolenaar59386482019-02-10 22:43:46 +01004358 * When successful both file descriptors are stored and the allocated pty name
4359 * is stored in both "*name1" and "*name2".
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004360 */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004361 static void
Bram Moolenaar59386482019-02-10 22:43:46 +01004362open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **name1, char_u **name2)
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004363{
4364 char *tty_name;
4365
Bram Moolenaar59386482019-02-10 22:43:46 +01004366 if (name1 != NULL)
4367 *name1 = NULL;
4368 if (name2 != NULL)
4369 *name2 = NULL;
4370
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004371 *pty_master_fd = mch_openpty(&tty_name); // open pty
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004372 if (*pty_master_fd >= 0)
4373 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004374 // Leaving out O_NOCTTY may lead to waitpid() always returning
4375 // 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4376 // adding O_NOCTTY always works when defined.
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004377#ifdef O_NOCTTY
4378 *pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4379#else
4380 *pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4381#endif
4382 if (*pty_slave_fd < 0)
4383 {
4384 close(*pty_master_fd);
4385 *pty_master_fd = -1;
4386 }
Bram Moolenaar59386482019-02-10 22:43:46 +01004387 else
4388 {
4389 if (name1 != NULL)
4390 *name1 = vim_strsave((char_u *)tty_name);
4391 if (name2 != NULL)
4392 *name2 = vim_strsave((char_u *)tty_name);
4393 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004394 }
4395}
4396#endif
4397
Bram Moolenaarfae42832017-08-01 22:24:26 +02004398/*
4399 * Send SIGINT to a child process if "c" is an interrupt character.
4400 */
Bram Moolenaar840d16f2019-09-10 21:27:18 +02004401 static void
Bram Moolenaarfae42832017-08-01 22:24:26 +02004402may_send_sigint(int c UNUSED, pid_t pid UNUSED, pid_t wpid UNUSED)
4403{
4404# ifdef SIGINT
4405 if (c == Ctrl_C || c == intr_char)
4406 {
4407# ifdef HAVE_SETSID
4408 kill(-pid, SIGINT);
4409# else
4410 kill(0, SIGINT);
4411# endif
4412 if (wpid > 0)
4413 kill(wpid, SIGINT);
4414 }
4415# endif
4416}
4417
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004418#if !defined(USE_SYSTEM) || defined(FEAT_TERMINAL) || defined(PROTO)
Bram Moolenaar13568252018-03-16 20:46:58 +01004419
Bram Moolenaar0f873732019-12-05 20:28:46 +01004420/*
4421 * Parse "cmd" and return the result in "argvp" which is an allocated array of
4422 * pointers, the last one is NULL.
4423 * The "sh_tofree" and "shcf_tofree" must be later freed by the caller.
4424 */
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004425 int
4426unix_build_argv(
Bram Moolenaar13568252018-03-16 20:46:58 +01004427 char_u *cmd,
4428 char ***argvp,
4429 char_u **sh_tofree,
4430 char_u **shcf_tofree)
4431{
4432 char **argv = NULL;
4433 int argc;
4434
4435 *sh_tofree = vim_strsave(p_sh);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004436 if (*sh_tofree == NULL) // out of memory
Bram Moolenaar13568252018-03-16 20:46:58 +01004437 return FAIL;
4438
4439 if (mch_parse_cmd(*sh_tofree, TRUE, &argv, &argc) == FAIL)
4440 return FAIL;
4441 *argvp = argv;
4442
4443 if (cmd != NULL)
4444 {
4445 char_u *s;
4446 char_u *p;
4447
4448 if (extra_shell_arg != NULL)
4449 argv[argc++] = (char *)extra_shell_arg;
4450
Bram Moolenaar0f873732019-12-05 20:28:46 +01004451 // Break 'shellcmdflag' into white separated parts. This doesn't
4452 // handle quoted strings, they are very unlikely to appear.
Bram Moolenaar964b3742019-05-24 18:54:09 +02004453 *shcf_tofree = alloc(STRLEN(p_shcf) + 1);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004454 if (*shcf_tofree == NULL) // out of memory
Bram Moolenaar13568252018-03-16 20:46:58 +01004455 return FAIL;
4456 s = *shcf_tofree;
4457 p = p_shcf;
4458 while (*p != NUL)
4459 {
4460 argv[argc++] = (char *)s;
4461 while (*p && *p != ' ' && *p != TAB)
4462 *s++ = *p++;
4463 *s++ = NUL;
4464 p = skipwhite(p);
4465 }
4466
4467 argv[argc++] = (char *)cmd;
4468 }
4469 argv[argc] = NULL;
4470 return OK;
4471}
4472#endif
4473
4474#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
4475/*
4476 * Use a terminal window to run a shell command in.
4477 */
4478 static int
4479mch_call_shell_terminal(
4480 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004481 int options UNUSED) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01004482{
4483 jobopt_T opt;
4484 char **argv = NULL;
4485 char_u *tofree1 = NULL;
4486 char_u *tofree2 = NULL;
4487 int retval = -1;
4488 buf_T *buf;
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004489 job_T *job;
Bram Moolenaar13568252018-03-16 20:46:58 +01004490 aco_save_T aco;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004491 oparg_T oa; // operator arguments
Bram Moolenaar13568252018-03-16 20:46:58 +01004492
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004493 if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar13568252018-03-16 20:46:58 +01004494 goto theend;
4495
4496 init_job_options(&opt);
4497 ch_log(NULL, "starting terminal for system command '%s'", cmd);
4498 buf = term_start(NULL, argv, &opt, TERM_START_SYSTEM);
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004499 if (buf == NULL)
4500 goto theend;
4501
4502 job = term_getjob(buf->b_term);
4503 ++job->jv_refcount;
Bram Moolenaar13568252018-03-16 20:46:58 +01004504
Bram Moolenaar0f873732019-12-05 20:28:46 +01004505 // Find a window to make "buf" curbuf.
Bram Moolenaar13568252018-03-16 20:46:58 +01004506 aucmd_prepbuf(&aco, buf);
4507
4508 clear_oparg(&oa);
4509 while (term_use_loop())
4510 {
4511 if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active)
4512 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004513 // If terminal_loop() returns OK we got a key that is handled
4514 // in Normal model. We don't do redrawing anyway.
Bram Moolenaar13568252018-03-16 20:46:58 +01004515 if (terminal_loop(TRUE) == OK)
4516 normal_cmd(&oa, TRUE);
4517 }
4518 else
4519 normal_cmd(&oa, TRUE);
4520 }
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004521 retval = job->jv_exitval;
Bram Moolenaar13568252018-03-16 20:46:58 +01004522 ch_log(NULL, "system command finished");
4523
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004524 job_unref(job);
4525
Bram Moolenaar0f873732019-12-05 20:28:46 +01004526 // restore curwin/curbuf and a few other things
Bram Moolenaar13568252018-03-16 20:46:58 +01004527 aucmd_restbuf(&aco);
4528
4529 wait_return(TRUE);
4530 do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
4531
4532theend:
4533 vim_free(argv);
4534 vim_free(tofree1);
4535 vim_free(tofree2);
4536 return retval;
4537}
4538#endif
4539
4540#ifdef USE_SYSTEM
4541/*
4542 * Use system() to start the shell: simple but slow.
4543 */
4544 static int
4545mch_call_shell_system(
Bram Moolenaar05540972016-01-30 20:31:25 +01004546 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004547 int options) // SHELL_*, see vim.h
Bram Moolenaar071d4272004-06-13 20:20:40 +00004548{
4549#ifdef VMS
4550 char *ifn = NULL;
4551 char *ofn = NULL;
4552#endif
Bram Moolenaar26e86442020-05-17 14:06:16 +02004553 tmode_T tmode = cur_tmode;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004554 char_u *newcmd; // only needed for unix
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01004555 int x;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556
4557 out_flush();
4558
4559 if (options & SHELL_COOKED)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004560 settmode(TMODE_COOK); // set to normal mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00004561
Bram Moolenaar62b42182010-09-21 22:09:37 +02004562# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004563 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02004564 loose_clipboard();
4565# endif
4566
Bram Moolenaar071d4272004-06-13 20:20:40 +00004567 if (cmd == NULL)
4568 x = system((char *)p_sh);
4569 else
4570 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004571# ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004572 if (ofn = strchr((char *)cmd, '>'))
4573 *ofn++ = '\0';
4574 if (ifn = strchr((char *)cmd, '<'))
4575 {
4576 char *p;
4577
4578 *ifn++ = '\0';
Bram Moolenaar0f873732019-12-05 20:28:46 +01004579 p = strchr(ifn,' '); // chop off any trailing spaces
Bram Moolenaar071d4272004-06-13 20:20:40 +00004580 if (p)
4581 *p = '\0';
4582 }
4583 if (ofn)
4584 x = vms_sys((char *)cmd, ofn, ifn);
4585 else
4586 x = system((char *)cmd);
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004587# else
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004588 newcmd = alloc(STRLEN(p_sh)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004589 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004590 + STRLEN(p_shcf) + STRLEN(cmd) + 4);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004591 if (newcmd == NULL)
4592 x = 0;
4593 else
4594 {
4595 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
4596 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
4597 (char *)p_shcf,
4598 (char *)cmd);
4599 x = system((char *)newcmd);
4600 vim_free(newcmd);
4601 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004602# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004603 }
4604# ifdef VMS
4605 x = vms_sys_status(x);
4606# endif
4607 if (emsg_silent)
4608 ;
4609 else if (x == 127)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004610 msg_puts(_("\nCannot execute shell sh\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004611 else if (x && !(options & SHELL_SILENT))
4612 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004613 msg_puts(_("\nshell returned "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614 msg_outnum((long)x);
4615 msg_putchar('\n');
4616 }
4617
4618 if (tmode == TMODE_RAW)
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004619 {
4620 // The shell may have messed with the mode, always set it.
4621 cur_tmode = TMODE_UNKNOWN;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004622 settmode(TMODE_RAW); // set to raw mode
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004623 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004624 resettitle();
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004625# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4626 restore_clipboard();
4627# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004628 return x;
Bram Moolenaar13568252018-03-16 20:46:58 +01004629}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004630
Bram Moolenaar0f873732019-12-05 20:28:46 +01004631#else // USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00004632
Bram Moolenaar0f873732019-12-05 20:28:46 +01004633# define EXEC_FAILED 122 // Exit code when shell didn't execute. Don't use
4634 // 127, some shells use that already
4635# define OPEN_NULL_FAILED 123 // Exit code if /dev/null can't be opened
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636
Bram Moolenaar13568252018-03-16 20:46:58 +01004637/*
4638 * Don't use system(), use fork()/exec().
4639 */
4640 static int
4641mch_call_shell_fork(
4642 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004643 int options) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01004644{
Bram Moolenaar26e86442020-05-17 14:06:16 +02004645 tmode_T tmode = cur_tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004646 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004647 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004648 pid_t wait_pid = 0;
4649# ifdef HAVE_UNION_WAIT
4650 union wait status;
4651# else
4652 int status = -1;
4653# endif
4654 int retval = -1;
4655 char **argv = NULL;
Bram Moolenaar13568252018-03-16 20:46:58 +01004656 char_u *tofree1 = NULL;
4657 char_u *tofree2 = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004658 int i;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004659 int pty_master_fd = -1; // for pty's
Bram Moolenaardf177f62005-02-22 08:39:57 +00004660# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661 int pty_slave_fd = -1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004662# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01004663 int fd_toshell[2]; // for pipes
Bram Moolenaar071d4272004-06-13 20:20:40 +00004664 int fd_fromshell[2];
4665 int pipe_error = FALSE;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004666 int did_settmode = FALSE; // settmode(TMODE_RAW) called
Bram Moolenaar071d4272004-06-13 20:20:40 +00004667
4668 out_flush();
4669 if (options & SHELL_COOKED)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004670 settmode(TMODE_COOK); // set to normal mode
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004671 if (tmode == TMODE_RAW)
4672 // The shell may have messed with the mode, always set it later.
4673 cur_tmode = TMODE_UNKNOWN;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004674
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004675 if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar835dc632016-02-07 14:27:38 +01004676 goto error;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004677
Bram Moolenaar071d4272004-06-13 20:20:40 +00004678 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004679 * For the GUI, when writing the output into the buffer and when reading
4680 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4681 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004682 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004683 if ((options & (SHELL_READ|SHELL_WRITE))
4684# ifdef FEAT_GUI
4685 || (gui.in_use && show_shell_mess)
4686# endif
4687 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004688 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004689# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690 /*
4691 * Try to open a master pty.
4692 * If this works, open the slave pty.
4693 * If the slave can't be opened, close the master pty.
4694 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004695 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar59386482019-02-10 22:43:46 +01004696 open_pty(&pty_master_fd, &pty_slave_fd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004697 /*
4698 * If not opening a pty or it didn't work, try using pipes.
4699 */
4700 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004701# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702 {
4703 pipe_error = (pipe(fd_toshell) < 0);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004704 if (!pipe_error) // pipe create OK
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705 {
4706 pipe_error = (pipe(fd_fromshell) < 0);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004707 if (pipe_error) // pipe create failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00004708 {
4709 close(fd_toshell[0]);
4710 close(fd_toshell[1]);
4711 }
4712 }
4713 if (pipe_error)
4714 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004715 msg_puts(_("\nCannot create pipes\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004716 out_flush();
4717 }
4718 }
4719 }
4720
Bram Moolenaar0f873732019-12-05 20:28:46 +01004721 if (!pipe_error) // pty or pipe opened or not used
Bram Moolenaar071d4272004-06-13 20:20:40 +00004722 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004723 SIGSET_DECL(curset)
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004724 BLOCK_SIGNALS(&curset);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004725 pid = fork(); // maybe we should use vfork()
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004726 if (pid == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004727 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004728 UNBLOCK_SIGNALS(&curset);
4729
Bram Moolenaar32526b32019-01-19 17:43:09 +01004730 msg_puts(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004731 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004732# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004733 || (gui.in_use && show_shell_mess)
4734# endif
4735 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004736 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004737# ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01004738 if (pty_master_fd >= 0) // close the pseudo tty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004739 {
4740 close(pty_master_fd);
4741 close(pty_slave_fd);
4742 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004743 else // close the pipes
Bram Moolenaardf177f62005-02-22 08:39:57 +00004744# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004745 {
4746 close(fd_toshell[0]);
4747 close(fd_toshell[1]);
4748 close(fd_fromshell[0]);
4749 close(fd_fromshell[1]);
4750 }
4751 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004752 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004753 else if (pid == 0) // child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004754 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004755 reset_signals(); // handle signals normally
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004756 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004757
Bram Moolenaar819524702018-02-27 19:10:00 +01004758# ifdef FEAT_JOB_CHANNEL
4759 if (ch_log_active())
Bram Moolenaar76603ba2020-08-30 17:24:37 +02004760 {
4761 ch_log(NULL, "closing channel log in the child process");
Bram Moolenaar819524702018-02-27 19:10:00 +01004762 ch_logfile((char_u *)"", (char_u *)"");
Bram Moolenaar76603ba2020-08-30 17:24:37 +02004763 }
Bram Moolenaar819524702018-02-27 19:10:00 +01004764# endif
4765
Bram Moolenaar071d4272004-06-13 20:20:40 +00004766 if (!show_shell_mess || (options & SHELL_EXPAND))
4767 {
4768 int fd;
4769
4770 /*
4771 * Don't want to show any message from the shell. Can't just
4772 * close stdout and stderr though, because some systems will
4773 * break if you try to write to them after that, so we must
4774 * use dup() to replace them with something else -- webb
4775 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4776 * waiting for input.
4777 */
4778 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4779 fclose(stdin);
4780 fclose(stdout);
4781 fclose(stderr);
4782
4783 /*
4784 * If any of these open()'s and dup()'s fail, we just continue
4785 * anyway. It's not fatal, and on most systems it will make
4786 * no difference at all. On a few it will cause the execvp()
4787 * to exit with a non-zero status even when the completion
4788 * could be done, which is nothing too serious. If the open()
4789 * or dup() failed we'd just do the same thing ourselves
4790 * anyway -- webb
4791 */
4792 if (fd >= 0)
4793 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004794 vim_ignored = dup(fd); // To replace stdin (fd 0)
4795 vim_ignored = dup(fd); // To replace stdout (fd 1)
4796 vim_ignored = dup(fd); // To replace stderr (fd 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797
Bram Moolenaar0f873732019-12-05 20:28:46 +01004798 // Don't need this now that we've duplicated it
Bram Moolenaar071d4272004-06-13 20:20:40 +00004799 close(fd);
4800 }
4801 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004802 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004804 || gui.in_use
4805# endif
4806 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004807 {
4808
Bram Moolenaardf177f62005-02-22 08:39:57 +00004809# ifdef HAVE_SETSID
Bram Moolenaar0f873732019-12-05 20:28:46 +01004810 // Create our own process group, so that the child and all its
4811 // children can be kill()ed. Don't do this when using pipes,
4812 // because stdin is not a tty, we would lose /dev/tty.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004813 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004814 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004815 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004816# if defined(SIGHUP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004817 // When doing "!xterm&" and 'shell' is bash: the shell
4818 // will exit and send SIGHUP to all processes in its
4819 // group, killing the just started process. Ignore SIGHUP
4820 // to avoid that. (suggested by Simon Schubert)
Bram Moolenaar07256082009-02-04 13:19:42 +00004821 signal(SIGHUP, SIG_IGN);
4822# endif
4823 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004824# endif
4825# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004826 if (pty_slave_fd >= 0)
4827 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004828 // push stream discipline modules
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004829 if (options & SHELL_COOKED)
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004830 setup_slavepty(pty_slave_fd);
Bram Moolenaarfff10d92021-10-13 10:05:30 +01004831# ifdef TIOCSCTTY
4832 // Try to become controlling tty (probably doesn't work,
4833 // unless run by root)
4834 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
4835# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004836 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004837# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02004838 set_default_child_environment(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839
Bram Moolenaara5792f52005-11-23 21:25:05 +00004840 /*
4841 * stderr is only redirected when using the GUI, so that a
4842 * program like gpg can still access the terminal to get a
4843 * passphrase using stderr.
4844 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004845# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004846 if (pty_master_fd >= 0)
4847 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004848 close(pty_master_fd); // close master side of pty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004849
Bram Moolenaar0f873732019-12-05 20:28:46 +01004850 // set up stdin/stdout/stderr for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004851 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004852 vim_ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004853 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004854 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004855 if (gui.in_use)
4856 {
4857 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004858 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004859 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004860
Bram Moolenaar0f873732019-12-05 20:28:46 +01004861 close(pty_slave_fd); // has been dupped, close it now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862 }
4863 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004864# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004865 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004866 // set up stdin for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867 close(fd_toshell[1]);
4868 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004869 vim_ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004870 close(fd_toshell[0]);
4871
Bram Moolenaar0f873732019-12-05 20:28:46 +01004872 // set up stdout for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004873 close(fd_fromshell[0]);
4874 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004875 vim_ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004876 close(fd_fromshell[1]);
4877
Bram Moolenaara5792f52005-11-23 21:25:05 +00004878# ifdef FEAT_GUI
4879 if (gui.in_use)
4880 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004881 // set up stderr for the child
Bram Moolenaara5792f52005-11-23 21:25:05 +00004882 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004883 vim_ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004884 }
4885# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004886 }
4887 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004888
Bram Moolenaar071d4272004-06-13 20:20:40 +00004889 /*
4890 * There is no type cast for the argv, because the type may be
4891 * different on different machines. This may cause a warning
4892 * message with strict compilers, don't worry about it.
4893 * Call _exit() instead of exit() to avoid closing the connection
4894 * to the X server (esp. with GTK, which uses atexit()).
4895 */
4896 execvp(argv[0], argv);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004897 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar071d4272004-06-13 20:20:40 +00004898 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004899 else // parent
Bram Moolenaar071d4272004-06-13 20:20:40 +00004900 {
4901 /*
4902 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004903 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004904 */
4905 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004906 catch_int_signal();
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004907 UNBLOCK_SIGNALS(&curset);
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01004908# ifdef FEAT_JOB_CHANNEL
4909 ++dont_check_job_ended;
4910# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004911 /*
4912 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004913 * This is also used to pipe stdin/stdout to/from the external
4914 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004915 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004916 if ((options & (SHELL_READ|SHELL_WRITE))
4917# ifdef FEAT_GUI
4918 || (gui.in_use && show_shell_mess)
4919# endif
4920 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004921 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004922# define BUFLEN 100 // length for buffer, pseudo tty limit is 128
Bram Moolenaar071d4272004-06-13 20:20:40 +00004923 char_u buffer[BUFLEN + 1];
Bram Moolenaar0f873732019-12-05 20:28:46 +01004924 int buffer_off = 0; // valid bytes in buffer[]
4925 char_u ta_buf[BUFLEN + 1]; // TypeAHead
4926 int ta_len = 0; // valid bytes in ta_buf[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00004927 int len;
4928 int p_more_save;
4929 int old_State;
4930 int c;
4931 int toshell_fd;
4932 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004933 garray_T ga;
4934 int noread_cnt;
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01004935# ifdef ELAPSED_FUNC
4936 elapsed_T start_tv;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004937# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004938
Bram Moolenaardf177f62005-02-22 08:39:57 +00004939# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004940 if (pty_master_fd >= 0)
4941 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004942 fromshell_fd = pty_master_fd;
4943 toshell_fd = dup(pty_master_fd);
4944 }
4945 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004946# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004947 {
4948 close(fd_toshell[0]);
4949 close(fd_fromshell[1]);
4950 toshell_fd = fd_toshell[1];
4951 fromshell_fd = fd_fromshell[0];
4952 }
4953
4954 /*
4955 * Write to the child if there are typed characters.
4956 * Read from the child if there are characters available.
4957 * Repeat the reading a few times if more characters are
4958 * available. Need to check for typed keys now and then, but
4959 * not too often (delays when no chars are available).
4960 * This loop is quit if no characters can be read from the pty
4961 * (WaitForChar detected special condition), or there are no
4962 * characters available and the child has exited.
4963 * Only check if the child has exited when there is no more
4964 * output. The child may exit before all the output has
4965 * been printed.
4966 *
4967 * Currently this busy loops!
4968 * This can probably dead-lock when the write blocks!
4969 */
4970 p_more_save = p_more;
4971 p_more = FALSE;
4972 old_State = State;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004973 State = EXTERNCMD; // don't redraw at window resize
Bram Moolenaar071d4272004-06-13 20:20:40 +00004974
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004975 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004976 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004977 // Fork a process that will write the lines to the
4978 // external program.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004979 if ((wpid = fork()) == -1)
4980 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004981 msg_puts(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004982 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004983 else if (wpid == 0) // child
Bram Moolenaardf177f62005-02-22 08:39:57 +00004984 {
4985 linenr_T lnum = curbuf->b_op_start.lnum;
4986 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004987 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004988 size_t l;
4989
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004990 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004991 for (;;)
4992 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004993 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004994 if (l == 0)
4995 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004996 else if (lp[written] == NL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004997 // NL -> NUL translation
Bram Moolenaardf177f62005-02-22 08:39:57 +00004998 len = write(toshell_fd, "", (size_t)1);
4999 else
5000 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01005001 char_u *s = vim_strchr(lp + written, NL);
5002
Bram Moolenaar89d40322006-08-29 15:30:07 +00005003 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00005004 s == NULL ? l
5005 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00005006 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00005007 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00005008 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005009 // Finished a line, add a NL, unless this line
5010 // should not have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005011 if (lnum != curbuf->b_op_end.lnum
Bram Moolenaar34d72d42015-07-17 14:18:08 +02005012 || (!curbuf->b_p_bin
5013 && curbuf->b_p_fixeol)
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005014 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00005015 && (lnum !=
5016 curbuf->b_ml.ml_line_count
5017 || curbuf->b_p_eol)))
Bram Moolenaar42335f52018-09-13 15:33:43 +02005018 vim_ignored = write(toshell_fd, "\n",
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00005019 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005020 ++lnum;
5021 if (lnum > curbuf->b_op_end.lnum)
5022 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005023 // finished all the lines, close pipe
Bram Moolenaardf177f62005-02-22 08:39:57 +00005024 close(toshell_fd);
5025 toshell_fd = -1;
5026 break;
5027 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00005028 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005029 written = 0;
5030 }
5031 else if (len > 0)
5032 written += len;
5033 }
5034 _exit(0);
5035 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01005036 else // parent
Bram Moolenaardf177f62005-02-22 08:39:57 +00005037 {
5038 close(toshell_fd);
5039 toshell_fd = -1;
5040 }
5041 }
5042
5043 if (options & SHELL_READ)
5044 ga_init2(&ga, 1, BUFLEN);
5045
5046 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005047# ifdef ELAPSED_FUNC
5048 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005049# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005050 for (;;)
5051 {
5052 /*
5053 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005054 * if there are any.
5055 * Don't do this if we are expanding wild cards (would eat
5056 * typeahead).
5057 * Don't do this when filtering and terminal is in cooked
5058 * mode, the shell command will handle the I/O. Avoids
5059 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005060 * Don't get characters when the child has already
5061 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00005062 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005063 * while (noread_cnt > 4), avoids that ":r !ls" eats
5064 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005065 */
5066 len = 0;
5067 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005068 && ((options &
5069 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
5070 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005071# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005072 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005073# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005074 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005075 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005076 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005077 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005078 if (ta_len == 0)
5079 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005080 // Get extra characters when we don't have any.
5081 // Reset the counter and timer.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005082 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005083# ifdef ELAPSED_FUNC
5084 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005085# endif
5086 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
5087 }
5088 if (ta_len > 0 || len > 0)
5089 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005090 /*
5091 * For pipes:
5092 * Check for CTRL-C: send interrupt signal to child.
5093 * Check for CTRL-D: EOF, close pipe to child.
5094 */
5095 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
5096 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005097 /*
5098 * Send SIGINT to the child's group or all
5099 * processes in our group.
5100 */
Bram Moolenaarfae42832017-08-01 22:24:26 +02005101 may_send_sigint(ta_buf[ta_len], pid, wpid);
5102
Bram Moolenaar071d4272004-06-13 20:20:40 +00005103 if (pty_master_fd < 0 && toshell_fd >= 0
5104 && ta_buf[ta_len] == Ctrl_D)
5105 {
5106 close(toshell_fd);
5107 toshell_fd = -1;
5108 }
5109 }
5110
Bram Moolenaarf4140482020-02-15 23:06:45 +01005111 term_replace_bs_del_keycode(ta_buf, ta_len, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005112
5113 /*
5114 * For pipes: echo the typed characters.
5115 * For a pty this does not seem to work.
5116 */
5117 if (pty_master_fd < 0)
5118 {
5119 for (i = ta_len; i < ta_len + len; ++i)
5120 {
5121 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
5122 msg_putchar(ta_buf[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005123 else if (has_mbyte)
5124 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005125 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005126
5127 msg_outtrans_len(ta_buf + i, l);
5128 i += l - 1;
5129 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005130 else
5131 msg_outtrans_len(ta_buf + i, 1);
5132 }
5133 windgoto(msg_row, msg_col);
5134 out_flush();
5135 }
5136
5137 ta_len += len;
5138
5139 /*
5140 * Write the characters to the child, unless EOF has
5141 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005142 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005143 * When writing buffer lines, drop the typed
5144 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005145 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005146 if (options & SHELL_WRITE)
5147 ta_len = 0;
5148 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005149 {
5150 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
5151 if (len > 0)
5152 {
5153 ta_len -= len;
5154 mch_memmove(ta_buf, ta_buf + len, ta_len);
5155 }
5156 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005157 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005158 }
5159
Bram Moolenaardf177f62005-02-22 08:39:57 +00005160 if (got_int)
5161 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005162 // CTRL-C sends a signal to the child, we ignore it
5163 // ourselves
Bram Moolenaardf177f62005-02-22 08:39:57 +00005164# ifdef HAVE_SETSID
5165 kill(-pid, SIGINT);
5166# else
5167 kill(0, SIGINT);
5168# endif
5169 if (wpid > 0)
5170 kill(wpid, SIGINT);
5171 got_int = FALSE;
5172 }
5173
Bram Moolenaar071d4272004-06-13 20:20:40 +00005174 /*
5175 * Check if the child has any characters to be printed.
5176 * Read them and write them to our window. Repeat this as
5177 * long as there is something to do, avoid the 10ms wait
5178 * for mch_inchar(), or sending typeahead characters to
5179 * the external process.
5180 * TODO: This should handle escape sequences, compatible
5181 * to some terminal (vt52?).
5182 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005183 ++noread_cnt;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005184 while (RealWaitForChar(fromshell_fd, 10L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005185 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005186 len = read_eintr(fromshell_fd, buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00005187 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005188 );
Bram Moolenaar0f873732019-12-05 20:28:46 +01005189 if (len <= 0) // end of file or error
Bram Moolenaar071d4272004-06-13 20:20:40 +00005190 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005191
5192 noread_cnt = 0;
5193 if (options & SHELL_READ)
5194 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005195 // Do NUL -> NL translation, append NL separated
5196 // lines to the current buffer.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005197 for (i = 0; i < len; ++i)
5198 {
5199 if (buffer[i] == NL)
5200 append_ga_line(&ga);
5201 else if (buffer[i] == NUL)
5202 ga_append(&ga, NL);
5203 else
5204 ga_append(&ga, buffer[i]);
5205 }
5206 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005207 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005208 {
5209 int l;
Bram Moolenaara2150ac2018-03-17 13:15:17 +01005210 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005211
Bram Moolenaardf177f62005-02-22 08:39:57 +00005212 len += buffer_off;
5213 buffer[len] = NUL;
5214
Bram Moolenaar0f873732019-12-05 20:28:46 +01005215 // Check if the last character in buffer[] is
5216 // incomplete, keep these bytes for the next
5217 // round.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005218 for (p = buffer; p < buffer + len; p += l)
5219 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02005220 l = MB_CPTR2LEN(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221 if (l == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005222 l = 1; // NUL byte?
Bram Moolenaar071d4272004-06-13 20:20:40 +00005223 else if (MB_BYTE2LEN(*p) != l)
5224 break;
5225 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01005226 if (p == buffer) // no complete character
Bram Moolenaar071d4272004-06-13 20:20:40 +00005227 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005228 // avoid getting stuck at an illegal byte
Bram Moolenaar071d4272004-06-13 20:20:40 +00005229 if (len >= 12)
5230 ++p;
5231 else
5232 {
5233 buffer_off = len;
5234 continue;
5235 }
5236 }
5237 c = *p;
5238 *p = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005239 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005240 if (p < buffer + len)
5241 {
5242 *p = c;
5243 buffer_off = (buffer + len) - p;
5244 mch_memmove(buffer, p, buffer_off);
5245 continue;
5246 }
5247 buffer_off = 0;
5248 }
5249 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005250 {
5251 buffer[len] = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005252 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005253 }
5254
5255 windgoto(msg_row, msg_col);
5256 cursor_on();
5257 out_flush();
5258 if (got_int)
5259 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005260
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005261# ifdef ELAPSED_FUNC
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005262 if (wait_pid == 0)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005263 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005264 long msec = ELAPSED_FUNC(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005265
Bram Moolenaar0f873732019-12-05 20:28:46 +01005266 // Avoid that we keep looping here without
5267 // checking for a CTRL-C for a long time. Don't
5268 // break out too often to avoid losing typeahead.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005269 if (msec > 2000)
5270 {
5271 noread_cnt = 5;
5272 break;
5273 }
5274 }
5275# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005276 }
5277
Bram Moolenaar0f873732019-12-05 20:28:46 +01005278 // If we already detected the child has finished, continue
5279 // reading output for a short while. Some text may be
5280 // buffered.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005281 if (wait_pid == pid)
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005282 {
5283 if (noread_cnt < 5)
5284 continue;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005285 break;
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005286 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005287
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288 /*
5289 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005290 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005291 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005292# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02005293 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005294# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005295 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005296# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005297 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5298 || (wait_pid == pid && WIFEXITED(status)))
5299 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005300 // Don't break the loop yet, try reading more
5301 // characters from "fromshell_fd" first. When using
5302 // pipes there might still be something to read and
5303 // then we'll break the loop at the "break" above.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005304 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005305 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005306 else
5307 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005308
Bram Moolenaar95a51352013-03-21 22:53:50 +01005309# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005310 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005311 clip_update();
5312# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005313 }
5314finished:
5315 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005316 if (options & SHELL_READ)
5317 {
5318 if (ga.ga_len > 0)
5319 {
5320 append_ga_line(&ga);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005321 // remember that the NL was missing
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005322 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005323 }
5324 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005325 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005326 ga_clear(&ga);
5327 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005328
Bram Moolenaar071d4272004-06-13 20:20:40 +00005329 /*
5330 * Give all typeahead that wasn't used back to ui_inchar().
5331 */
5332 if (ta_len)
5333 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005334 State = old_State;
5335 if (toshell_fd >= 0)
5336 close(toshell_fd);
5337 close(fromshell_fd);
5338 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01005339# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005340 else
5341 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005342 long delay_msec = 1;
5343
Bram Moolenaar8a3da6a2020-12-08 19:18:37 +01005344 if (tmode == TMODE_RAW)
5345 // possibly disables modifyOtherKeys, so that the system
5346 // can recognize CTRL-C
5347 out_str(T_CTE);
Bram Moolenaar0981c872020-08-23 14:28:37 +02005348
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005349 /*
5350 * Similar to the loop above, but only handle X events, no
5351 * I/O.
5352 */
5353 for (;;)
5354 {
5355 if (got_int)
5356 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005357 // CTRL-C sends a signal to the child, we ignore it
5358 // ourselves
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005359# ifdef HAVE_SETSID
5360 kill(-pid, SIGINT);
5361# else
5362 kill(0, SIGINT);
5363# endif
5364 got_int = FALSE;
5365 }
5366# ifdef __NeXT__
5367 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
5368# else
5369 wait_pid = waitpid(pid, &status, WNOHANG);
5370# endif
5371 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5372 || (wait_pid == pid && WIFEXITED(status)))
5373 {
5374 wait_pid = pid;
5375 break;
5376 }
5377
Bram Moolenaar0f873732019-12-05 20:28:46 +01005378 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005379 clip_update();
5380
Bram Moolenaar0f873732019-12-05 20:28:46 +01005381 // Wait for 1 to 10 msec. 1 is faster but gives the child
Bram Moolenaar0981c872020-08-23 14:28:37 +02005382 // less time, gradually wait longer.
5383 mch_delay(delay_msec,
5384 MCH_DELAY_IGNOREINPUT | MCH_DELAY_SETTMODE);
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005385 if (++delay_msec > 10)
5386 delay_msec = 10;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005387 }
Bram Moolenaar0981c872020-08-23 14:28:37 +02005388
Bram Moolenaar8a3da6a2020-12-08 19:18:37 +01005389 if (tmode == TMODE_RAW)
5390 // possibly enables modifyOtherKeys again
5391 out_str(T_CTI);
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005392 }
5393# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005394
5395 /*
5396 * Wait until our child has exited.
5397 * Ignore wait() returning pids of other children and returning
5398 * because of some signal like SIGWINCH.
5399 * Don't wait if wait_pid was already set above, indicating the
5400 * child already exited.
5401 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02005402 if (wait_pid != pid)
5403 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005404
Bram Moolenaar624891f2010-10-13 16:22:09 +02005405# ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01005406 // Close slave side of pty. Only do this after the child has
5407 // exited, otherwise the child may hang when it tries to write on
5408 // the pty.
Bram Moolenaar624891f2010-10-13 16:22:09 +02005409 if (pty_master_fd >= 0)
5410 close(pty_slave_fd);
5411# endif
5412
Bram Moolenaar0f873732019-12-05 20:28:46 +01005413 // Make sure the child that writes to the external program is
5414 // dead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005415 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02005416 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00005417 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02005418 wait4pid(wpid, NULL);
5419 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005420
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005421# ifdef FEAT_JOB_CHANNEL
5422 --dont_check_job_ended;
5423# endif
5424
Bram Moolenaar071d4272004-06-13 20:20:40 +00005425 /*
5426 * Set to raw mode right now, otherwise a CTRL-C after
5427 * catch_signals() will kill Vim.
5428 */
5429 if (tmode == TMODE_RAW)
5430 settmode(TMODE_RAW);
5431 did_settmode = TRUE;
5432 set_signals();
5433
5434 if (WIFEXITED(status))
5435 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005436 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar071d4272004-06-13 20:20:40 +00005437 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01005438 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005439 {
5440 if (retval == EXEC_FAILED)
5441 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005442 msg_puts(_("\nCannot execute shell "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005443 msg_outtrans(p_sh);
5444 msg_putchar('\n');
5445 }
5446 else if (!(options & SHELL_SILENT))
5447 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005448 msg_puts(_("\nshell returned "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005449 msg_outnum((long)retval);
5450 msg_putchar('\n');
5451 }
5452 }
5453 }
5454 else
Bram Moolenaar32526b32019-01-19 17:43:09 +01005455 msg_puts(_("\nCommand terminated\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005456 }
5457 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005458
5459error:
5460 if (!did_settmode)
5461 if (tmode == TMODE_RAW)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005462 settmode(TMODE_RAW); // set to raw mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00005463 resettitle();
Bram Moolenaar13568252018-03-16 20:46:58 +01005464 vim_free(argv);
5465 vim_free(tofree1);
5466 vim_free(tofree2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005467
5468 return retval;
Bram Moolenaar13568252018-03-16 20:46:58 +01005469}
Bram Moolenaar0f873732019-12-05 20:28:46 +01005470#endif // USE_SYSTEM
Bram Moolenaar13568252018-03-16 20:46:58 +01005471
5472 int
5473mch_call_shell(
5474 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01005475 int options) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01005476{
5477#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
5478 if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL)
5479 return mch_call_shell_terminal(cmd, options);
5480#endif
5481#ifdef USE_SYSTEM
5482 return mch_call_shell_system(cmd, options);
5483#else
5484 return mch_call_shell_fork(cmd, options);
5485#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005486}
5487
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005488#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005489 void
Bram Moolenaar493359e2018-06-12 20:25:52 +02005490mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005491{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005492 pid_t pid;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005493 int fd_in[2] = {-1, -1}; // for stdin
5494 int fd_out[2] = {-1, -1}; // for stdout
5495 int fd_err[2] = {-1, -1}; // for stderr
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005496 int pty_master_fd = -1;
5497 int pty_slave_fd = -1;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01005498 channel_T *channel = NULL;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005499 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
5500 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
5501 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005502 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005503 int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
5504 int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
Bram Moolenaarb2412082017-08-20 18:09:14 +02005505 int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER;
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005506 int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005507 SIGSET_DECL(curset)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005508
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005509 if (use_out_for_err && use_null_for_out)
5510 use_null_for_err = TRUE;
5511
Bram Moolenaar0f873732019-12-05 20:28:46 +01005512 // default is to fail
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005513 job->jv_status = JOB_FAILED;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005514
Bram Moolenaarb2412082017-08-20 18:09:14 +02005515 if (options->jo_pty
5516 && (!(use_file_for_in || use_null_for_in)
Bram Moolenaar59386482019-02-10 22:43:46 +01005517 || !(use_file_for_out || use_null_for_out)
Bram Moolenaarb2412082017-08-20 18:09:14 +02005518 || !(use_out_for_err || use_file_for_err || use_null_for_err)))
Bram Moolenaar59386482019-02-10 22:43:46 +01005519 open_pty(&pty_master_fd, &pty_slave_fd,
5520 &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005521
Bram Moolenaar0f873732019-12-05 20:28:46 +01005522 // TODO: without the channel feature connect the child to /dev/null?
5523 // Open pipes for stdin, stdout, stderr.
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005524 if (use_file_for_in)
5525 {
5526 char_u *fname = options->jo_io_name[PART_IN];
5527
5528 fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
5529 if (fd_in[0] < 0)
5530 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005531 semsg(_(e_notopen), fname);
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005532 goto failed;
5533 }
5534 }
Bram Moolenaarb2412082017-08-20 18:09:14 +02005535 else
Bram Moolenaar0f873732019-12-05 20:28:46 +01005536 // When writing buffer lines to the input don't use the pty, so that
5537 // the pipe can be closed when all lines were written.
Bram Moolenaarb2412082017-08-20 18:09:14 +02005538 if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in)
5539 && pipe(fd_in) < 0)
5540 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005541
5542 if (use_file_for_out)
5543 {
5544 char_u *fname = options->jo_io_name[PART_OUT];
5545
5546 fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
5547 if (fd_out[1] < 0)
5548 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005549 semsg(_(e_notopen), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005550 goto failed;
5551 }
5552 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005553 else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005554 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005555
5556 if (use_file_for_err)
5557 {
5558 char_u *fname = options->jo_io_name[PART_ERR];
5559
5560 fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
5561 if (fd_err[1] < 0)
5562 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005563 semsg(_(e_notopen), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005564 goto failed;
5565 }
5566 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005567 else if (!use_out_for_err && !use_null_for_err
5568 && pty_master_fd < 0 && pipe(fd_err) < 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005569 goto failed;
5570
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005571 if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5572 {
Bram Moolenaarde279892016-03-11 22:19:44 +01005573 if (options->jo_set & JO_CHANNEL)
5574 {
5575 channel = options->jo_channel;
5576 if (channel != NULL)
5577 ++channel->ch_refcount;
5578 }
5579 else
5580 channel = add_channel();
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005581 if (channel == NULL)
5582 goto failed;
Bram Moolenaarf3360612017-10-01 16:21:31 +02005583 if (job->jv_tty_out != NULL)
5584 ch_log(channel, "using pty %s on fd %d",
5585 job->jv_tty_out, pty_master_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005586 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005587
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005588 BLOCK_SIGNALS(&curset);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005589 pid = fork(); // maybe we should use vfork()
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005590 if (pid == -1)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005591 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005592 // failed to fork
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005593 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005594 goto failed;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005595 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005596 if (pid == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005597 {
Bram Moolenaar4694a172016-04-21 14:05:23 +02005598 int null_fd = -1;
5599 int stderr_works = TRUE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005600
Bram Moolenaar0f873732019-12-05 20:28:46 +01005601 // child
5602 reset_signals(); // handle signals normally
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005603 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005604
Bram Moolenaar819524702018-02-27 19:10:00 +01005605# ifdef FEAT_JOB_CHANNEL
5606 if (ch_log_active())
Bram Moolenaar0f873732019-12-05 20:28:46 +01005607 // close the log file in the child
Bram Moolenaar819524702018-02-27 19:10:00 +01005608 ch_logfile((char_u *)"", (char_u *)"");
5609# endif
5610
Bram Moolenaar835dc632016-02-07 14:27:38 +01005611# ifdef HAVE_SETSID
Bram Moolenaar0f873732019-12-05 20:28:46 +01005612 // Create our own process group, so that the child and all its
5613 // children can be kill()ed. Don't do this when using pipes,
5614 // because stdin is not a tty, we would lose /dev/tty.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005615 (void)setsid();
5616# endif
5617
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005618# ifdef FEAT_TERMINAL
5619 if (options->jo_term_rows > 0)
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005620 {
5621 char *term = (char *)T_NAME;
5622
5623#ifdef FEAT_GUI
5624 if (term_is_gui(T_NAME))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005625 // In the GUI 'term' is not what we want, use $TERM.
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005626 term = getenv("TERM");
5627#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005628 // Use 'term' or $TERM if it starts with "xterm", otherwise fall
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005629 // back to "xterm" or "xterm-color".
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005630 if (term == NULL || *term == NUL || STRNCMP(term, "xterm", 5) != 0)
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005631 {
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005632 if (t_colors >= 256)
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005633 // TODO: should we check this name is supported?
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005634 term = "xterm-256color";
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005635 else if (t_colors > 16)
5636 term = "xterm-color";
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005637 else
5638 term = "xterm";
5639 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005640 set_child_environment(
5641 (long)options->jo_term_rows,
5642 (long)options->jo_term_cols,
Bram Moolenaar493359e2018-06-12 20:25:52 +02005643 term,
5644 is_terminal);
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005645 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005646 else
5647# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02005648 set_default_child_environment(is_terminal);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005649
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005650 if (options->jo_env != NULL)
5651 {
5652 dict_T *dict = options->jo_env;
5653 hashitem_T *hi;
5654 int todo = (int)dict->dv_hashtab.ht_used;
5655
5656 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
5657 if (!HASHITEM_EMPTY(hi))
5658 {
5659 typval_T *item = &dict_lookup(hi)->di_tv;
5660
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005661 vim_setenv((char_u*)hi->hi_key, tv_get_string(item));
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005662 --todo;
5663 }
5664 }
5665
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005666 if (use_null_for_in || use_null_for_out || use_null_for_err)
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005667 {
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005668 null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005669 if (null_fd < 0)
5670 {
5671 perror("opening /dev/null failed");
5672 _exit(OPEN_NULL_FAILED);
5673 }
5674 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005675
Bram Moolenaar223896d2017-08-02 22:33:28 +02005676 if (pty_slave_fd >= 0)
5677 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005678 // push stream discipline modules
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01005679 setup_slavepty(pty_slave_fd);
Bram Moolenaar223896d2017-08-02 22:33:28 +02005680# ifdef TIOCSCTTY
Bram Moolenaar0f873732019-12-05 20:28:46 +01005681 // Try to become controlling tty (probably doesn't work,
5682 // unless run by root)
Bram Moolenaar223896d2017-08-02 22:33:28 +02005683 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
5684# endif
5685 }
5686
Bram Moolenaar0f873732019-12-05 20:28:46 +01005687 // set up stdin for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005688 close(0);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005689 if (use_null_for_in && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005690 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005691 else if (fd_in[0] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005692 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005693 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005694 vim_ignored = dup(fd_in[0]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005695
Bram Moolenaar0f873732019-12-05 20:28:46 +01005696 // set up stderr for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005697 close(2);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005698 if (use_null_for_err && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005699 {
Bram Moolenaar42335f52018-09-13 15:33:43 +02005700 vim_ignored = dup(null_fd);
Bram Moolenaar4694a172016-04-21 14:05:23 +02005701 stderr_works = FALSE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005702 }
5703 else if (use_out_for_err)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005704 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005705 else if (fd_err[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005706 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005707 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005708 vim_ignored = dup(fd_err[1]);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005709
Bram Moolenaar0f873732019-12-05 20:28:46 +01005710 // set up stdout for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005711 close(1);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005712 if (use_null_for_out && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005713 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005714 else if (fd_out[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005715 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005716 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005717 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005718
5719 if (fd_in[0] >= 0)
5720 close(fd_in[0]);
5721 if (fd_in[1] >= 0)
5722 close(fd_in[1]);
5723 if (fd_out[0] >= 0)
5724 close(fd_out[0]);
5725 if (fd_out[1] >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005726 close(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005727 if (fd_err[0] >= 0)
5728 close(fd_err[0]);
5729 if (fd_err[1] >= 0)
5730 close(fd_err[1]);
5731 if (pty_master_fd >= 0)
5732 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005733 close(pty_master_fd); // not used in the child
5734 close(pty_slave_fd); // was duped above
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005735 }
Bram Moolenaarea83bf02016-05-08 09:40:51 +02005736
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005737 if (null_fd >= 0)
5738 close(null_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005739
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005740 if (options->jo_cwd != NULL && mch_chdir((char *)options->jo_cwd) != 0)
5741 _exit(EXEC_FAILED);
5742
Bram Moolenaar0f873732019-12-05 20:28:46 +01005743 // See above for type of argv.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005744 execvp(argv[0], argv);
5745
Bram Moolenaar4694a172016-04-21 14:05:23 +02005746 if (stderr_works)
5747 perror("executing job failed");
Bram Moolenaarfae42832017-08-01 22:24:26 +02005748# ifdef EXITFREE
Bram Moolenaar0f873732019-12-05 20:28:46 +01005749 // calling free_all_mem() here causes problems. Ignore valgrind
5750 // reporting possibly leaked memory.
Bram Moolenaarfae42832017-08-01 22:24:26 +02005751# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005752 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar835dc632016-02-07 14:27:38 +01005753 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005754
Bram Moolenaar0f873732019-12-05 20:28:46 +01005755 // parent
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005756 UNBLOCK_SIGNALS(&curset);
5757
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005758 job->jv_pid = pid;
5759 job->jv_status = JOB_STARTED;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005760 job->jv_channel = channel; // ch_refcount was set above
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005761
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005762 if (pty_master_fd >= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005763 close(pty_slave_fd); // not used in the parent
5764 // close child stdin, stdout and stderr
Bram Moolenaar819524702018-02-27 19:10:00 +01005765 if (fd_in[0] >= 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005766 close(fd_in[0]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005767 if (fd_out[1] >= 0)
Bram Moolenaare98d1212016-03-08 15:37:41 +01005768 close(fd_out[1]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005769 if (fd_err[1] >= 0)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005770 close(fd_err[1]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005771 if (channel != NULL)
5772 {
Bram Moolenaar652de232019-04-04 20:13:09 +02005773 int in_fd = INVALID_FD;
5774 int out_fd = INVALID_FD;
5775 int err_fd = INVALID_FD;
5776
5777 if (!(use_file_for_in || use_null_for_in))
5778 in_fd = fd_in[1] >= 0 ? fd_in[1] : pty_master_fd;
5779
5780 if (!(use_file_for_out || use_null_for_out))
5781 out_fd = fd_out[0] >= 0 ? fd_out[0] : pty_master_fd;
5782
5783 // When using pty_master_fd only set it for stdout, do not duplicate
5784 // it for stderr, it only needs to be read once.
5785 if (!(use_out_for_err || use_file_for_err || use_null_for_err))
5786 {
5787 if (fd_err[0] >= 0)
5788 err_fd = fd_err[0];
5789 else if (out_fd != pty_master_fd)
5790 err_fd = pty_master_fd;
5791 }
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005792
5793 channel_set_pipes(channel, in_fd, out_fd, err_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005794 channel_set_job(channel, job, options);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005795 }
Bram Moolenaar979e8c52017-08-01 15:08:07 +02005796 else
5797 {
5798 if (fd_in[1] >= 0)
5799 close(fd_in[1]);
5800 if (fd_out[0] >= 0)
5801 close(fd_out[0]);
5802 if (fd_err[0] >= 0)
5803 close(fd_err[0]);
5804 if (pty_master_fd >= 0)
5805 close(pty_master_fd);
5806 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005807
Bram Moolenaar0f873732019-12-05 20:28:46 +01005808 // success!
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005809 return;
5810
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005811failed:
Bram Moolenaarde279892016-03-11 22:19:44 +01005812 channel_unref(channel);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005813 if (fd_in[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005814 close(fd_in[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005815 if (fd_in[1] >= 0)
5816 close(fd_in[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005817 if (fd_out[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005818 close(fd_out[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005819 if (fd_out[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005820 close(fd_out[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005821 if (fd_err[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005822 close(fd_err[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005823 if (fd_err[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005824 close(fd_err[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005825 if (pty_master_fd >= 0)
5826 close(pty_master_fd);
5827 if (pty_slave_fd >= 0)
5828 close(pty_slave_fd);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005829}
5830
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005831 static char_u *
5832get_signal_name(int sig)
5833{
5834 int i;
5835 char_u numbuf[NUMBUFLEN];
5836
5837 if (sig == SIGKILL)
5838 return vim_strsave((char_u *)"kill");
5839
5840 for (i = 0; signal_info[i].sig != -1; i++)
5841 if (sig == signal_info[i].sig)
5842 return strlow_save((char_u *)signal_info[i].name);
5843
5844 vim_snprintf((char *)numbuf, NUMBUFLEN, "%d", sig);
5845 return vim_strsave(numbuf);
5846}
5847
Bram Moolenaar835dc632016-02-07 14:27:38 +01005848 char *
5849mch_job_status(job_T *job)
5850{
5851# ifdef HAVE_UNION_WAIT
5852 union wait status;
5853# else
5854 int status = -1;
5855# endif
5856 pid_t wait_pid = 0;
5857
5858# ifdef __NeXT__
5859 wait_pid = wait4(job->jv_pid, &status, WNOHANG, (struct rusage *)0);
5860# else
5861 wait_pid = waitpid(job->jv_pid, &status, WNOHANG);
5862# endif
5863 if (wait_pid == -1)
5864 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005865 // process must have exited
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005866 if (job->jv_status < JOB_ENDED)
5867 ch_log(job->jv_channel, "Job no longer exists: %s",
5868 strerror(errno));
Bram Moolenaar97792de2016-10-15 18:36:49 +02005869 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005870 }
5871 if (wait_pid == 0)
5872 return "run";
5873 if (WIFEXITED(status))
5874 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005875 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar835dc632016-02-07 14:27:38 +01005876 job->jv_exitval = WEXITSTATUS(status);
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005877 if (job->jv_status < JOB_ENDED)
5878 ch_log(job->jv_channel, "Job exited with %d", job->jv_exitval);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005879 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005880 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005881 if (WIFSIGNALED(status))
5882 {
5883 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005884 job->jv_termsig = get_signal_name(WTERMSIG(status));
5885 if (job->jv_status < JOB_ENDED && job->jv_termsig != NULL)
5886 ch_log(job->jv_channel, "Job terminated by signal \"%s\"",
5887 job->jv_termsig);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005888 goto return_dead;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005889 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01005890 return "run";
Bram Moolenaar97792de2016-10-15 18:36:49 +02005891
5892return_dead:
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005893 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005894 job->jv_status = JOB_ENDED;
Bram Moolenaar97792de2016-10-15 18:36:49 +02005895 return "dead";
5896}
5897
5898 job_T *
5899mch_detect_ended_job(job_T *job_list)
5900{
5901# ifdef HAVE_UNION_WAIT
5902 union wait status;
5903# else
5904 int status = -1;
5905# endif
5906 pid_t wait_pid = 0;
5907 job_T *job;
5908
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005909# ifndef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01005910 // Do not do this when waiting for a shell command to finish, we would get
5911 // the exit value here (and discard it), the exit value obtained there
5912 // would then be wrong.
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005913 if (dont_check_job_ended > 0)
5914 return NULL;
5915# endif
5916
Bram Moolenaar97792de2016-10-15 18:36:49 +02005917# ifdef __NeXT__
5918 wait_pid = wait4(-1, &status, WNOHANG, (struct rusage *)0);
5919# else
5920 wait_pid = waitpid(-1, &status, WNOHANG);
5921# endif
5922 if (wait_pid <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005923 // no process ended
Bram Moolenaar97792de2016-10-15 18:36:49 +02005924 return NULL;
5925 for (job = job_list; job != NULL; job = job->jv_next)
5926 {
5927 if (job->jv_pid == wait_pid)
5928 {
5929 if (WIFEXITED(status))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005930 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar97792de2016-10-15 18:36:49 +02005931 job->jv_exitval = WEXITSTATUS(status);
5932 else if (WIFSIGNALED(status))
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005933 {
Bram Moolenaar97792de2016-10-15 18:36:49 +02005934 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005935 job->jv_termsig = get_signal_name(WTERMSIG(status));
5936 }
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005937 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005938 {
5939 ch_log(job->jv_channel, "Job ended");
5940 job->jv_status = JOB_ENDED;
5941 }
5942 return job;
5943 }
5944 }
5945 return NULL;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005946}
5947
Bram Moolenaar3a117e12016-10-30 21:57:52 +01005948/*
5949 * Send a (deadly) signal to "job".
5950 * Return FAIL if "how" is not a valid name.
5951 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01005952 int
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005953mch_signal_job(job_T *job, char_u *how)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005954{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005955 int sig = -1;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005956
Bram Moolenaar923d9262016-02-25 20:56:01 +01005957 if (*how == NUL || STRCMP(how, "term") == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005958 sig = SIGTERM;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005959 else if (STRCMP(how, "hup") == 0)
5960 sig = SIGHUP;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005961 else if (STRCMP(how, "quit") == 0)
5962 sig = SIGQUIT;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005963 else if (STRCMP(how, "int") == 0)
5964 sig = SIGINT;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005965 else if (STRCMP(how, "kill") == 0)
5966 sig = SIGKILL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02005967#ifdef SIGWINCH
5968 else if (STRCMP(how, "winch") == 0)
5969 sig = SIGWINCH;
5970#endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005971 else if (isdigit(*how))
5972 sig = atoi((char *)how);
5973 else
5974 return FAIL;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005975
Bram Moolenaar76ab4fd2018-12-08 14:39:05 +01005976 // Never kill ourselves!
5977 if (job->jv_pid != 0)
5978 {
5979 // TODO: have an option to only kill the process, not the group?
5980 kill(-job->jv_pid, sig);
5981 kill(job->jv_pid, sig);
5982 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005983
Bram Moolenaar835dc632016-02-07 14:27:38 +01005984 return OK;
5985}
Bram Moolenaar76467df2016-02-12 19:30:26 +01005986
5987/*
5988 * Clear the data related to "job".
5989 */
5990 void
5991mch_clear_job(job_T *job)
5992{
Bram Moolenaar0f873732019-12-05 20:28:46 +01005993 // call waitpid because child process may become zombie
Bram Moolenaar76467df2016-02-12 19:30:26 +01005994# ifdef __NeXT__
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005995 (void)wait4(job->jv_pid, NULL, WNOHANG, (struct rusage *)0);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005996# else
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005997 (void)waitpid(job->jv_pid, NULL, WNOHANG);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005998# endif
5999}
Bram Moolenaar835dc632016-02-07 14:27:38 +01006000#endif
6001
Bram Moolenaar13ebb032017-08-26 22:02:51 +02006002#if defined(FEAT_TERMINAL) || defined(PROTO)
6003 int
6004mch_create_pty_channel(job_T *job, jobopt_T *options)
6005{
6006 int pty_master_fd = -1;
6007 int pty_slave_fd = -1;
6008 channel_T *channel;
6009
Bram Moolenaar59386482019-02-10 22:43:46 +01006010 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaard0342202020-06-29 22:40:42 +02006011 if (pty_master_fd < 0 || pty_slave_fd < 0)
6012 return FAIL;
Bram Moolenaar13ebb032017-08-26 22:02:51 +02006013 close(pty_slave_fd);
6014
6015 channel = add_channel();
6016 if (channel == NULL)
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02006017 {
6018 close(pty_master_fd);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02006019 return FAIL;
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02006020 }
Bram Moolenaarf3360612017-10-01 16:21:31 +02006021 if (job->jv_tty_out != NULL)
6022 ch_log(channel, "using pty %s on fd %d",
6023 job->jv_tty_out, pty_master_fd);
Bram Moolenaar0f873732019-12-05 20:28:46 +01006024 job->jv_channel = channel; // ch_refcount was set by add_channel()
Bram Moolenaar13ebb032017-08-26 22:02:51 +02006025 channel->ch_keep_open = TRUE;
6026
Bram Moolenaar0f873732019-12-05 20:28:46 +01006027 // Only set the pty_master_fd for stdout, do not duplicate it for stderr,
6028 // it only needs to be read once.
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02006029 channel_set_pipes(channel, pty_master_fd, pty_master_fd, INVALID_FD);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02006030 channel_set_job(channel, job, options);
6031 return OK;
6032}
6033#endif
6034
Bram Moolenaar071d4272004-06-13 20:20:40 +00006035/*
6036 * Check for CTRL-C typed by reading all available characters.
6037 * In cooked mode we should get SIGINT, no need to check.
6038 */
6039 void
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02006040mch_breakcheck(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006041{
Bram Moolenaar26e86442020-05-17 14:06:16 +02006042 if ((mch_cur_tmode == TMODE_RAW || force)
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02006043 && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006044 fill_input_buf(FALSE);
6045}
6046
6047/*
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006048 * Wait "msec" msec until a character is available from the mouse, keyboard,
6049 * from inbuf[].
6050 * "msec" == -1 will block forever.
6051 * Invokes timer callbacks when needed.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006052 * When "ignore_input" is TRUE even check for pending input when input is
6053 * already available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006054 * "interrupted" (if not NULL) is set to TRUE when no character is available
6055 * but something else needs to be done.
Bram Moolenaar40b1b542016-04-20 20:18:23 +02006056 * Returns TRUE when a character is available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006057 * When a GUI is being used, this will never get called -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00006058 */
6059 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006060WaitForChar(long msec, int *interrupted, int ignore_input)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006061{
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006062#ifdef FEAT_TIMERS
Bram Moolenaarc9e649a2017-12-18 18:14:47 +01006063 return ui_wait_for_chars_or_timer(
6064 msec, WaitForCharOrMouse, interrupted, ignore_input) == OK;
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006065#else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006066 return WaitForCharOrMouse(msec, interrupted, ignore_input);
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006067#endif
6068}
6069
6070/*
6071 * Wait "msec" msec until a character is available from the mouse or keyboard
6072 * or from inbuf[].
6073 * "msec" == -1 will block forever.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006074 * for "ignore_input" see WaitForCharOr().
Bram Moolenaarcda77642016-06-04 13:32:35 +02006075 * "interrupted" (if not NULL) is set to TRUE when no character is available
6076 * but something else needs to be done.
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006077 * When a GUI is being used, this will never get called -- webb
6078 */
6079 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006080WaitForCharOrMouse(long msec, int *interrupted, int ignore_input)
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006081{
Bram Moolenaar071d4272004-06-13 20:20:40 +00006082#ifdef FEAT_MOUSE_GPM
6083 int gpm_process_wanted;
6084#endif
6085#ifdef FEAT_XCLIPBOARD
6086 int rest;
6087#endif
6088 int avail;
6089
Bram Moolenaar0f873732019-12-05 20:28:46 +01006090 if (!ignore_input && input_available()) // something in inbuf[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00006091 return 1;
6092
6093#if defined(FEAT_MOUSE_DEC)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006094 // May need to query the mouse position.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006095 if (WantQueryMouse)
6096 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00006097 WantQueryMouse = FALSE;
Bram Moolenaar92fd5992019-05-02 23:00:22 +02006098 if (!no_query_mouse_for_testing)
6099 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006100 }
6101#endif
6102
6103 /*
6104 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
6105 * events. This is a bit complicated, because they might both be defined.
6106 */
6107#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
6108# ifdef FEAT_XCLIPBOARD
6109 rest = 0;
6110 if (do_xterm_trace())
6111 rest = msec;
6112# endif
6113 do
6114 {
6115# ifdef FEAT_XCLIPBOARD
6116 if (rest != 0)
6117 {
6118 msec = XT_TRACE_DELAY;
6119 if (rest >= 0 && rest < XT_TRACE_DELAY)
6120 msec = rest;
6121 if (rest >= 0)
6122 rest -= msec;
6123 }
6124# endif
Bram Moolenaar28e67e02019-08-15 23:05:49 +02006125# ifdef FEAT_SOUND_CANBERRA
6126 // Invoke any pending sound callbacks.
6127 if (has_sound_callback_in_queue())
6128 invoke_sound_callback();
6129# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006130# ifdef FEAT_MOUSE_GPM
6131 gpm_process_wanted = 0;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006132 avail = RealWaitForChar(read_cmd_fd, msec,
Bram Moolenaarcda77642016-06-04 13:32:35 +02006133 &gpm_process_wanted, interrupted);
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006134 if (!avail && !gpm_process_wanted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006135# else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006136 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006137 if (!avail)
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006138# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006139 {
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006140 if (!ignore_input && input_available())
Bram Moolenaar071d4272004-06-13 20:20:40 +00006141 return 1;
6142# ifdef FEAT_XCLIPBOARD
6143 if (rest == 0 || !do_xterm_trace())
6144# endif
6145 break;
6146 }
6147 }
6148 while (FALSE
6149# ifdef FEAT_MOUSE_GPM
6150 || (gpm_process_wanted && mch_gpm_process() == 0)
6151# endif
6152# ifdef FEAT_XCLIPBOARD
6153 || (!avail && rest != 0)
6154# endif
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006155 )
6156 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006157
6158#else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006159 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006160#endif
6161 return avail;
6162}
6163
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01006164#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00006165/*
6166 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006167 * "msec" == 0 will check for characters once.
6168 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006169 * When a GUI is being used, this will not be used for input -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00006170 * Or when a Linux GPM mouse event is waiting.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006171 * Or when a clientserver message is on the queue.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006172 * "interrupted" (if not NULL) is set to TRUE when no character is available
6173 * but something else needs to be done.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006174 */
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006175 static int
Bram Moolenaarcda77642016-06-04 13:32:35 +02006176RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006177{
6178 int ret;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006179 int result;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006180#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006181 static int busy = FALSE;
6182
Bram Moolenaar0f873732019-12-05 20:28:46 +01006183 // May retry getting characters after an event was handled.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006184# define MAY_LOOP
6185
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006186# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006187 // Remember at what time we started, so that we know how much longer we
6188 // should wait after being interrupted.
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01006189 long start_msec = msec;
6190 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006191
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02006192 if (msec > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006193 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006194# endif
6195
Bram Moolenaar0f873732019-12-05 20:28:46 +01006196 // Handle being called recursively. This may happen for the session
6197 // manager stuff, it may save the file, which does a breakcheck.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006198 if (busy)
6199 return 0;
6200#endif
6201
6202#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00006203 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006204#endif
6205 {
6206#ifdef MAY_LOOP
Bram Moolenaar0f873732019-12-05 20:28:46 +01006207 int finished = TRUE; // default is to 'loop' just once
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006208# ifdef FEAT_MZSCHEME
6209 int mzquantum_used = FALSE;
6210# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006211#endif
6212#ifndef HAVE_SELECT
Bram Moolenaar0f873732019-12-05 20:28:46 +01006213 // each channel may use in, out and err
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006214 struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006215 int nfd;
6216# ifdef FEAT_XCLIPBOARD
6217 int xterm_idx = -1;
6218# endif
6219# ifdef FEAT_MOUSE_GPM
6220 int gpm_idx = -1;
6221# endif
6222# ifdef USE_XSMP
6223 int xsmp_idx = -1;
6224# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006225 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006226
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006227# ifdef FEAT_MZSCHEME
6228 mzvim_check_threads();
6229 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6230 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006231 towait = (int)p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006232 mzquantum_used = TRUE;
6233 }
6234# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006235 fds[0].fd = fd;
6236 fds[0].events = POLLIN;
6237 nfd = 1;
6238
Bram Moolenaar071d4272004-06-13 20:20:40 +00006239# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006240 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006241 if (xterm_Shell != (Widget)0)
6242 {
6243 xterm_idx = nfd;
6244 fds[nfd].fd = ConnectionNumber(xterm_dpy);
6245 fds[nfd].events = POLLIN;
6246 nfd++;
6247 }
6248# endif
6249# ifdef FEAT_MOUSE_GPM
6250 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6251 {
6252 gpm_idx = nfd;
6253 fds[nfd].fd = gpm_fd;
6254 fds[nfd].events = POLLIN;
6255 nfd++;
6256 }
6257# endif
6258# ifdef USE_XSMP
6259 if (xsmp_icefd != -1)
6260 {
6261 xsmp_idx = nfd;
6262 fds[nfd].fd = xsmp_icefd;
6263 fds[nfd].events = POLLIN;
6264 nfd++;
6265 }
6266# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006267#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006268 nfd = channel_poll_setup(nfd, &fds, &towait);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006269#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006270 if (interrupted != NULL)
6271 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006272
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006273 ret = poll(fds, nfd, towait);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006274
6275 result = ret > 0 && (fds[0].revents & POLLIN);
Bram Moolenaarcda77642016-06-04 13:32:35 +02006276 if (result == 0 && interrupted != NULL && ret > 0)
6277 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006278
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006279# ifdef FEAT_MZSCHEME
6280 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006281 // MzThreads scheduling is required and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006282 finished = FALSE;
6283# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006284
Bram Moolenaar071d4272004-06-13 20:20:40 +00006285# ifdef FEAT_XCLIPBOARD
6286 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
6287 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006288 xterm_update(); // Maybe we should hand out clipboard
Bram Moolenaar071d4272004-06-13 20:20:40 +00006289 if (--ret == 0 && !input_available())
Bram Moolenaar0f873732019-12-05 20:28:46 +01006290 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006291 finished = FALSE;
6292 }
6293# endif
6294# ifdef FEAT_MOUSE_GPM
6295 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006296 *check_for_gpm = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006297# endif
6298# ifdef USE_XSMP
6299 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
6300 {
6301 if (fds[xsmp_idx].revents & POLLIN)
6302 {
6303 busy = TRUE;
6304 xsmp_handle_requests();
6305 busy = FALSE;
6306 }
6307 else if (fds[xsmp_idx].revents & POLLHUP)
6308 {
6309 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006310 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006311 xsmp_close();
6312 }
6313 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006314 finished = FALSE; // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006315 }
6316# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006317#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006318 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006319 if (ret >= 0)
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006320 channel_poll_check(ret, &fds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006321#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006322
Bram Moolenaar0f873732019-12-05 20:28:46 +01006323#else // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006324
6325 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006326 struct timeval *tvp;
Bram Moolenaar61fb8d82018-11-12 21:45:08 +01006327 // These are static because they can take 8 Kbyte each and cause the
6328 // signal stack to run out with -O3.
6329 static fd_set rfds, wfds, efds;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006330 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006331 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006332
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006333# ifdef FEAT_MZSCHEME
6334 mzvim_check_threads();
6335 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6336 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006337 towait = p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006338 mzquantum_used = TRUE;
6339 }
6340# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006341
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006342 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006343 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006344 tv.tv_sec = towait / 1000;
6345 tv.tv_usec = (towait % 1000) * (1000000/1000);
6346 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006347 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006348 else
6349 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006350
6351 /*
6352 * Select on ready for reading and exceptional condition (end of file).
6353 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006354select_eintr:
6355 FD_ZERO(&rfds);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006356 FD_ZERO(&wfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006357 FD_ZERO(&efds);
6358 FD_SET(fd, &rfds);
6359# if !defined(__QNX__) && !defined(__CYGWIN32__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006360 // For QNX select() always returns 1 if this is set. Why?
Bram Moolenaar071d4272004-06-13 20:20:40 +00006361 FD_SET(fd, &efds);
6362# endif
6363 maxfd = fd;
6364
Bram Moolenaar071d4272004-06-13 20:20:40 +00006365# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006366 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006367 if (xterm_Shell != (Widget)0)
6368 {
6369 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
6370 if (maxfd < ConnectionNumber(xterm_dpy))
6371 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006372
Bram Moolenaar0f873732019-12-05 20:28:46 +01006373 // An event may have already been read but not handled. In
6374 // particularly, XFlush may cause this.
Bram Moolenaardd82d692012-08-15 17:26:57 +02006375 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006376 }
6377# endif
6378# ifdef FEAT_MOUSE_GPM
6379 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6380 {
6381 FD_SET(gpm_fd, &rfds);
6382 FD_SET(gpm_fd, &efds);
6383 if (maxfd < gpm_fd)
6384 maxfd = gpm_fd;
6385 }
6386# endif
6387# ifdef USE_XSMP
6388 if (xsmp_icefd != -1)
6389 {
6390 FD_SET(xsmp_icefd, &rfds);
6391 FD_SET(xsmp_icefd, &efds);
6392 if (maxfd < xsmp_icefd)
6393 maxfd = xsmp_icefd;
6394 }
6395# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006396# ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006397 maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006398# endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006399 if (interrupted != NULL)
6400 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006401
Bram Moolenaar643b6142018-09-12 20:29:09 +02006402 ret = select(maxfd + 1, SELECT_TYPE_ARG234 &rfds,
6403 SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 &efds, tvp);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006404 result = ret > 0 && FD_ISSET(fd, &rfds);
6405 if (result)
6406 --ret;
Bram Moolenaarcda77642016-06-04 13:32:35 +02006407 else if (interrupted != NULL && ret > 0)
6408 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006409
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006410# ifdef EINTR
6411 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006412 {
dbivolaruab16ad32021-12-29 19:41:47 +00006413 // Check whether the EINTR is caused by SIGTSTP
6414 if (got_tstp && !in_mch_suspend)
6415 {
6416 exarg_T ea;
6417 ea.forceit = TRUE;
6418 ex_stop(&ea);
6419 got_tstp = FALSE;
6420 }
6421
Bram Moolenaar0f873732019-12-05 20:28:46 +01006422 // Check whether window has been resized, EINTR may be caused by
6423 // SIGWINCH.
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006424 if (do_resize)
6425 handle_resize();
6426
Bram Moolenaar0f873732019-12-05 20:28:46 +01006427 // Interrupted by a signal, need to try again. We ignore msec
6428 // here, because we do want to check even after a timeout if
6429 // characters are available. Needed for reading output of an
6430 // external command after the process has finished.
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006431 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006432 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006433# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00006434# ifdef __TANDEM
6435 if (ret == -1 && errno == ENOTSUP)
6436 {
6437 FD_ZERO(&rfds);
6438 FD_ZERO(&efds);
6439 ret = 0;
6440 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006441# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006442# ifdef FEAT_MZSCHEME
6443 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006444 // loop if MzThreads must be scheduled and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006445 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006446# endif
6447
Bram Moolenaar071d4272004-06-13 20:20:40 +00006448# ifdef FEAT_XCLIPBOARD
6449 if (ret > 0 && xterm_Shell != (Widget)0
6450 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
6451 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006452 xterm_update(); // Maybe we should hand out clipboard
6453 // continue looping when we only got the X event and the input
6454 // buffer is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00006455 if (--ret == 0 && !input_available())
6456 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006457 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006458 finished = FALSE;
6459 }
6460 }
6461# endif
6462# ifdef FEAT_MOUSE_GPM
6463 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
6464 {
6465 if (FD_ISSET(gpm_fd, &efds))
6466 gpm_close();
6467 else if (FD_ISSET(gpm_fd, &rfds))
6468 *check_for_gpm = 1;
6469 }
6470# endif
6471# ifdef USE_XSMP
6472 if (ret > 0 && xsmp_icefd != -1)
6473 {
6474 if (FD_ISSET(xsmp_icefd, &efds))
6475 {
6476 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006477 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006478 xsmp_close();
6479 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006480 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006481 }
6482 else if (FD_ISSET(xsmp_icefd, &rfds))
6483 {
6484 busy = TRUE;
6485 xsmp_handle_requests();
6486 busy = FALSE;
6487 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006488 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006489 }
6490 }
6491# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006492#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar0f873732019-12-05 20:28:46 +01006493 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006494 if (ret >= 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006495 ret = channel_select_check(ret, &rfds, &wfds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006496#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006497
Bram Moolenaar0f873732019-12-05 20:28:46 +01006498#endif // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006499
6500#ifdef MAY_LOOP
6501 if (finished || msec == 0)
6502 break;
6503
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006504# ifdef FEAT_CLIENTSERVER
6505 if (server_waiting())
6506 break;
6507# endif
6508
Bram Moolenaar0f873732019-12-05 20:28:46 +01006509 // We're going to loop around again, find out for how long
Bram Moolenaar071d4272004-06-13 20:20:40 +00006510 if (msec > 0)
6511 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006512# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006513 // Compute remaining wait time.
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006514 msec = start_msec - ELAPSED_FUNC(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006515# else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006516 // Guess we got interrupted halfway.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006517 msec = msec / 2;
6518# endif
6519 if (msec <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006520 break; // waited long enough
Bram Moolenaar071d4272004-06-13 20:20:40 +00006521 }
6522#endif
6523 }
6524
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006525 return result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006526}
6527
Bram Moolenaar071d4272004-06-13 20:20:40 +00006528/*
Bram Moolenaar02743632005-07-25 20:42:36 +00006529 * Expand a path into all matching files and/or directories. Handles "*",
6530 * "?", "[a-z]", "**", etc.
6531 * "path" has backslashes before chars that are not to be expanded.
6532 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006533 */
6534 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006535mch_expandpath(
6536 garray_T *gap,
6537 char_u *path,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006538 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006539{
Bram Moolenaar02743632005-07-25 20:42:36 +00006540 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006541}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006542
6543/*
6544 * mch_expand_wildcards() - this code does wild-card pattern matching using
6545 * the shell
6546 *
6547 * return OK for success, FAIL for error (you may lose some memory) and put
6548 * an error message in *file.
6549 *
6550 * num_pat is number of input patterns
6551 * pat is array of pointers to input patterns
6552 * num_file is pointer to number of matched file names
6553 * file is pointer to array of pointers to matched file names
6554 */
6555
6556#ifndef SEEK_SET
6557# define SEEK_SET 0
6558#endif
6559#ifndef SEEK_END
6560# define SEEK_END 2
6561#endif
6562
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006563#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00006564
Bram Moolenaar071d4272004-06-13 20:20:40 +00006565 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006566mch_expand_wildcards(
6567 int num_pat,
6568 char_u **pat,
6569 int *num_file,
6570 char_u ***file,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006571 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006572{
6573 int i;
6574 size_t len;
Bram Moolenaar85325f82017-03-30 21:18:45 +02006575 long llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006576 char_u *p;
6577 int dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006578
Bram Moolenaarc7247912008-01-13 12:54:11 +00006579 /*
6580 * This is the non-OS/2 implementation (really Unix).
6581 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006582 int j;
6583 char_u *tempname;
6584 char_u *command;
6585 FILE *fd;
6586 char_u *buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006587#define STYLE_ECHO 0 // use "echo", the default
6588#define STYLE_GLOB 1 // use "glob", for csh
6589#define STYLE_VIMGLOB 2 // use "vimglob", for Posix sh
6590#define STYLE_PRINT 3 // use "print -N", for zsh
6591#define STYLE_BT 4 // `cmd` expansion, execute the pattern
6592 // directly
Bram Moolenaar071d4272004-06-13 20:20:40 +00006593 int shell_style = STYLE_ECHO;
6594 int check_spaces;
6595 static int did_find_nul = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006596 int ampersand = FALSE;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006597 // vimglob() function to define for Posix shell
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006598 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006599
Bram Moolenaar0f873732019-12-05 20:28:46 +01006600 *num_file = 0; // default: no files found
Bram Moolenaar071d4272004-06-13 20:20:40 +00006601 *file = NULL;
6602
6603 /*
6604 * If there are no wildcards, just copy the names to allocated memory.
6605 * Saves a lot of time, because we don't have to start a new shell.
6606 */
6607 if (!have_wildcard(num_pat, pat))
6608 return save_patterns(num_pat, pat, num_file, file);
6609
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006610# ifdef HAVE_SANDBOX
Bram Moolenaar0f873732019-12-05 20:28:46 +01006611 // Don't allow any shell command in the sandbox.
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006612 if (sandbox != 0 && check_secure())
6613 return FAIL;
6614# endif
6615
Bram Moolenaar071d4272004-06-13 20:20:40 +00006616 /*
6617 * Don't allow the use of backticks in secure and restricted mode.
6618 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006619 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006620 for (i = 0; i < num_pat; ++i)
6621 if (vim_strchr(pat[i], '`') != NULL
6622 && (check_restricted() || check_secure()))
6623 return FAIL;
6624
6625 /*
6626 * get a name for the temp file
6627 */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02006628 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006629 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006630 emsg(_(e_notmp));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006631 return FAIL;
6632 }
6633
6634 /*
6635 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00006636 * file.
6637 * STYLE_BT: NL separated
6638 * If expanding `cmd` execute it directly.
6639 * STYLE_GLOB: NUL separated
6640 * If we use *csh, "glob" will work better than "echo".
6641 * STYLE_PRINT: NL or NUL separated
6642 * If we use *zsh, "print -N" will work better than "glob".
6643 * STYLE_VIMGLOB: NL separated
6644 * If we use *sh*, we define "vimglob()".
6645 * STYLE_ECHO: space separated.
6646 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006647 */
6648 if (num_pat == 1 && *pat[0] == '`'
6649 && (len = STRLEN(pat[0])) > 2
6650 && *(pat[0] + len - 1) == '`')
6651 shell_style = STYLE_BT;
6652 else if ((len = STRLEN(p_sh)) >= 3)
6653 {
6654 if (STRCMP(p_sh + len - 3, "csh") == 0)
6655 shell_style = STYLE_GLOB;
6656 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
6657 shell_style = STYLE_PRINT;
6658 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006659 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
6660 "sh") != NULL)
6661 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006662
Bram Moolenaar0f873732019-12-05 20:28:46 +01006663 // Compute the length of the command. We need 2 extra bytes: for the
6664 // optional '&' and for the NUL.
6665 // Worst case: "unset nonomatch; print -N >" plus two is 29
Bram Moolenaar071d4272004-06-13 20:20:40 +00006666 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006667 if (shell_style == STYLE_VIMGLOB)
6668 len += STRLEN(sh_vimglob_func);
6669
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006670 for (i = 0; i < num_pat; ++i)
6671 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006672 // Count the length of the patterns in the same way as they are put in
6673 // "command" below.
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006674#ifdef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01006675 len += STRLEN(pat[i]) + 3; // add space and two quotes
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006676#else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006677 ++len; // add space
Bram Moolenaar316059c2006-01-14 21:18:42 +00006678 for (j = 0; pat[i][j] != NUL; ++j)
6679 {
6680 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006681 ++len; // may add a backslash
Bram Moolenaar316059c2006-01-14 21:18:42 +00006682 ++len;
6683 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006684#endif
6685 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006686 command = alloc(len);
6687 if (command == NULL)
6688 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006689 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006690 vim_free(tempname);
6691 return FAIL;
6692 }
6693
6694 /*
6695 * Build the shell command:
6696 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
6697 * recognizes this).
6698 * - Add the shell command to print the expanded names.
6699 * - Add the temp file name.
6700 * - Add the file name patterns.
6701 */
6702 if (shell_style == STYLE_BT)
6703 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006704 // change `command; command& ` to (command; command )
Bram Moolenaar316059c2006-01-14 21:18:42 +00006705 STRCPY(command, "(");
Bram Moolenaar0f873732019-12-05 20:28:46 +01006706 STRCAT(command, pat[0] + 1); // exclude first backtick
Bram Moolenaar071d4272004-06-13 20:20:40 +00006707 p = command + STRLEN(command) - 1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006708 *p-- = ')'; // remove last backtick
Bram Moolenaar1c465442017-03-12 20:10:05 +01006709 while (p > command && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006710 --p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006711 if (*p == '&') // remove trailing '&'
Bram Moolenaar071d4272004-06-13 20:20:40 +00006712 {
Bram Moolenaarbdace832019-03-02 10:13:42 +01006713 ampersand = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006714 *p = ' ';
6715 }
6716 STRCAT(command, ">");
6717 }
6718 else
6719 {
Christian Brabandt8b8d8292021-11-19 12:37:36 +00006720 STRCPY(command, "");
6721 if (shell_style == STYLE_GLOB)
6722 {
6723 // Assume the nonomatch option is valid only for csh like shells,
6724 // otherwise, this may set the positional parameters for the shell,
6725 // e.g. "$*".
6726 if (flags & EW_NOTFOUND)
6727 STRCAT(command, "set nonomatch; ");
6728 else
6729 STRCAT(command, "unset nonomatch; ");
6730 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006731 if (shell_style == STYLE_GLOB)
6732 STRCAT(command, "glob >");
6733 else if (shell_style == STYLE_PRINT)
6734 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00006735 else if (shell_style == STYLE_VIMGLOB)
6736 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006737 else
6738 STRCAT(command, "echo >");
6739 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006740
Bram Moolenaar071d4272004-06-13 20:20:40 +00006741 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00006742
Bram Moolenaar071d4272004-06-13 20:20:40 +00006743 if (shell_style != STYLE_BT)
6744 for (i = 0; i < num_pat; ++i)
6745 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006746 // When using system() always add extra quotes, because the shell
6747 // is started twice. Otherwise put a backslash before special
6748 // characters, except inside ``.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006749#ifdef USE_SYSTEM
6750 STRCAT(command, " \"");
6751 STRCAT(command, pat[i]);
6752 STRCAT(command, "\"");
6753#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00006754 int intick = FALSE;
6755
Bram Moolenaar071d4272004-06-13 20:20:40 +00006756 p = command + STRLEN(command);
6757 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00006758 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00006759 {
6760 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00006761 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006762 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
6763 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006764 // Remove a backslash, take char literally. But keep
6765 // backslash inside backticks, before a special character
6766 // and before a backtick.
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006767 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00006768 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
6769 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006770 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006771 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006772 }
Bram Moolenaare4df1642014-08-29 12:58:44 +02006773 else if (!intick
6774 && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
6775 && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006776 // Put a backslash before a special character, but not
6777 // when inside ``. And not for $var when EW_KEEPDOLLAR is
6778 // set.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006779 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006780
Bram Moolenaar0f873732019-12-05 20:28:46 +01006781 // Copy one character.
Bram Moolenaar280f1262006-01-30 00:14:18 +00006782 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00006783 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006784 *p = NUL;
6785#endif
6786 }
6787 if (flags & EW_SILENT)
6788 show_shell_mess = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006789 if (ampersand)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006790 STRCAT(command, "&"); // put the '&' after the redirection
Bram Moolenaar071d4272004-06-13 20:20:40 +00006791
6792 /*
6793 * Using zsh -G: If a pattern has no matches, it is just deleted from
6794 * the argument list, otherwise zsh gives an error message and doesn't
6795 * expand any other pattern.
6796 */
6797 if (shell_style == STYLE_PRINT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006798 extra_shell_arg = (char_u *)"-G"; // Use zsh NULL_GLOB option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006799
6800 /*
6801 * If we use -f then shell variables set in .cshrc won't get expanded.
6802 * vi can do it, so we will too, but it is only necessary if there is a "$"
6803 * in one of the patterns, otherwise we can still use the fast option.
6804 */
6805 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
Bram Moolenaar0f873732019-12-05 20:28:46 +01006806 extra_shell_arg = (char_u *)"-f"; // Use csh fast option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006807
6808 /*
6809 * execute the shell command
6810 */
6811 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
6812
Bram Moolenaar0f873732019-12-05 20:28:46 +01006813 // When running in the background, give it some time to create the temp
6814 // file, but don't wait for it to finish.
Bram Moolenaarbdace832019-03-02 10:13:42 +01006815 if (ampersand)
Bram Moolenaar0981c872020-08-23 14:28:37 +02006816 mch_delay(10L, MCH_DELAY_IGNOREINPUT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006817
Bram Moolenaar0f873732019-12-05 20:28:46 +01006818 extra_shell_arg = NULL; // cleanup
Bram Moolenaar071d4272004-06-13 20:20:40 +00006819 show_shell_mess = TRUE;
6820 vim_free(command);
6821
Bram Moolenaar0f873732019-12-05 20:28:46 +01006822 if (i != 0) // mch_call_shell() failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00006823 {
6824 mch_remove(tempname);
6825 vim_free(tempname);
6826 /*
6827 * With interactive completion, the error message is not printed.
6828 * However with USE_SYSTEM, I don't know how to turn off error messages
6829 * from the shell, so screen may still get messed up -- webb.
6830 */
6831#ifndef USE_SYSTEM
6832 if (!(flags & EW_SILENT))
6833#endif
6834 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006835 redraw_later_clear(); // probably messed up screen
6836 msg_putchar('\n'); // clear bottom line quickly
6837 cmdline_row = Rows - 1; // continue on last line
Bram Moolenaar071d4272004-06-13 20:20:40 +00006838#ifdef USE_SYSTEM
6839 if (!(flags & EW_SILENT))
6840#endif
6841 {
Bram Moolenaar40bcec12021-12-05 22:19:27 +00006842 msg(_(e_cannot_expand_wildcards));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006843 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006844 }
6845 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006846 // If a `cmd` expansion failed, don't list `cmd` as a match, even when
6847 // EW_NOTFOUND is given
Bram Moolenaar071d4272004-06-13 20:20:40 +00006848 if (shell_style == STYLE_BT)
6849 return FAIL;
6850 goto notfound;
6851 }
6852
6853 /*
6854 * read the names from the file into memory
6855 */
6856 fd = fopen((char *)tempname, READBIN);
6857 if (fd == NULL)
6858 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006859 // Something went wrong, perhaps a file name with a special char.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006860 if (!(flags & EW_SILENT))
6861 {
Bram Moolenaar40bcec12021-12-05 22:19:27 +00006862 msg(_(e_cannot_expand_wildcards));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006863 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006864 }
6865 vim_free(tempname);
6866 goto notfound;
6867 }
6868 fseek(fd, 0L, SEEK_END);
Bram Moolenaar0f873732019-12-05 20:28:46 +01006869 llen = ftell(fd); // get size of temp file
Bram Moolenaar071d4272004-06-13 20:20:40 +00006870 fseek(fd, 0L, SEEK_SET);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006871 if (llen < 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006872 // just in case ftell() would fail
Bram Moolenaar85325f82017-03-30 21:18:45 +02006873 buffer = NULL;
6874 else
6875 buffer = alloc(llen + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006876 if (buffer == NULL)
6877 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006878 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006879 mch_remove(tempname);
6880 vim_free(tempname);
6881 fclose(fd);
6882 return FAIL;
6883 }
Bram Moolenaar85325f82017-03-30 21:18:45 +02006884 len = llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006885 i = fread((char *)buffer, 1, len, fd);
6886 fclose(fd);
6887 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00006888 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006889 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006890 // unexpected read error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006891 semsg(_(e_notread), tempname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006892 vim_free(tempname);
6893 vim_free(buffer);
6894 return FAIL;
6895 }
6896 vim_free(tempname);
6897
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006898# ifdef __CYGWIN__
Bram Moolenaar0f873732019-12-05 20:28:46 +01006899 // Translate <CR><NL> into <NL>. Caution, buffer may contain NUL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006900 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02006901 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006902 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
6903 *p++ = buffer[i];
6904 len = p - buffer;
6905# endif
6906
6907
Bram Moolenaar0f873732019-12-05 20:28:46 +01006908 // file names are separated with Space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006909 if (shell_style == STYLE_ECHO)
6910 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006911 buffer[len] = '\n'; // make sure the buffer ends in NL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006912 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006913 for (i = 0; *p != '\n'; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006914 {
6915 while (*p != ' ' && *p != '\n')
6916 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006917 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006918 }
6919 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006920 // file names are separated with NL
Bram Moolenaarc7247912008-01-13 12:54:11 +00006921 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006922 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006923 buffer[len] = NUL; // make sure the buffer ends in NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006924 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006925 for (i = 0; *p != NUL; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006926 {
6927 while (*p != '\n' && *p != NUL)
6928 ++p;
6929 if (*p != NUL)
6930 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006931 p = skipwhite(p); // skip leading white space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006932 }
6933 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006934 // file names are separated with NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006935 else
6936 {
6937 /*
6938 * Some versions of zsh use spaces instead of NULs to separate
6939 * results. Only do this when there is no NUL before the end of the
6940 * buffer, otherwise we would never be able to use file names with
6941 * embedded spaces when zsh does use NULs.
6942 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6943 * don't check for spaces again.
6944 */
6945 check_spaces = FALSE;
6946 if (shell_style == STYLE_PRINT && !did_find_nul)
6947 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006948 // If there is a NUL, set did_find_nul, else set check_spaces
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006949 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006950 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006951 did_find_nul = TRUE;
6952 else
6953 check_spaces = TRUE;
6954 }
6955
6956 /*
6957 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6958 * already is one, for STYLE_GLOB it needs to be added.
6959 */
6960 if (len && buffer[len - 1] == NUL)
6961 --len;
6962 else
6963 buffer[len] = NUL;
6964 i = 0;
6965 for (p = buffer; p < buffer + len; ++p)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006966 if (*p == NUL || (*p == ' ' && check_spaces)) // count entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006967 {
6968 ++i;
6969 *p = NUL;
6970 }
6971 if (len)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006972 ++i; // count last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006973 }
6974 if (i == 0)
6975 {
6976 /*
6977 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6978 * /bin/sh will happily expand it to nothing rather than returning an
6979 * error; and hey, it's good to check anyway -- webb.
6980 */
6981 vim_free(buffer);
6982 goto notfound;
6983 }
6984 *num_file = i;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006985 *file = ALLOC_MULT(char_u *, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006986 if (*file == NULL)
6987 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006988 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006989 vim_free(buffer);
6990 return FAIL;
6991 }
6992
6993 /*
6994 * Isolate the individual file names.
6995 */
6996 p = buffer;
6997 for (i = 0; i < *num_file; ++i)
6998 {
6999 (*file)[i] = p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007000 // Space or NL separates
Bram Moolenaarc7247912008-01-13 12:54:11 +00007001 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
7002 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007003 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00007004 while (!(shell_style == STYLE_ECHO && *p == ' ')
7005 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007006 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007007 if (p == buffer + len) // last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00007008 *p = NUL;
7009 else
7010 {
7011 *p++ = NUL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007012 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00007013 }
7014 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007015 else // NUL separates
Bram Moolenaar071d4272004-06-13 20:20:40 +00007016 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007017 while (*p && p < buffer + len) // skip entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00007018 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007019 ++p; // skip NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00007020 }
7021 }
7022
7023 /*
7024 * Move the file names to allocated memory.
7025 */
7026 for (j = 0, i = 0; i < *num_file; ++i)
7027 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007028 // Require the files to exist. Helps when using /bin/sh
Bram Moolenaar071d4272004-06-13 20:20:40 +00007029 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
7030 continue;
7031
Bram Moolenaar0f873732019-12-05 20:28:46 +01007032 // check if this entry should be included
Bram Moolenaar071d4272004-06-13 20:20:40 +00007033 dir = (mch_isdir((*file)[i]));
7034 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
7035 continue;
7036
Bram Moolenaar0f873732019-12-05 20:28:46 +01007037 // Skip files that are not executable if we check for that.
Bram Moolenaarb5971142015-03-21 17:32:19 +01007038 if (!dir && (flags & EW_EXEC)
7039 && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00007040 continue;
7041
Bram Moolenaar964b3742019-05-24 18:54:09 +02007042 p = alloc(STRLEN((*file)[i]) + 1 + dir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007043 if (p)
7044 {
7045 STRCPY(p, (*file)[i]);
7046 if (dir)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007047 add_pathsep(p); // add '/' to a directory name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007048 (*file)[j++] = p;
7049 }
7050 }
7051 vim_free(buffer);
7052 *num_file = j;
7053
Bram Moolenaar0f873732019-12-05 20:28:46 +01007054 if (*num_file == 0) // rejected all entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00007055 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01007056 VIM_CLEAR(*file);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007057 goto notfound;
7058 }
7059
7060 return OK;
7061
7062notfound:
7063 if (flags & EW_NOTFOUND)
7064 return save_patterns(num_pat, pat, num_file, file);
7065 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007066}
7067
Bram Moolenaar0f873732019-12-05 20:28:46 +01007068#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00007069
Bram Moolenaar071d4272004-06-13 20:20:40 +00007070 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007071save_patterns(
7072 int num_pat,
7073 char_u **pat,
7074 int *num_file,
7075 char_u ***file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007076{
7077 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00007078 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007079
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007080 *file = ALLOC_MULT(char_u *, num_pat);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007081 if (*file == NULL)
7082 return FAIL;
7083 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00007084 {
7085 s = vim_strsave(pat[i]);
7086 if (s != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007087 // Be compatible with expand_filename(): halve the number of
7088 // backslashes.
Bram Moolenaard8b02732005-01-14 21:48:43 +00007089 backslash_halve(s);
7090 (*file)[i] = s;
7091 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007092 *num_file = num_pat;
7093 return OK;
7094}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007095
Bram Moolenaar071d4272004-06-13 20:20:40 +00007096/*
7097 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
7098 * expand.
7099 */
7100 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007101mch_has_exp_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007102{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007103 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007104 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007105 if (*p == '\\' && p[1] != NUL)
7106 ++p;
7107 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007108 if (vim_strchr((char_u *)
7109#ifdef VMS
7110 "*?%"
7111#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007112 "*?[{'"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007113#endif
7114 , *p) != NULL)
7115 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007116 }
7117 return FALSE;
7118}
7119
7120/*
7121 * Return TRUE if the string "p" contains a wildcard.
7122 * Don't recognize '~' at the end as a wildcard.
7123 */
7124 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007125mch_has_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007126{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007127 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007128 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007129 if (*p == '\\' && p[1] != NUL)
7130 ++p;
7131 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007132 if (vim_strchr((char_u *)
7133#ifdef VMS
7134 "*?%$"
7135#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007136 "*?[{`'$"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007137#endif
7138 , *p) != NULL
7139 || (*p == '~' && p[1] != NUL))
7140 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007141 }
7142 return FALSE;
7143}
7144
Bram Moolenaar071d4272004-06-13 20:20:40 +00007145 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007146have_wildcard(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007147{
7148 int i;
7149
7150 for (i = 0; i < num; i++)
7151 if (mch_has_wildcard(file[i]))
7152 return 1;
7153 return 0;
7154}
7155
7156 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007157have_dollars(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007158{
7159 int i;
7160
7161 for (i = 0; i < num; i++)
7162 if (vim_strchr(file[i], '$') != NULL)
7163 return TRUE;
7164 return FALSE;
7165}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007166
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007167#if !defined(HAVE_RENAME) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007168/*
7169 * Scaled-down version of rename(), which is missing in Xenix.
7170 * This version can only move regular files and will fail if the
7171 * destination exists.
7172 */
7173 int
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007174mch_rename(const char *src, const char *dest)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007175{
7176 struct stat st;
7177
Bram Moolenaar0f873732019-12-05 20:28:46 +01007178 if (stat(dest, &st) >= 0) // fail if destination exists
Bram Moolenaar071d4272004-06-13 20:20:40 +00007179 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007180 if (link(src, dest) != 0) // link file to new name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007181 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007182 if (mch_remove(src) == 0) // delete link to old name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007183 return 0;
7184 return -1;
7185}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007186#endif // !HAVE_RENAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00007187
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007188#if defined(FEAT_MOUSE_GPM) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007189/*
7190 * Initializes connection with gpm (if it isn't already opened)
7191 * Return 1 if succeeded (or connection already opened), 0 if failed
7192 */
7193 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007194gpm_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007195{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007196 static Gpm_Connect gpm_connect; // Must it be kept till closing ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007197
7198 if (!gpm_flag)
7199 {
7200 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
7201 gpm_connect.defaultMask = ~GPM_HARD;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007202 // Default handling for mouse move
7203 gpm_connect.minMod = 0; // Handle any modifier keys
Bram Moolenaar071d4272004-06-13 20:20:40 +00007204 gpm_connect.maxMod = 0xffff;
7205 if (Gpm_Open(&gpm_connect, 0) > 0)
7206 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007207 // gpm library tries to handling TSTP causes
7208 // problems. Anyways, we close connection to Gpm whenever
7209 // we are going to suspend or starting an external process
7210 // so we shouldn't have problem with this
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007211# ifdef SIGTSTP
dbivolaruab16ad32021-12-29 19:41:47 +00007212 signal(SIGTSTP, restricted ? SIG_IGN : (RETSIGTYPE (*)())sig_tstp);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007213# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007214 return 1; // succeed
Bram Moolenaar071d4272004-06-13 20:20:40 +00007215 }
7216 if (gpm_fd == -2)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007217 Gpm_Close(); // We don't want to talk to xterm via gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007218 return 0;
7219 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007220 return 1; // already open
Bram Moolenaar071d4272004-06-13 20:20:40 +00007221}
7222
7223/*
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007224 * Returns TRUE if the GPM mouse is enabled.
7225 */
7226 int
7227gpm_enabled(void)
7228{
7229 return gpm_flag && gpm_fd >= 0;
7230}
7231
7232/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007233 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007234 */
7235 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007236gpm_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007237{
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007238 if (gpm_enabled())
Bram Moolenaar071d4272004-06-13 20:20:40 +00007239 Gpm_Close();
7240}
7241
Bram Moolenaarbedf0912019-05-04 16:58:45 +02007242/*
7243 * Reads gpm event and adds special keys to input buf. Returns length of
Bram Moolenaar071d4272004-06-13 20:20:40 +00007244 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02007245 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00007246 */
7247 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007248mch_gpm_process(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007249{
7250 int button;
7251 static Gpm_Event gpm_event;
7252 char_u string[6];
7253 int_u vim_modifiers;
7254 int row,col;
7255 unsigned char buttons_mask;
7256 unsigned char gpm_modifiers;
7257 static unsigned char old_buttons = 0;
7258
7259 Gpm_GetEvent(&gpm_event);
7260
7261#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007262 // Don't put events in the input queue now.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007263 if (hold_gui_events)
7264 return 0;
7265#endif
7266
7267 row = gpm_event.y - 1;
7268 col = gpm_event.x - 1;
7269
Bram Moolenaar0f873732019-12-05 20:28:46 +01007270 string[0] = ESC; // Our termcode
Bram Moolenaar071d4272004-06-13 20:20:40 +00007271 string[1] = 'M';
7272 string[2] = 'G';
7273 switch (GPM_BARE_EVENTS(gpm_event.type))
7274 {
7275 case GPM_DRAG:
7276 string[3] = MOUSE_DRAG;
7277 break;
7278 case GPM_DOWN:
7279 buttons_mask = gpm_event.buttons & ~old_buttons;
7280 old_buttons = gpm_event.buttons;
7281 switch (buttons_mask)
7282 {
7283 case GPM_B_LEFT:
7284 button = MOUSE_LEFT;
7285 break;
7286 case GPM_B_MIDDLE:
7287 button = MOUSE_MIDDLE;
7288 break;
7289 case GPM_B_RIGHT:
7290 button = MOUSE_RIGHT;
7291 break;
7292 default:
7293 return 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007294 // Don't know what to do. Can more than one button be
7295 // reported in one event?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007296 }
7297 string[3] = (char_u)(button | 0x20);
7298 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
7299 break;
7300 case GPM_UP:
7301 string[3] = MOUSE_RELEASE;
7302 old_buttons &= ~gpm_event.buttons;
7303 break;
7304 default:
7305 return 0;
7306 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007307 // This code is based on gui_x11_mouse_cb in gui_x11.c
Bram Moolenaar071d4272004-06-13 20:20:40 +00007308 gpm_modifiers = gpm_event.modifiers;
7309 vim_modifiers = 0x0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007310 // I ignore capslock stats. Aren't we all just hate capslock mixing with
7311 // Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
7312 // K_CAPSSHIFT is defined 8, so it probably isn't even reported
Bram Moolenaar071d4272004-06-13 20:20:40 +00007313 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
7314 vim_modifiers |= MOUSE_SHIFT;
7315
7316 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
7317 vim_modifiers |= MOUSE_CTRL;
7318 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
7319 vim_modifiers |= MOUSE_ALT;
7320 string[3] |= vim_modifiers;
7321 string[4] = (char_u)(col + ' ' + 1);
7322 string[5] = (char_u)(row + ' ' + 1);
7323 add_to_input_buf(string, 6);
7324 return 6;
7325}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007326#endif // FEAT_MOUSE_GPM
Bram Moolenaar071d4272004-06-13 20:20:40 +00007327
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007328#ifdef FEAT_SYSMOUSE
7329/*
7330 * Initialize connection with sysmouse.
7331 * Let virtual console inform us with SIGUSR2 for pending sysmouse
7332 * output, any sysmouse output than will be processed via sig_sysmouse().
7333 * Return OK if succeeded, FAIL if failed.
7334 */
7335 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007336sysmouse_open(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007337{
7338 struct mouse_info mouse;
7339
7340 mouse.operation = MOUSE_MODE;
7341 mouse.u.mode.mode = 0;
7342 mouse.u.mode.signal = SIGUSR2;
7343 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
7344 {
7345 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
7346 mouse.operation = MOUSE_SHOW;
7347 ioctl(1, CONS_MOUSECTL, &mouse);
7348 return OK;
7349 }
7350 return FAIL;
7351}
7352
7353/*
7354 * Stop processing SIGUSR2 signals, and also make sure that
7355 * virtual console do not send us any sysmouse related signal.
7356 */
7357 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007358sysmouse_close(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007359{
7360 struct mouse_info mouse;
7361
7362 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
7363 mouse.operation = MOUSE_MODE;
7364 mouse.u.mode.mode = 0;
7365 mouse.u.mode.signal = 0;
7366 ioctl(1, CONS_MOUSECTL, &mouse);
7367}
7368
7369/*
7370 * Gets info from sysmouse and adds special keys to input buf.
7371 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007372 static RETSIGTYPE
7373sig_sysmouse SIGDEFARG(sigarg)
7374{
7375 struct mouse_info mouse;
7376 struct video_info video;
7377 char_u string[6];
7378 int row, col;
7379 int button;
7380 int buttons;
7381 static int oldbuttons = 0;
7382
7383#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007384 // Don't put events in the input queue now.
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007385 if (hold_gui_events)
7386 return;
7387#endif
7388
7389 mouse.operation = MOUSE_GETINFO;
7390 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
7391 && ioctl(1, FBIO_MODEINFO, &video) != -1
7392 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
7393 && video.vi_cheight > 0 && video.vi_cwidth > 0)
7394 {
7395 row = mouse.u.data.y / video.vi_cheight;
7396 col = mouse.u.data.x / video.vi_cwidth;
7397 buttons = mouse.u.data.buttons;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007398 string[0] = ESC; // Our termcode
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007399 string[1] = 'M';
7400 string[2] = 'S';
7401 if (oldbuttons == buttons && buttons != 0)
7402 {
7403 button = MOUSE_DRAG;
7404 }
7405 else
7406 {
7407 switch (buttons)
7408 {
7409 case 0:
7410 button = MOUSE_RELEASE;
7411 break;
7412 case 1:
7413 button = MOUSE_LEFT;
7414 break;
7415 case 2:
7416 button = MOUSE_MIDDLE;
7417 break;
7418 case 4:
7419 button = MOUSE_RIGHT;
7420 break;
7421 default:
7422 return;
7423 }
7424 oldbuttons = buttons;
7425 }
7426 string[3] = (char_u)(button);
7427 string[4] = (char_u)(col + ' ' + 1);
7428 string[5] = (char_u)(row + ' ' + 1);
7429 add_to_input_buf(string, 6);
7430 }
7431 return;
7432}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007433#endif // FEAT_SYSMOUSE
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007434
Bram Moolenaar071d4272004-06-13 20:20:40 +00007435#if defined(FEAT_LIBCALL) || defined(PROTO)
Bram Moolenaard99df422016-01-29 23:20:40 +01007436typedef char_u * (*STRPROCSTR)(char_u *);
7437typedef char_u * (*INTPROCSTR)(int);
7438typedef int (*STRPROCINT)(char_u *);
7439typedef int (*INTPROCINT)(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007440
7441/*
7442 * Call a DLL routine which takes either a string or int param
7443 * and returns an allocated string.
7444 */
7445 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007446mch_libcall(
7447 char_u *libname,
7448 char_u *funcname,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007449 char_u *argstring, // NULL when using a argint
Bram Moolenaar05540972016-01-30 20:31:25 +01007450 int argint,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007451 char_u **string_result, // NULL when using number_result
Bram Moolenaar05540972016-01-30 20:31:25 +01007452 int *number_result)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007453{
7454# if defined(USE_DLOPEN)
7455 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007456 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007457# else
7458 shl_t hinstLib;
7459# endif
7460 STRPROCSTR ProcAdd;
7461 INTPROCSTR ProcAddI;
7462 char_u *retval_str = NULL;
7463 int retval_int = 0;
7464 int success = FALSE;
7465
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007466 /*
7467 * Get a handle to the DLL module.
7468 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007469# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007470 // First clear any error, it's not cleared by the dlopen() call.
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007471 (void)dlerror();
7472
Bram Moolenaar071d4272004-06-13 20:20:40 +00007473 hinstLib = dlopen((char *)libname, RTLD_LAZY
7474# ifdef RTLD_LOCAL
7475 | RTLD_LOCAL
7476# endif
7477 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007478 if (hinstLib == NULL)
7479 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007480 // "dlerr" must be used before dlclose()
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007481 dlerr = (char *)dlerror();
7482 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007483 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007484 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007485# else
7486 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
7487# endif
7488
Bram Moolenaar0f873732019-12-05 20:28:46 +01007489 // If the handle is valid, try to get the function address.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007490 if (hinstLib != NULL)
7491 {
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007492# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007493 /*
7494 * Catch a crash when calling the library function. For example when
7495 * using a number where a string pointer is expected.
7496 */
7497 mch_startjmp();
7498 if (SETJMP(lc_jump_env) != 0)
7499 {
7500 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007501# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007502 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007503# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007504 mch_didjmp();
7505 }
7506 else
7507# endif
7508 {
7509 retval_str = NULL;
7510 retval_int = 0;
7511
7512 if (argstring != NULL)
7513 {
7514# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007515 *(void **)(&ProcAdd) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007516 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007517# else
7518 if (shl_findsym(&hinstLib, (const char *)funcname,
7519 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
7520 ProcAdd = NULL;
7521# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007522 if ((success = (ProcAdd != NULL
7523# if defined(USE_DLOPEN)
7524 && dlerr == NULL
7525# endif
7526 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007527 {
7528 if (string_result == NULL)
Bram Moolenaara4224862020-09-13 22:00:12 +02007529 retval_int = ((STRPROCINT)(void *)ProcAdd)(argstring);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007530 else
7531 retval_str = (ProcAdd)(argstring);
7532 }
7533 }
7534 else
7535 {
7536# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007537 *(void **)(&ProcAddI) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007538 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007539# else
7540 if (shl_findsym(&hinstLib, (const char *)funcname,
7541 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
7542 ProcAddI = NULL;
7543# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007544 if ((success = (ProcAddI != NULL
7545# if defined(USE_DLOPEN)
7546 && dlerr == NULL
7547# endif
7548 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007549 {
7550 if (string_result == NULL)
Bram Moolenaara4224862020-09-13 22:00:12 +02007551 retval_int = ((INTPROCINT)(void *)ProcAddI)(argint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007552 else
7553 retval_str = (ProcAddI)(argint);
7554 }
7555 }
7556
Bram Moolenaar0f873732019-12-05 20:28:46 +01007557 // Save the string before we free the library.
7558 // Assume that a "1" or "-1" result is an illegal pointer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007559 if (string_result == NULL)
7560 *number_result = retval_int;
7561 else if (retval_str != NULL
7562 && retval_str != (char_u *)1
7563 && retval_str != (char_u *)-1)
7564 *string_result = vim_strsave(retval_str);
7565 }
7566
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007567# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007568 mch_endjmp();
7569# ifdef SIGHASARG
7570 if (lc_signal != 0)
7571 {
7572 int i;
7573
Bram Moolenaar0f873732019-12-05 20:28:46 +01007574 // try to find the name of this signal
Bram Moolenaar071d4272004-06-13 20:20:40 +00007575 for (i = 0; signal_info[i].sig != -1; i++)
7576 if (lc_signal == signal_info[i].sig)
7577 break;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007578 semsg("E368: got SIG%s in libcall()", signal_info[i].name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007579 }
7580# endif
7581# endif
7582
Bram Moolenaar071d4272004-06-13 20:20:40 +00007583# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007584 // "dlerr" must be used before dlclose()
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007585 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007586 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007587
Bram Moolenaar0f873732019-12-05 20:28:46 +01007588 // Free the DLL module.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007589 (void)dlclose(hinstLib);
7590# else
7591 (void)shl_unload(hinstLib);
7592# endif
7593 }
7594
7595 if (!success)
7596 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007597 semsg(_(e_libcall), funcname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007598 return FAIL;
7599 }
7600
7601 return OK;
7602}
7603#endif
7604
7605#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007606static int xterm_trace = -1; // default: disabled
Bram Moolenaar071d4272004-06-13 20:20:40 +00007607static int xterm_button;
7608
7609/*
7610 * Setup a dummy window for X selections in a terminal.
7611 */
7612 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007613setup_term_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007614{
7615 int z = 0;
7616 char *strp = "";
7617 Widget AppShell;
7618
7619 if (!x_connect_to_server())
7620 return;
7621
7622 open_app_context();
7623 if (app_context != NULL && xterm_Shell == (Widget)0)
7624 {
7625 int (*oldhandler)();
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007626# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007627 int (*oldIOhandler)();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007628# endif
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007629# ifdef ELAPSED_FUNC
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01007630 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007631
7632 if (p_verbose > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007633 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007634# endif
7635
Bram Moolenaar0f873732019-12-05 20:28:46 +01007636 // Ignore X errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007637 oldhandler = XSetErrorHandler(x_error_check);
7638
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007639# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007640 // Ignore X IO errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007641 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
7642 mch_startjmp();
7643 if (SETJMP(lc_jump_env) != 0)
7644 {
7645 mch_didjmp();
7646 xterm_dpy = NULL;
7647 }
7648 else
Bram Moolenaaredce7422019-01-20 18:39:30 +01007649# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007650 {
7651 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
7652 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007653 if (xterm_dpy != NULL)
7654 xterm_dpy_retry_count = 0;
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007655# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007656 mch_endjmp();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007657# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007658 }
7659
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007660# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007661 // Now handle X IO errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007662 (void)XSetIOErrorHandler(oldIOhandler);
Bram Moolenaaredce7422019-01-20 18:39:30 +01007663# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007664 // Now handle X errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007665 (void)XSetErrorHandler(oldhandler);
7666
7667 if (xterm_dpy == NULL)
7668 {
7669 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01007670 verb_msg(_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007671 return;
7672 }
7673
Bram Moolenaar0f873732019-12-05 20:28:46 +01007674 // Catch terminating error of the X server connection.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007675 (void)XSetIOErrorHandler(x_IOerror_handler);
7676
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007677# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007678 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007679 {
7680 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007681 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007682 verbose_leave();
7683 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007684# endif
7685
Bram Moolenaar0f873732019-12-05 20:28:46 +01007686 // Create a Shell to make converters work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007687 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
7688 applicationShellWidgetClass, xterm_dpy,
7689 NULL);
7690 if (AppShell == (Widget)0)
7691 return;
7692 xterm_Shell = XtVaCreatePopupShell("VIM",
7693 topLevelShellWidgetClass, AppShell,
7694 XtNmappedWhenManaged, 0,
7695 XtNwidth, 1,
7696 XtNheight, 1,
7697 NULL);
7698 if (xterm_Shell == (Widget)0)
7699 return;
7700
7701 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02007702 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007703 if (x11_display == NULL)
7704 x11_display = xterm_dpy;
7705
7706 XtRealizeWidget(xterm_Shell);
7707 XSync(xterm_dpy, False);
7708 xterm_update();
7709 }
7710 if (xterm_Shell != (Widget)0)
7711 {
7712 clip_init(TRUE);
7713 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
7714 x11_window = (Window)atol(strp);
Bram Moolenaar0f873732019-12-05 20:28:46 +01007715 // Check if $WINDOWID is valid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007716 if (test_x11_window(xterm_dpy) == FAIL)
7717 x11_window = 0;
7718 if (x11_window != 0)
7719 xterm_trace = 0;
7720 }
7721}
7722
7723 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007724start_xterm_trace(int button)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007725{
7726 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
7727 return;
7728 xterm_trace = 1;
7729 xterm_button = button;
7730 do_xterm_trace();
7731}
7732
7733
7734 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007735stop_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007736{
7737 if (xterm_trace < 0)
7738 return;
7739 xterm_trace = 0;
7740}
7741
7742/*
7743 * Query the xterm pointer and generate mouse termcodes if necessary
7744 * return TRUE if dragging is active, else FALSE
7745 */
7746 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007747do_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007748{
7749 Window root, child;
7750 int root_x, root_y;
7751 int win_x, win_y;
7752 int row, col;
7753 int_u mask_return;
7754 char_u buf[50];
7755 char_u *strp;
7756 long got_hints;
7757 static char_u *mouse_code;
7758 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
7759 static int prev_row = 0, prev_col = 0;
7760 static XSizeHints xterm_hints;
7761
7762 if (xterm_trace <= 0)
7763 return FALSE;
7764
7765 if (xterm_trace == 1)
7766 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007767 // Get the hints just before tracking starts. The font size might
7768 // have changed recently.
Bram Moolenaara6c2c912008-01-13 15:31:00 +00007769 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
7770 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007771 || xterm_hints.width_inc <= 1
7772 || xterm_hints.height_inc <= 1)
7773 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007774 xterm_trace = -1; // Not enough data -- disable tracing
Bram Moolenaar071d4272004-06-13 20:20:40 +00007775 return FALSE;
7776 }
7777
Bram Moolenaar0f873732019-12-05 20:28:46 +01007778 // Rely on the same mouse code for the duration of this
Bram Moolenaar071d4272004-06-13 20:20:40 +00007779 mouse_code = find_termcode(mouse_name);
7780 prev_row = mouse_row;
Bram Moolenaarcde88542015-08-11 19:14:00 +02007781 prev_col = mouse_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007782 xterm_trace = 2;
7783
Bram Moolenaar0f873732019-12-05 20:28:46 +01007784 // Find the offset of the chars, there might be a scrollbar on the
7785 // left of the window and/or a menu on the top (eterm etc.)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007786 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7787 &win_x, &win_y, &mask_return);
7788 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
7789 - (xterm_hints.height_inc / 2);
7790 if (xterm_hints.y <= xterm_hints.height_inc / 2)
7791 xterm_hints.y = 2;
7792 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
7793 - (xterm_hints.width_inc / 2);
7794 if (xterm_hints.x <= xterm_hints.width_inc / 2)
7795 xterm_hints.x = 2;
7796 return TRUE;
7797 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02007798 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007799 {
7800 xterm_trace = 0;
7801 return FALSE;
7802 }
7803
7804 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7805 &win_x, &win_y, &mask_return);
7806
7807 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
7808 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
7809 if (row == prev_row && col == prev_col)
7810 return TRUE;
7811
7812 STRCPY(buf, mouse_code);
7813 strp = buf + STRLEN(buf);
7814 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
7815 *strp++ = (char_u)(col + ' ' + 1);
7816 *strp++ = (char_u)(row + ' ' + 1);
7817 *strp = 0;
7818 add_to_input_buf(buf, STRLEN(buf));
7819
7820 prev_row = row;
7821 prev_col = col;
7822 return TRUE;
7823}
7824
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02007825# if defined(FEAT_GUI) || defined(FEAT_XCLIPBOARD) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007826/*
7827 * Destroy the display, window and app_context. Required for GTK.
7828 */
7829 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007830clear_xterm_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007831{
7832 if (xterm_Shell != (Widget)0)
7833 {
7834 XtDestroyWidget(xterm_Shell);
7835 xterm_Shell = (Widget)0;
7836 }
7837 if (xterm_dpy != NULL)
7838 {
Bram Moolenaare8208012008-06-20 09:59:25 +00007839# if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01007840 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007841 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00007842# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007843 if (x11_display == xterm_dpy)
7844 x11_display = NULL;
7845 xterm_dpy = NULL;
7846 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007847# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007848 if (app_context != (XtAppContext)NULL)
7849 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007850 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007851 XtDestroyApplicationContext(app_context);
7852 app_context = (XtAppContext)NULL;
7853 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007854# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007855}
7856# endif
7857
7858/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007859 * Catch up with GUI or X events.
7860 */
7861 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007862clip_update(void)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007863{
7864# ifdef FEAT_GUI
7865 if (gui.in_use)
7866 gui_mch_update();
7867 else
7868# endif
7869 if (xterm_Shell != (Widget)0)
7870 xterm_update();
7871}
7872
7873/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007874 * Catch up with any queued X events. This may put keyboard input into the
7875 * input buffer, call resize call-backs, trigger timers etc. If there is
7876 * nothing in the X event queue (& no timers pending), then we return
7877 * immediately.
7878 */
7879 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007880xterm_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007881{
7882 XEvent event;
7883
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007884 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007885 {
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007886 XtInputMask mask = XtAppPending(app_context);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007887
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007888 if (mask == 0 || vim_is_input_buf_full())
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007889 break;
7890
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007891 if (mask & XtIMXEvent)
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007892 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007893 // There is an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007894 XtAppNextEvent(app_context, &event);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007895#ifdef FEAT_CLIENTSERVER
7896 {
7897 XPropertyEvent *e = (XPropertyEvent *)&event;
7898
7899 if (e->type == PropertyNotify && e->window == commWindow
Bram Moolenaar071d4272004-06-13 20:20:40 +00007900 && e->atom == commProperty && e->state == PropertyNewValue)
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007901 serverEventProc(xterm_dpy, &event, 0);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007902 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007903#endif
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007904 XtDispatchEvent(&event);
7905 }
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007906 else
7907 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007908 // There is something else than an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007909 XtAppProcessEvent(app_context, mask);
7910 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007911 }
7912}
7913
7914 int
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007915clip_xterm_own_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007916{
7917 if (xterm_Shell != (Widget)0)
7918 return clip_x11_own_selection(xterm_Shell, cbd);
7919 return FAIL;
7920}
7921
7922 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007923clip_xterm_lose_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007924{
7925 if (xterm_Shell != (Widget)0)
7926 clip_x11_lose_selection(xterm_Shell, cbd);
7927}
7928
7929 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007930clip_xterm_request_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007931{
7932 if (xterm_Shell != (Widget)0)
7933 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7934}
7935
7936 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007937clip_xterm_set_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007938{
7939 clip_x11_set_selection(cbd);
7940}
7941#endif
7942
7943
7944#if defined(USE_XSMP) || defined(PROTO)
7945/*
7946 * Code for X Session Management Protocol.
7947 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007948
7949# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007950/*
7951 * This is our chance to ask the user if they want to save,
7952 * or abort the logout
7953 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007954 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007955xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007956{
Bram Moolenaare1004402020-10-24 20:49:43 +02007957 int save_cmod_flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007958 int cancel_shutdown = False;
7959
Bram Moolenaare1004402020-10-24 20:49:43 +02007960 save_cmod_flags = cmdmod.cmod_flags;
7961 cmdmod.cmod_flags |= CMOD_CONFIRM;
Bram Moolenaar027387f2016-01-02 22:25:52 +01007962 if (check_changed_any(FALSE, FALSE))
Bram Moolenaar0f873732019-12-05 20:28:46 +01007963 // Mustn't logout
Bram Moolenaar071d4272004-06-13 20:20:40 +00007964 cancel_shutdown = True;
Bram Moolenaare1004402020-10-24 20:49:43 +02007965 cmdmod.cmod_flags = save_cmod_flags;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007966 setcursor(); // position cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00007967 out_flush();
7968
Bram Moolenaar0f873732019-12-05 20:28:46 +01007969 // Done interaction
Bram Moolenaar071d4272004-06-13 20:20:40 +00007970 SmcInteractDone(smc_conn, cancel_shutdown);
7971
Bram Moolenaar0f873732019-12-05 20:28:46 +01007972 // Finish off
7973 // Only end save-yourself here if we're not cancelling shutdown;
7974 // we'll get a cancelled callback later in which we'll end it.
7975 // Hopefully get around glitchy SMs (like GNOME-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007976 if (!cancel_shutdown)
7977 {
7978 xsmp.save_yourself = False;
7979 SmcSaveYourselfDone(smc_conn, True);
7980 }
7981}
7982# endif
7983
7984/*
7985 * Callback that starts save-yourself.
7986 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007987 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007988xsmp_handle_save_yourself(
7989 SmcConn smc_conn,
7990 SmPointer client_data UNUSED,
7991 int save_type UNUSED,
7992 Bool shutdown,
7993 int interact_style UNUSED,
7994 Bool fast UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007995{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007996 // Handle already being in saveyourself
Bram Moolenaar071d4272004-06-13 20:20:40 +00007997 if (xsmp.save_yourself)
7998 SmcSaveYourselfDone(smc_conn, True);
7999 xsmp.save_yourself = True;
8000 xsmp.shutdown = shutdown;
8001
Bram Moolenaar0f873732019-12-05 20:28:46 +01008002 // First up, preserve all files
Bram Moolenaar071d4272004-06-13 20:20:40 +00008003 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01008004 ml_sync_all(FALSE, FALSE); // preserve all swap files
Bram Moolenaar071d4272004-06-13 20:20:40 +00008005
8006 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008007 verb_msg(_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008008
8009# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01008010 // Now see if we can ask about unsaved files
Bram Moolenaar071d4272004-06-13 20:20:40 +00008011 if (shutdown && !fast && gui.in_use)
Bram Moolenaar0f873732019-12-05 20:28:46 +01008012 // Need to interact with user, but need SM's permission
Bram Moolenaar071d4272004-06-13 20:20:40 +00008013 SmcInteractRequest(smc_conn, SmDialogError,
8014 xsmp_handle_interaction, client_data);
8015 else
8016# endif
8017 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01008018 // Can stop the cycle here
Bram Moolenaar071d4272004-06-13 20:20:40 +00008019 SmcSaveYourselfDone(smc_conn, True);
8020 xsmp.save_yourself = False;
8021 }
8022}
8023
8024
8025/*
8026 * Callback to warn us of imminent death.
8027 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008028 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008029xsmp_die(SmcConn smc_conn UNUSED, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008030{
8031 xsmp_close();
8032
Bram Moolenaar0f873732019-12-05 20:28:46 +01008033 // quit quickly leaving swapfiles for modified buffers behind
Bram Moolenaar071d4272004-06-13 20:20:40 +00008034 getout_preserve_modified(0);
8035}
8036
8037
8038/*
8039 * Callback to tell us that save-yourself has completed.
8040 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008041 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008042xsmp_save_complete(
8043 SmcConn smc_conn UNUSED,
8044 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008045{
8046 xsmp.save_yourself = False;
8047}
8048
8049
8050/*
8051 * Callback to tell us that an instigated shutdown was cancelled
8052 * (maybe even by us)
8053 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008054 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008055xsmp_shutdown_cancelled(
8056 SmcConn smc_conn,
8057 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008058{
8059 if (xsmp.save_yourself)
8060 SmcSaveYourselfDone(smc_conn, True);
8061 xsmp.save_yourself = False;
8062 xsmp.shutdown = False;
8063}
8064
8065
8066/*
8067 * Callback to tell us that a new ICE connection has been established.
8068 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008069 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008070xsmp_ice_connection(
8071 IceConn iceConn,
8072 IcePointer clientData UNUSED,
8073 Bool opening,
8074 IcePointer *watchData UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008075{
Bram Moolenaar0f873732019-12-05 20:28:46 +01008076 // Intercept creation of ICE connection fd
Bram Moolenaar071d4272004-06-13 20:20:40 +00008077 if (opening)
8078 {
8079 xsmp_icefd = IceConnectionNumber(iceConn);
8080 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
8081 }
8082}
8083
8084
Bram Moolenaar0f873732019-12-05 20:28:46 +01008085// Handle any ICE processing that's required; return FAIL if SM lost
Bram Moolenaar071d4272004-06-13 20:20:40 +00008086 int
Bram Moolenaar05540972016-01-30 20:31:25 +01008087xsmp_handle_requests(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008088{
8089 Bool rep;
8090
8091 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
8092 == IceProcessMessagesIOError)
8093 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01008094 // Lost ICE
Bram Moolenaar071d4272004-06-13 20:20:40 +00008095 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008096 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008097 xsmp_close();
8098 return FAIL;
8099 }
8100 else
8101 return OK;
8102}
8103
8104static int dummy;
8105
Bram Moolenaar0f873732019-12-05 20:28:46 +01008106// Set up X Session Management Protocol
Bram Moolenaar071d4272004-06-13 20:20:40 +00008107 void
8108xsmp_init(void)
8109{
8110 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00008111 SmcCallbacks smcallbacks;
8112#if 0
8113 SmPropValue smname;
8114 SmProp smnameprop;
8115 SmProp *smprops[1];
8116#endif
8117
8118 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008119 verb_msg(_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008120
8121 xsmp.save_yourself = xsmp.shutdown = False;
8122
Bram Moolenaar0f873732019-12-05 20:28:46 +01008123 // Set up SM callbacks - must have all, even if they're not used
Bram Moolenaar071d4272004-06-13 20:20:40 +00008124 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
8125 smcallbacks.save_yourself.client_data = NULL;
8126 smcallbacks.die.callback = xsmp_die;
8127 smcallbacks.die.client_data = NULL;
8128 smcallbacks.save_complete.callback = xsmp_save_complete;
8129 smcallbacks.save_complete.client_data = NULL;
8130 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
8131 smcallbacks.shutdown_cancelled.client_data = NULL;
8132
Bram Moolenaar0f873732019-12-05 20:28:46 +01008133 // Set up a watch on ICE connection creations. The "dummy" argument is
8134 // apparently required for FreeBSD (we get a BUS error when using NULL).
Bram Moolenaar071d4272004-06-13 20:20:40 +00008135 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
8136 {
8137 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008138 verb_msg(_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008139 return;
8140 }
8141
Bram Moolenaar0f873732019-12-05 20:28:46 +01008142 // Create an SM connection
Bram Moolenaar071d4272004-06-13 20:20:40 +00008143 xsmp.smcconn = SmcOpenConnection(
8144 NULL,
8145 NULL,
8146 SmProtoMajor,
8147 SmProtoMinor,
8148 SmcSaveYourselfProcMask | SmcDieProcMask
8149 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
8150 &smcallbacks,
8151 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00008152 &xsmp.clientid,
Bram Moolenaar4841a7c2018-09-22 14:08:49 +02008153 sizeof(errorstring) - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00008154 errorstring);
8155 if (xsmp.smcconn == NULL)
8156 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00008157 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008158 {
Bram Moolenaare1be1182020-10-24 13:30:51 +02008159 char errorreport[132];
8160
8161 // If the message is too long it might not be NUL terminated. Add
8162 // a NUL at the end to make sure we don't go over the end.
8163 errorstring[sizeof(errorstring) - 1] = NUL;
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008164 vim_snprintf(errorreport, sizeof(errorreport),
8165 _("XSMP SmcOpenConnection failed: %s"), errorstring);
Bram Moolenaar32526b32019-01-19 17:43:09 +01008166 verb_msg(errorreport);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008167 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008168 return;
8169 }
8170 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
8171
8172#if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01008173 // ID ourselves
Bram Moolenaar071d4272004-06-13 20:20:40 +00008174 smname.value = "vim";
8175 smname.length = 3;
8176 smnameprop.name = "SmProgram";
8177 smnameprop.type = "SmARRAY8";
8178 smnameprop.num_vals = 1;
8179 smnameprop.vals = &smname;
8180
8181 smprops[0] = &smnameprop;
8182 SmcSetProperties(xsmp.smcconn, 1, smprops);
8183#endif
8184}
8185
8186
Bram Moolenaar0f873732019-12-05 20:28:46 +01008187// Shut down XSMP comms.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008188 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008189xsmp_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008190{
8191 if (xsmp_icefd != -1)
8192 {
8193 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00008194 if (xsmp.clientid != NULL)
8195 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00008196 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008197 xsmp_icefd = -1;
8198 }
8199}
Bram Moolenaar0f873732019-12-05 20:28:46 +01008200#endif // USE_XSMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00008201
8202
8203#ifdef EBCDIC
Bram Moolenaar0f873732019-12-05 20:28:46 +01008204// Translate character to its CTRL- value
Bram Moolenaar071d4272004-06-13 20:20:40 +00008205char CtrlTable[] =
8206{
8207/* 00 - 5E */
8208 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8209 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8210 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8211 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8212 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8213 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8214/* ^ */ 0x1E,
8215/* - */ 0x1F,
8216/* 61 - 6C */
8217 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8218/* _ */ 0x1F,
8219/* 6E - 80 */
8220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8221/* a */ 0x01,
8222/* b */ 0x02,
8223/* c */ 0x03,
8224/* d */ 0x37,
8225/* e */ 0x2D,
8226/* f */ 0x2E,
8227/* g */ 0x2F,
8228/* h */ 0x16,
8229/* i */ 0x05,
8230/* 8A - 90 */
8231 0, 0, 0, 0, 0, 0, 0,
8232/* j */ 0x15,
8233/* k */ 0x0B,
8234/* l */ 0x0C,
8235/* m */ 0x0D,
8236/* n */ 0x0E,
8237/* o */ 0x0F,
8238/* p */ 0x10,
8239/* q */ 0x11,
8240/* r */ 0x12,
8241/* 9A - A1 */
8242 0, 0, 0, 0, 0, 0, 0, 0,
8243/* s */ 0x13,
8244/* t */ 0x3C,
8245/* u */ 0x3D,
8246/* v */ 0x32,
8247/* w */ 0x26,
8248/* x */ 0x18,
8249/* y */ 0x19,
8250/* z */ 0x3F,
8251/* AA - AC */
8252 0, 0, 0,
8253/* [ */ 0x27,
8254/* AE - BC */
8255 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8256/* ] */ 0x1D,
8257/* BE - C0 */ 0, 0, 0,
8258/* A */ 0x01,
8259/* B */ 0x02,
8260/* C */ 0x03,
8261/* D */ 0x37,
8262/* E */ 0x2D,
8263/* F */ 0x2E,
8264/* G */ 0x2F,
8265/* H */ 0x16,
8266/* I */ 0x05,
8267/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
8268/* J */ 0x15,
8269/* K */ 0x0B,
8270/* L */ 0x0C,
8271/* M */ 0x0D,
8272/* N */ 0x0E,
8273/* O */ 0x0F,
8274/* P */ 0x10,
8275/* Q */ 0x11,
8276/* R */ 0x12,
8277/* DA - DF */ 0, 0, 0, 0, 0, 0,
8278/* \ */ 0x1C,
8279/* E1 */ 0,
8280/* S */ 0x13,
8281/* T */ 0x3C,
8282/* U */ 0x3D,
8283/* V */ 0x32,
8284/* W */ 0x26,
8285/* X */ 0x18,
8286/* Y */ 0x19,
8287/* Z */ 0x3F,
8288/* EA - FF*/ 0, 0, 0, 0, 0, 0,
8289 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8290};
8291
8292char MetaCharTable[]=
Bram Moolenaar0f873732019-12-05 20:28:46 +01008293{// 0 1 2 3 4 5 6 7 8 9 A B C D E F
Bram Moolenaar071d4272004-06-13 20:20:40 +00008294 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
8295 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
8296 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
8297 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
8298};
8299
8300
Bram Moolenaar0f873732019-12-05 20:28:46 +01008301// TODO: Use characters NOT numbers!!!
Bram Moolenaar071d4272004-06-13 20:20:40 +00008302char CtrlCharTable[]=
Bram Moolenaar0f873732019-12-05 20:28:46 +01008303{// 0 1 2 3 4 5 6 7 8 9 A B C D E F
Bram Moolenaar071d4272004-06-13 20:20:40 +00008304 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
8305 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
8306 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
8307 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
8308};
8309
8310
8311#endif