blob: 56ee764b0f3ad467907dd95828416706cb9f400e [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * OS/2 port by Paul Slootman
5 * VMS merge by Zoltan Arpadffy
6 *
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 * See README.txt for an overview of the Vim source code.
10 */
11
12/*
13 * os_unix.c -- code for all flavors of Unix (BSD, SYSV, SVR4, POSIX, ...)
14 * Also for OS/2, using the excellent EMX package!!!
Bram Moolenaar041c7102020-05-30 18:14:57 +020015 * Also for Atari MiNT.
Bram Moolenaar071d4272004-06-13 20:20:40 +000016 *
17 * A lot of this file was originally written by Juergen Weigert and later
18 * changed beyond recognition.
19 */
20
Bram Moolenaar071d4272004-06-13 20:20:40 +000021#include "vim.h"
22
Bram Moolenaar325b7a22004-07-05 15:58:32 +000023#ifdef FEAT_MZSCHEME
24# include "if_mzsch.h"
25#endif
26
Bram Moolenaar0f873732019-12-05 20:28:46 +010027#include "os_unixx.h" // unix includes for os_unix.c only
Bram Moolenaar071d4272004-06-13 20:20:40 +000028
29#ifdef USE_XSMP
30# include <X11/SM/SMlib.h>
31#endif
32
Bram Moolenaar588ebeb2008-05-07 17:09:24 +000033#ifdef HAVE_SELINUX
34# include <selinux/selinux.h>
35static int selinux_enabled = -1;
36#endif
37
Bram Moolenaar5bd32f42014-04-02 14:05:38 +020038#ifdef HAVE_SMACK
39# include <attr/xattr.h>
40# include <linux/xattr.h>
41# ifndef SMACK_LABEL_LEN
42# define SMACK_LABEL_LEN 1024
43# endif
44#endif
45
Bram Moolenaara2442432007-04-26 14:26:37 +000046#ifdef __CYGWIN__
Bram Moolenaar4f974752019-02-17 17:44:42 +010047# ifndef MSWIN
Bram Moolenaar0d1498e2008-06-29 12:00:49 +000048# include <cygwin/version.h>
Bram Moolenaar0f873732019-12-05 20:28:46 +010049# include <sys/cygwin.h> // for cygwin_conv_to_posix_path() and/or
50 // for cygwin_conv_path()
Bram Moolenaar693e40c2013-02-26 14:56:42 +010051# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
52# define WIN32_LEAN_AND_MEAN
53# include <windows.h>
54# include "winclip.pro"
55# endif
Bram Moolenaara2442432007-04-26 14:26:37 +000056# endif
57#endif
58
Bram Moolenaar071d4272004-06-13 20:20:40 +000059#ifdef FEAT_MOUSE_GPM
60# include <gpm.h>
Bram Moolenaar0f873732019-12-05 20:28:46 +010061// <linux/keyboard.h> contains defines conflicting with "keymap.h",
62// I just copied relevant defines here. A cleaner solution would be to put gpm
63// code into separate file and include there linux/keyboard.h
64// #include <linux/keyboard.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000065# define KG_SHIFT 0
66# define KG_CTRL 2
67# define KG_ALT 3
68# define KG_ALTGR 1
69# define KG_SHIFTL 4
70# define KG_SHIFTR 5
71# define KG_CTRLL 6
72# define KG_CTRLR 7
73# define KG_CAPSSHIFT 8
74
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010075static void gpm_close(void);
76static int gpm_open(void);
77static int mch_gpm_process(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000078#endif
79
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000080#ifdef FEAT_SYSMOUSE
81# include <sys/consio.h>
82# include <sys/fbio.h>
83
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010084static int sysmouse_open(void);
85static void sysmouse_close(void);
Bram Moolenaard99df422016-01-29 23:20:40 +010086static RETSIGTYPE sig_sysmouse SIGPROTOARG;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000087#endif
88
Bram Moolenaar071d4272004-06-13 20:20:40 +000089/*
90 * end of autoconf section. To be extended...
91 */
92
Bram Moolenaar0f873732019-12-05 20:28:46 +010093// Are the following #ifdefs still required? And why? Is that for X11?
Bram Moolenaar071d4272004-06-13 20:20:40 +000094
95#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
96# ifdef SIGWINCH
97# undef SIGWINCH
98# endif
99# ifdef TIOCGWINSZ
100# undef TIOCGWINSZ
101# endif
102#endif
103
Bram Moolenaar0f873732019-12-05 20:28:46 +0100104#if defined(SIGWINDOW) && !defined(SIGWINCH) // hpux 9.01 has it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000105# define SIGWINCH SIGWINDOW
106#endif
107
108#ifdef FEAT_X11
109# include <X11/Xlib.h>
110# include <X11/Xutil.h>
111# include <X11/Xatom.h>
112# ifdef FEAT_XCLIPBOARD
113# include <X11/Intrinsic.h>
114# include <X11/Shell.h>
115# include <X11/StringDefs.h>
116static Widget xterm_Shell = (Widget)0;
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100117static void clip_update(void);
118static void xterm_update(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000119# endif
120
121# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
122Window x11_window = 0;
123# endif
124Display *x11_display = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000125#endif
126
Bram Moolenaar5c3128e2020-05-11 20:54:42 +0200127static int ignore_sigtstp = FALSE;
128
Bram Moolenaar071d4272004-06-13 20:20:40 +0000129#ifdef FEAT_TITLE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100130static int get_x11_title(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000131
132static char_u *oldtitle = NULL;
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200133static volatile sig_atomic_t oldtitle_outdated = FALSE;
Bram Moolenaardac13472019-09-16 21:06:21 +0200134static int unix_did_set_title = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000135static char_u *oldicon = NULL;
136static int did_set_icon = FALSE;
137#endif
138
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100139static void may_core_dump(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000140
Bram Moolenaar205b8862011-09-07 15:04:31 +0200141#ifdef HAVE_UNION_WAIT
142typedef union wait waitstatus;
143#else
144typedef int waitstatus;
145#endif
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200146static int WaitForChar(long msec, int *interrupted, int ignore_input);
147static int WaitForCharOrMouse(long msec, int *interrupted, int ignore_input);
Bram Moolenaar041c7102020-05-30 18:14:57 +0200148#ifdef VMS
Bram Moolenaarcda77642016-06-04 13:32:35 +0200149int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150#else
Bram Moolenaarcda77642016-06-04 13:32:35 +0200151static int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152#endif
153
154#ifdef FEAT_XCLIPBOARD
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100155static int do_xterm_trace(void);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100156# define XT_TRACE_DELAY 50 // delay for xterm tracing
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157#endif
158
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100159static void handle_resize(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160
161#if defined(SIGWINCH)
Bram Moolenaard99df422016-01-29 23:20:40 +0100162static RETSIGTYPE sig_winch SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000163#endif
164#if defined(SIGINT)
Bram Moolenaard99df422016-01-29 23:20:40 +0100165static RETSIGTYPE catch_sigint SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166#endif
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200167#if defined(SIGUSR1)
168static RETSIGTYPE catch_sigusr1 SIGPROTOARG;
169#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170#if defined(SIGPWR)
Bram Moolenaard99df422016-01-29 23:20:40 +0100171static RETSIGTYPE catch_sigpwr SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172#endif
173#if defined(SIGALRM) && defined(FEAT_X11) \
174 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
175# define SET_SIG_ALARM
Bram Moolenaard99df422016-01-29 23:20:40 +0100176static RETSIGTYPE sig_alarm SIGPROTOARG;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100177// volatile because it is used in signal handler sig_alarm().
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200178static volatile sig_atomic_t sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179#endif
Bram Moolenaard99df422016-01-29 23:20:40 +0100180static RETSIGTYPE deathtrap SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000181
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100182static void catch_int_signal(void);
183static void set_signals(void);
184static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)());
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +0200185#ifdef HAVE_SIGPROCMASK
186# define SIGSET_DECL(set) sigset_t set;
187# define BLOCK_SIGNALS(set) block_signals(set)
188# define UNBLOCK_SIGNALS(set) unblock_signals(set)
189#else
190# define SIGSET_DECL(set)
191# define BLOCK_SIGNALS(set) do { /**/ } while (0)
192# define UNBLOCK_SIGNALS(set) do { /**/ } while (0)
193#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100194static int have_wildcard(int, char_u **);
195static int have_dollars(int, char_u **);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100197static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198
199#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000200# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201#endif
202
Bram Moolenaar0f873732019-12-05 20:28:46 +0100203// volatile because it is used in signal handler sig_winch().
Bram Moolenaar8e82c052018-08-21 19:47:48 +0200204static volatile sig_atomic_t do_resize = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000205static char_u *extra_shell_arg = NULL;
206static int show_shell_mess = TRUE;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100207// volatile because it is used in signal handler deathtrap().
208static volatile sig_atomic_t deadly_signal = 0; // The signal we caught
209// volatile because it is used in signal handler deathtrap().
210static volatile sig_atomic_t in_mch_delay = FALSE; // sleeping in mch_delay()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000211
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +0100212#if defined(FEAT_JOB_CHANNEL) && !defined(USE_SYSTEM)
213static int dont_check_job_ended = 0;
214#endif
215
Bram Moolenaar26e86442020-05-17 14:06:16 +0200216// Current terminal mode from mch_settmode(). Can differ from cur_tmode.
217static tmode_T mch_cur_tmode = TMODE_COOK;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000218
219#ifdef USE_XSMP
220typedef struct
221{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100222 SmcConn smcconn; // The SM connection ID
223 IceConn iceconn; // The ICE connection ID
224 char *clientid; // The client ID for the current smc session
225 Bool save_yourself; // If we're in the middle of a save_yourself
226 Bool shutdown; // If we're in shutdown mode
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227} xsmp_config_T;
228
229static xsmp_config_T xsmp;
230#endif
231
232#ifdef SYS_SIGLIST_DECLARED
233/*
234 * I have seen
235 * extern char *_sys_siglist[NSIG];
236 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
237 * that describe the signals. That is nearly what we want here. But
238 * autoconf does only check for sys_siglist (without the underscore), I
239 * do not want to change everything today.... jw.
Bram Moolenaar3f7d0902016-11-12 21:13:42 +0100240 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.ac.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241 */
242#endif
243
244static struct signalinfo
245{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100246 int sig; // Signal number, eg. SIGSEGV etc
247 char *name; // Signal name (not char_u!).
248 char deadly; // Catch as a deadly signal?
Bram Moolenaar071d4272004-06-13 20:20:40 +0000249} signal_info[] =
250{
251#ifdef SIGHUP
252 {SIGHUP, "HUP", TRUE},
253#endif
254#ifdef SIGQUIT
255 {SIGQUIT, "QUIT", TRUE},
256#endif
257#ifdef SIGILL
258 {SIGILL, "ILL", TRUE},
259#endif
260#ifdef SIGTRAP
261 {SIGTRAP, "TRAP", TRUE},
262#endif
263#ifdef SIGABRT
264 {SIGABRT, "ABRT", TRUE},
265#endif
266#ifdef SIGEMT
267 {SIGEMT, "EMT", TRUE},
268#endif
269#ifdef SIGFPE
270 {SIGFPE, "FPE", TRUE},
271#endif
272#ifdef SIGBUS
273 {SIGBUS, "BUS", TRUE},
274#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100275#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100276 // MzScheme uses SEGV in its garbage collector
Bram Moolenaar071d4272004-06-13 20:20:40 +0000277 {SIGSEGV, "SEGV", TRUE},
278#endif
279#ifdef SIGSYS
280 {SIGSYS, "SYS", TRUE},
281#endif
282#ifdef SIGALRM
Bram Moolenaar0f873732019-12-05 20:28:46 +0100283 {SIGALRM, "ALRM", FALSE}, // Perl's alarm() can trigger it
Bram Moolenaar071d4272004-06-13 20:20:40 +0000284#endif
285#ifdef SIGTERM
286 {SIGTERM, "TERM", TRUE},
287#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100288#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000289 {SIGVTALRM, "VTALRM", TRUE},
290#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000291#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100292 // MzScheme uses SIGPROF for its own needs; On Linux with profiling
293 // this makes Vim exit. WE_ARE_PROFILING is defined in Makefile.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000294 {SIGPROF, "PROF", TRUE},
295#endif
296#ifdef SIGXCPU
297 {SIGXCPU, "XCPU", TRUE},
298#endif
299#ifdef SIGXFSZ
300 {SIGXFSZ, "XFSZ", TRUE},
301#endif
302#ifdef SIGUSR1
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200303 {SIGUSR1, "USR1", FALSE},
Bram Moolenaar071d4272004-06-13 20:20:40 +0000304#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000305#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100306 // Used for sysmouse handling
Bram Moolenaar071d4272004-06-13 20:20:40 +0000307 {SIGUSR2, "USR2", TRUE},
308#endif
309#ifdef SIGINT
310 {SIGINT, "INT", FALSE},
311#endif
312#ifdef SIGWINCH
313 {SIGWINCH, "WINCH", FALSE},
314#endif
315#ifdef SIGTSTP
316 {SIGTSTP, "TSTP", FALSE},
317#endif
318#ifdef SIGPIPE
319 {SIGPIPE, "PIPE", FALSE},
320#endif
321 {-1, "Unknown!", FALSE}
322};
323
Bram Moolenaar25724922009-07-14 15:38:41 +0000324 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100325mch_chdir(char *path)
Bram Moolenaar25724922009-07-14 15:38:41 +0000326{
327 if (p_verbose >= 5)
328 {
329 verbose_enter();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100330 smsg("chdir(%s)", path);
Bram Moolenaar25724922009-07-14 15:38:41 +0000331 verbose_leave();
332 }
333# ifdef VMS
334 return chdir(vms_fixfilename(path));
335# else
336 return chdir(path);
337# endif
338}
339
Bram Moolenaar0f873732019-12-05 20:28:46 +0100340// Why is NeXT excluded here (and not in os_unixx.h)?
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +0100341#if defined(ECHOE) && defined(ICANON) \
342 && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) \
343 && !defined(__NeXT__)
Bram Moolenaar4f44b882017-08-13 20:06:18 +0200344# define NEW_TTY_SYSTEM
345#endif
346
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000347/*
Bram Moolenaard23a8232018-02-10 18:45:26 +0100348 * Write s[len] to the screen (stdout).
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000349 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100351mch_write(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352{
Bram Moolenaar42335f52018-09-13 15:33:43 +0200353 vim_ignored = (int)write(1, (char *)s, len);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100354 if (p_wd) // Unix is too fast, slow down a bit more
Bram Moolenaar8fdd7212016-03-26 19:41:48 +0100355 RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356}
357
358/*
Bram Moolenaare40b9d42019-01-27 16:55:47 +0100359 * Function passed to inchar_loop() to handle window resizing.
360 * If "check_only" is TRUE: Return whether there was a resize.
361 * If "check_only" is FALSE: Deal with the window resized.
362 */
363 static int
364resize_func(int check_only)
365{
366 if (check_only)
367 return do_resize;
368 while (do_resize)
369 handle_resize();
370 return FALSE;
371}
372
373/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000374 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375 * Get a characters from the keyboard.
376 * Return the number of characters that are available.
377 * If wtime == 0 do not wait for characters.
378 * If wtime == n wait a short time for characters.
379 * If wtime == -1 wait forever for characters.
380 */
381 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100382mch_inchar(
383 char_u *buf,
384 int maxlen,
Bram Moolenaar0f873732019-12-05 20:28:46 +0100385 long wtime, // don't use "time", MIPS cannot handle it
Bram Moolenaar05540972016-01-30 20:31:25 +0100386 int tb_change_cnt)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000387{
Bram Moolenaare40b9d42019-01-27 16:55:47 +0100388 return inchar_loop(buf, maxlen, wtime, tb_change_cnt,
389 WaitForChar, resize_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390}
391
392 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100393handle_resize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000394{
395 do_resize = FALSE;
396 shell_resized();
397}
398
399/*
Bram Moolenaar40b1b542016-04-20 20:18:23 +0200400 * Return non-zero if a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000401 */
402 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100403mch_char_avail(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000404{
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200405 return WaitForChar(0L, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406}
407
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200408#if defined(FEAT_TERMINAL) || defined(PROTO)
409/*
410 * Check for any pending input or messages.
411 */
412 int
413mch_check_messages(void)
414{
415 return WaitForChar(0L, NULL, TRUE);
416}
417#endif
418
Bram Moolenaar071d4272004-06-13 20:20:40 +0000419#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
420# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000421# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422# endif
423# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
424# include <sys/sysctl.h>
425# endif
426# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
427# include <sys/sysinfo.h>
428# endif
Bram Moolenaar362dc332018-03-05 21:59:37 +0100429# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100430# include <mach/mach_host.h>
431# include <mach/mach_port.h>
Bram Moolenaar988615f2018-02-27 17:58:20 +0100432# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000433
434/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000435 * Return total amount of memory available in Kbyte.
436 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000438 long_u
Bram Moolenaar05540972016-01-30 20:31:25 +0100439mch_total_mem(int special UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000440{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 long_u mem = 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +0100442 long_u shiftright = 10; // how much to shift "mem" right for Kbyte
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443
Bram Moolenaar362dc332018-03-05 21:59:37 +0100444# ifdef MACOS_X
Bram Moolenaar988615f2018-02-27 17:58:20 +0100445 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100446 // Mac (Darwin) way of getting the amount of RAM available
Bram Moolenaar988615f2018-02-27 17:58:20 +0100447 mach_port_t host = mach_host_self();
448 kern_return_t kret;
449# ifdef HOST_VM_INFO64
450 struct vm_statistics64 vm_stat;
451 natural_t count = HOST_VM_INFO64_COUNT;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452
Bram Moolenaar988615f2018-02-27 17:58:20 +0100453 kret = host_statistics64(host, HOST_VM_INFO64,
454 (host_info64_t)&vm_stat, &count);
455# else
456 struct vm_statistics vm_stat;
457 natural_t count = HOST_VM_INFO_COUNT;
458
459 kret = host_statistics(host, HOST_VM_INFO,
460 (host_info_t)&vm_stat, &count);
461# endif
462 if (kret == KERN_SUCCESS)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100463 // get the amount of user memory by summing each usage
Bram Moolenaar988615f2018-02-27 17:58:20 +0100464 mem = (long_u)(vm_stat.free_count + vm_stat.active_count
465 + vm_stat.inactive_count
466# ifdef MAC_OS_X_VERSION_10_9
467 + vm_stat.compressor_page_count
468# endif
Bram Moolenaar62b7f6a2018-03-22 21:44:07 +0100469 ) * sysconf(_SC_PAGESIZE);
Bram Moolenaar988615f2018-02-27 17:58:20 +0100470 mach_port_deallocate(mach_task_self(), host);
471 }
472# endif
473
474# ifdef HAVE_SYSCTL
475 if (mem == 0)
476 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100477 // BSD way of getting the amount of RAM available.
Bram Moolenaar988615f2018-02-27 17:58:20 +0100478 int mib[2];
479 size_t len = sizeof(long_u);
480# ifdef HW_USERMEM64
481 long_u physmem;
482# else
Bram Moolenaar0f873732019-12-05 20:28:46 +0100483 // sysctl() may return 32 bit or 64 bit, accept both
Bram Moolenaar988615f2018-02-27 17:58:20 +0100484 union {
485 int_u u32;
486 long_u u64;
487 } physmem;
488# endif
489
490 mib[0] = CTL_HW;
491# ifdef HW_USERMEM64
492 mib[1] = HW_USERMEM64;
493# else
494 mib[1] = HW_USERMEM;
495# endif
496 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
497 {
498# ifdef HW_USERMEM64
499 mem = (long_u)physmem;
500# else
501 if (len == sizeof(physmem.u64))
502 mem = (long_u)physmem.u64;
503 else
504 mem = (long_u)physmem.u32;
505# endif
506 }
507 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200508# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000509
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200510# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511 if (mem == 0)
512 {
513 struct sysinfo sinfo;
514
Bram Moolenaar0f873732019-12-05 20:28:46 +0100515 // Linux way of getting amount of RAM available
Bram Moolenaar071d4272004-06-13 20:20:40 +0000516 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000517 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200518# ifdef HAVE_SYSINFO_MEM_UNIT
Bram Moolenaar0f873732019-12-05 20:28:46 +0100519 // avoid overflow as much as possible
Bram Moolenaar914572a2007-05-01 11:37:47 +0000520 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
521 {
522 sinfo.mem_unit = sinfo.mem_unit >> 1;
523 --shiftright;
524 }
525 mem = sinfo.totalram * sinfo.mem_unit;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200526# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000527 mem = sinfo.totalram;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200528# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000529 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200531# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200533# ifdef HAVE_SYSCONF
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534 if (mem == 0)
535 {
536 long pagesize, pagecount;
537
Bram Moolenaar0f873732019-12-05 20:28:46 +0100538 // Solaris way of getting amount of RAM available
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539 pagesize = sysconf(_SC_PAGESIZE);
540 pagecount = sysconf(_SC_PHYS_PAGES);
541 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000542 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100543 // avoid overflow as much as possible
Bram Moolenaar914572a2007-05-01 11:37:47 +0000544 while (shiftright > 0 && (pagesize & 1) == 0)
545 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000546 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000547 --shiftright;
548 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000550 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200552# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553
Bram Moolenaar0f873732019-12-05 20:28:46 +0100554 // Return the minimum of the physical memory and the user limit, because
555 // using more than the user limit may cause Vim to be terminated.
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200556# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557 {
558 struct rlimit rlp;
559
560 if (getrlimit(RLIMIT_DATA, &rlp) == 0
561 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200562# ifdef RLIM_INFINITY
Bram Moolenaar071d4272004-06-13 20:20:40 +0000563 && rlp.rlim_cur != RLIM_INFINITY
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200564# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000565 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000567 {
568 mem = (long_u)rlp.rlim_cur;
569 shiftright = 10;
570 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000571 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200572# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000573
574 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000575 return mem >> shiftright;
576 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577}
578#endif
579
Bram Moolenaar0981c872020-08-23 14:28:37 +0200580/*
581 * "flags": MCH_DELAY_IGNOREINPUT - don't read input
582 * MCH_DELAY_SETTMODE - use settmode() even for short delays
583 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584 void
Bram Moolenaar0981c872020-08-23 14:28:37 +0200585mch_delay(long msec, int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000586{
Bram Moolenaar26e86442020-05-17 14:06:16 +0200587 tmode_T old_tmode;
Bram Moolenaar80361a52020-10-05 21:39:25 +0200588 int call_settmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000589#ifdef FEAT_MZSCHEME
Bram Moolenaar0f873732019-12-05 20:28:46 +0100590 long total = msec; // remember original value
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000591#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000592
Bram Moolenaar0981c872020-08-23 14:28:37 +0200593 if (flags & MCH_DELAY_IGNOREINPUT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100595 // Go to cooked mode without echo, to allow SIGINT interrupting us
596 // here. But we don't want QUIT to kill us (CTRL-\ used in a
597 // shell may produce SIGQUIT).
Bram Moolenaar26e86442020-05-17 14:06:16 +0200598 // Only do this if sleeping for more than half a second.
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000599 in_mch_delay = TRUE;
Bram Moolenaar80361a52020-10-05 21:39:25 +0200600 call_settmode = mch_cur_tmode == TMODE_RAW
601 && (msec > 500 || (flags & MCH_DELAY_SETTMODE));
602 if (call_settmode)
603 {
604 old_tmode = mch_cur_tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000605 settmode(TMODE_SLEEP);
Bram Moolenaar80361a52020-10-05 21:39:25 +0200606 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607
608 /*
609 * Everybody sleeps in a different way...
610 * Prefer nanosleep(), some versions of usleep() can only sleep up to
611 * one second.
612 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000613#ifdef FEAT_MZSCHEME
614 do
615 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100616 // if total is large enough, wait by portions in p_mzq
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000617 if (total > p_mzq)
618 msec = p_mzq;
619 else
620 msec = total;
621 total -= msec;
622#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000623#ifdef HAVE_NANOSLEEP
624 {
625 struct timespec ts;
626
627 ts.tv_sec = msec / 1000;
628 ts.tv_nsec = (msec % 1000) * 1000000;
629 (void)nanosleep(&ts, NULL);
630 }
631#else
632# ifdef HAVE_USLEEP
633 while (msec >= 1000)
634 {
635 usleep((unsigned int)(999 * 1000));
636 msec -= 999;
637 }
638 usleep((unsigned int)(msec * 1000));
639# else
640# ifndef HAVE_SELECT
641 poll(NULL, 0, (int)msec);
642# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643 {
644 struct timeval tv;
645
646 tv.tv_sec = msec / 1000;
647 tv.tv_usec = (msec % 1000) * 1000;
Bram Moolenaar0981c872020-08-23 14:28:37 +0200648 // NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
649 // a patch from Sun to fix this. Reported by Gunnar Pedersen.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000650 select(0, NULL, NULL, NULL, &tv);
651 }
Bram Moolenaar0f873732019-12-05 20:28:46 +0100652# endif // HAVE_SELECT
653# endif // HAVE_NANOSLEEP
654#endif // HAVE_USLEEP
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000655#ifdef FEAT_MZSCHEME
656 }
657 while (total > 0);
658#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000659
Bram Moolenaar80361a52020-10-05 21:39:25 +0200660 if (call_settmode)
Bram Moolenaar26e86442020-05-17 14:06:16 +0200661 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000662 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663 }
664 else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +0200665 WaitForChar(msec, NULL, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000666}
667
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000668#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000669 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
670# define HAVE_CHECK_STACK_GROWTH
671/*
672 * Support for checking for an almost-out-of-stack-space situation.
673 */
674
675/*
676 * Return a pointer to an item on the stack. Used to find out if the stack
677 * grows up or down.
678 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679static int stack_grows_downwards;
680
681/*
682 * Find out if the stack grows upwards or downwards.
683 * "p" points to a variable on the stack of the caller.
684 */
685 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100686check_stack_growth(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687{
688 int i;
689
690 stack_grows_downwards = (p > (char *)&i);
691}
692#endif
693
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000694#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000695static char *stack_limit = NULL;
696
697#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
698# include <pthread.h>
699# include <pthread_np.h>
700#endif
701
702/*
703 * Find out until how var the stack can grow without getting into trouble.
704 * Called when starting up and when switching to the signal stack in
705 * deathtrap().
706 */
707 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100708get_stack_limit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000709{
710 struct rlimit rlp;
711 int i;
712 long lim;
713
Bram Moolenaar0f873732019-12-05 20:28:46 +0100714 // Set the stack limit to 15/16 of the allowable size. Skip this when the
715 // limit doesn't fit in a long (rlim_cur might be "long long").
Bram Moolenaar071d4272004-06-13 20:20:40 +0000716 if (getrlimit(RLIMIT_STACK, &rlp) == 0
717 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
718# ifdef RLIM_INFINITY
719 && rlp.rlim_cur != RLIM_INFINITY
720# endif
721 )
722 {
723 lim = (long)rlp.rlim_cur;
724#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
725 {
726 pthread_attr_t attr;
727 size_t size;
728
Bram Moolenaar0f873732019-12-05 20:28:46 +0100729 // On FreeBSD the initial thread always has a fixed stack size, no
730 // matter what the limits are set to. Normally it's 1 Mbyte.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731 pthread_attr_init(&attr);
732 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
733 {
734 pthread_attr_getstacksize(&attr, &size);
735 if (lim > (long)size)
736 lim = (long)size;
737 }
738 pthread_attr_destroy(&attr);
739 }
740#endif
741 if (stack_grows_downwards)
742 {
743 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
744 if (stack_limit >= (char *)&i)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100745 // overflow, set to 1/16 of current stack position
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746 stack_limit = (char *)((long)&i / 16L);
747 }
748 else
749 {
750 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
751 if (stack_limit <= (char *)&i)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100752 stack_limit = NULL; // overflow
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753 }
754 }
755}
756
757/*
758 * Return FAIL when running out of stack space.
759 * "p" must point to any variable local to the caller that's on the stack.
760 */
761 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100762mch_stackcheck(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763{
764 if (stack_limit != NULL)
765 {
766 if (stack_grows_downwards)
767 {
768 if (p < stack_limit)
769 return FAIL;
770 }
771 else if (p > stack_limit)
772 return FAIL;
773 }
774 return OK;
775}
776#endif
777
778#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
779/*
780 * Support for using the signal stack.
781 * This helps when we run out of stack space, which causes a SIGSEGV. The
782 * signal handler then must run on another stack, since the normal stack is
783 * completely full.
784 */
785
Bram Moolenaar0e62a672021-02-25 17:17:56 +0100786#if !defined SIGSTKSZ && !defined(HAVE_SYSCONF_SIGSTKSZ)
Bram Moolenaar0f873732019-12-05 20:28:46 +0100787# define SIGSTKSZ 8000 // just a guess of how much stack is needed...
Bram Moolenaar071d4272004-06-13 20:20:40 +0000788#endif
789
790# ifdef HAVE_SIGALTSTACK
Bram Moolenaar0f873732019-12-05 20:28:46 +0100791static stack_t sigstk; // for sigaltstack()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792# else
Bram Moolenaar0f873732019-12-05 20:28:46 +0100793static struct sigstack sigstk; // for sigstack()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794# endif
795
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796static char *signal_stack;
797
798 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100799init_signal_stack(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800{
801 if (signal_stack != NULL)
802 {
803# ifdef HAVE_SIGALTSTACK
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804# ifdef HAVE_SS_BASE
805 sigstk.ss_base = signal_stack;
806# else
807 sigstk.ss_sp = signal_stack;
808# endif
Bram Moolenaar0e62a672021-02-25 17:17:56 +0100809# ifdef HAVE_SYSCONF_SIGSTKSZ
810 sigstk.ss_size = sysconf(_SC_SIGSTKSZ);
811# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000812 sigstk.ss_size = SIGSTKSZ;
Bram Moolenaar0e62a672021-02-25 17:17:56 +0100813# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814 sigstk.ss_flags = 0;
815 (void)sigaltstack(&sigstk, NULL);
816# else
817 sigstk.ss_sp = signal_stack;
818 if (stack_grows_downwards)
Bram Moolenaar0e62a672021-02-25 17:17:56 +0100819# ifdef HAVE_SYSCONF_SIGSTKSZ
820 sigstk.ss_sp += sysconf(_SC_SIGSTKSZ) - 1;
821# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822 sigstk.ss_sp += SIGSTKSZ - 1;
Bram Moolenaar0e62a672021-02-25 17:17:56 +0100823# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000824 sigstk.ss_onstack = 0;
825 (void)sigstack(&sigstk, NULL);
826# endif
827 }
828}
829#endif
830
831/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000832 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000833 * will barf when the second argument to signal() is ``wrong''.
834 * Let me try it with a few tricky defines from my own osdef.h (jw).
835 */
836#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 static RETSIGTYPE
838sig_winch SIGDEFARG(sigarg)
839{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100840 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
842 do_resize = TRUE;
843 SIGRETURN;
844}
845#endif
846
847#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848 static RETSIGTYPE
849catch_sigint SIGDEFARG(sigarg)
850{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100851 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaar071d4272004-06-13 20:20:40 +0000852 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
853 got_int = TRUE;
854 SIGRETURN;
855}
856#endif
857
Bram Moolenaarbe5ee862020-06-10 20:56:58 +0200858#if defined(SIGUSR1)
859 static RETSIGTYPE
860catch_sigusr1 SIGDEFARG(sigarg)
861{
862 // this is not required on all systems, but it doesn't hurt anybody
863 signal(SIGUSR1, (RETSIGTYPE (*)())catch_sigusr1);
864 got_sigusr1 = TRUE;
865 SIGRETURN;
866}
867#endif
868
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870 static RETSIGTYPE
871catch_sigpwr SIGDEFARG(sigarg)
872{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100873 // this is not required on all systems, but it doesn't hurt anybody
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000874 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875 /*
876 * I'm not sure we get the SIGPWR signal when the system is really going
877 * down or when the batteries are almost empty. Just preserve the swap
878 * files and don't exit, that can't do any harm.
879 */
880 ml_sync_all(FALSE, FALSE);
881 SIGRETURN;
882}
883#endif
884
885#ifdef SET_SIG_ALARM
886/*
887 * signal function for alarm().
888 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889 static RETSIGTYPE
890sig_alarm SIGDEFARG(sigarg)
891{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100892 // doesn't do anything, just to break a system call
Bram Moolenaar071d4272004-06-13 20:20:40 +0000893 sig_alarm_called = TRUE;
894 SIGRETURN;
895}
896#endif
897
Bram Moolenaaredce7422019-01-20 18:39:30 +0100898#if (defined(HAVE_SETJMP_H) \
899 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
900 || defined(FEAT_LIBCALL))) \
901 || defined(PROTO)
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100902# define USING_SETJMP 1
Bram Moolenaaredce7422019-01-20 18:39:30 +0100903
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100904// argument to SETJMP()
905static JMP_BUF lc_jump_env;
906
907# ifdef SIGHASARG
Bram Moolenaar32aa1022019-11-02 22:54:41 +0100908// Caught signal number, 0 when no signal was caught; used for mch_libcall().
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100909// Volatile because it is used in signal handlers.
910static volatile sig_atomic_t lc_signal;
911# endif
912
913// TRUE when lc_jump_env is valid.
914// Volatile because it is used in signal handler deathtrap().
915static volatile sig_atomic_t lc_active INIT(= FALSE);
916
Bram Moolenaar071d4272004-06-13 20:20:40 +0000917/*
918 * A simplistic version of setjmp() that only allows one level of using.
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100919 * Used to protect areas where we could crash.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000920 * Don't call twice before calling mch_endjmp()!.
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100921 *
Bram Moolenaar071d4272004-06-13 20:20:40 +0000922 * Usage:
923 * mch_startjmp();
924 * if (SETJMP(lc_jump_env) != 0)
925 * {
926 * mch_didjmp();
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100927 * emsg("crash!");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000928 * }
929 * else
930 * {
931 * do_the_work;
932 * mch_endjmp();
933 * }
934 * Note: Can't move SETJMP() here, because a function calling setjmp() must
935 * not return before the saved environment is used.
936 * Returns OK for normal return, FAIL when the protected code caused a
937 * problem and LONGJMP() was used.
938 */
Bram Moolenaar113e1072019-01-20 15:30:40 +0100939 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100940mch_startjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000941{
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100942# ifdef SIGHASARG
Bram Moolenaar071d4272004-06-13 20:20:40 +0000943 lc_signal = 0;
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100944# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000945 lc_active = TRUE;
946}
947
Bram Moolenaar113e1072019-01-20 15:30:40 +0100948 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100949mch_endjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000950{
951 lc_active = FALSE;
952}
953
Bram Moolenaar113e1072019-01-20 15:30:40 +0100954 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100955mch_didjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000956{
957# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaarb7a7e032018-12-28 17:01:59 +0100958 // On FreeBSD the signal stack has to be reset after using siglongjmp(),
959 // otherwise catching the signal only works once.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000960 init_signal_stack();
961# endif
962}
963#endif
964
965/*
966 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200967 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000968 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200969 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
970 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971 */
972 static RETSIGTYPE
973deathtrap SIGDEFARG(sigarg)
974{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100975 static int entered = 0; // count the number of times we got here.
976 // Note: when memory has been corrupted
977 // this may get an arbitrary value!
Bram Moolenaar071d4272004-06-13 20:20:40 +0000978#ifdef SIGHASARG
979 int i;
980#endif
981
Bram Moolenaarb2148f52019-01-20 23:43:57 +0100982#if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000983 /*
984 * Catch a crash in protected code.
985 * Restores the environment saved in lc_jump_env, which looks like
986 * SETJMP() returns 1.
987 */
988 if (lc_active)
989 {
990# if defined(SIGHASARG)
991 lc_signal = sigarg;
992# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +0100993 lc_active = FALSE; // don't jump again
Bram Moolenaar071d4272004-06-13 20:20:40 +0000994 LONGJMP(lc_jump_env, 1);
Bram Moolenaar0f873732019-12-05 20:28:46 +0100995 // NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +0000996 }
997#endif
998
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000999#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +00001000# ifdef SIGQUIT
Bram Moolenaar0f873732019-12-05 20:28:46 +01001001 // While in mch_delay() we go to cooked mode to allow a CTRL-C to
1002 // interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
1003 // pressing CTRL-\, but we don't want Vim to exit then.
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +00001004 if (in_mch_delay && sigarg == SIGQUIT)
1005 SIGRETURN;
1006# endif
1007
Bram Moolenaar0f873732019-12-05 20:28:46 +01001008 // When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
1009 // here. This avoids that a non-reentrant function is interrupted, e.g.,
1010 // free(). Calling free() again may then cause a crash.
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001011 if (entered == 0
1012 && (0
1013# ifdef SIGHUP
1014 || sigarg == SIGHUP
1015# endif
1016# ifdef SIGQUIT
1017 || sigarg == SIGQUIT
1018# endif
1019# ifdef SIGTERM
1020 || sigarg == SIGTERM
1021# endif
1022# ifdef SIGPWR
1023 || sigarg == SIGPWR
1024# endif
1025# ifdef SIGUSR1
1026 || sigarg == SIGUSR1
1027# endif
1028# ifdef SIGUSR2
1029 || sigarg == SIGUSR2
1030# endif
1031 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001032 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001033 SIGRETURN;
1034#endif
1035
Bram Moolenaar0f873732019-12-05 20:28:46 +01001036 // Remember how often we have been called.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001037 ++entered;
1038
Bram Moolenaar0f873732019-12-05 20:28:46 +01001039 // Executing autocommands is likely to use more stack space than we have
1040 // available in the signal stack.
Bram Moolenaare429e702016-06-10 19:49:14 +02001041 block_autocmds();
Bram Moolenaare429e702016-06-10 19:49:14 +02001042
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043#ifdef FEAT_EVAL
Bram Moolenaar0f873732019-12-05 20:28:46 +01001044 // Set the v:dying variable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045 set_vim_var_nr(VV_DYING, (long)entered);
1046#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001047 v_dying = entered;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001048
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001049#ifdef HAVE_STACK_LIMIT
Bram Moolenaar0f873732019-12-05 20:28:46 +01001050 // Since we are now using the signal stack, need to reset the stack
1051 // limit. Otherwise using a regexp will fail.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001052 get_stack_limit();
1053#endif
1054
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001055#if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01001056 // This is for opening gdb the moment Vim crashes.
1057 // You need to manually adjust the file name and Vim executable name.
1058 // Suggested by SungHyun Nam.
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001059 {
1060# define VI_GDB_FILE "/tmp/vimgdb"
1061# define VIM_NAME "/usr/bin/vim"
1062 FILE *fp = fopen(VI_GDB_FILE, "w");
1063 if (fp)
1064 {
1065 fprintf(fp,
1066 "file %s\n"
1067 "attach %d\n"
1068 "set height 1000\n"
1069 "bt full\n"
1070 , VIM_NAME, getpid());
1071 fclose(fp);
1072 system("xterm -e gdb -x "VI_GDB_FILE);
1073 unlink(VI_GDB_FILE);
1074 }
1075 }
1076#endif
1077
Bram Moolenaar071d4272004-06-13 20:20:40 +00001078#ifdef SIGHASARG
Bram Moolenaar0f873732019-12-05 20:28:46 +01001079 // try to find the name of this signal
Bram Moolenaar071d4272004-06-13 20:20:40 +00001080 for (i = 0; signal_info[i].sig != -1; i++)
1081 if (sigarg == signal_info[i].sig)
1082 break;
1083 deadly_signal = sigarg;
1084#endif
1085
Bram Moolenaar0f873732019-12-05 20:28:46 +01001086 full_screen = FALSE; // don't write message to the GUI, it might be
1087 // part of the problem...
Bram Moolenaar071d4272004-06-13 20:20:40 +00001088 /*
1089 * If something goes wrong after entering here, we may get here again.
1090 * When this happens, give a message and try to exit nicely (resetting the
1091 * terminal mode, etc.)
1092 * When this happens twice, just exit, don't even try to give a message,
1093 * stack may be corrupt or something weird.
1094 * When this still happens again (or memory was corrupted in such a way
1095 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1096 */
1097 if (entered >= 3)
1098 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001099 reset_signals(); // don't catch any signals anymore
Bram Moolenaar071d4272004-06-13 20:20:40 +00001100 may_core_dump();
1101 if (entered >= 4)
1102 _exit(8);
1103 exit(7);
1104 }
1105 if (entered == 2)
1106 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001107 // No translation, it may call malloc().
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001108 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109 out_flush();
1110 getout(1);
1111 }
1112
Bram Moolenaar0f873732019-12-05 20:28:46 +01001113 // No translation, it may call malloc().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001114#ifdef SIGHASARG
Bram Moolenaar69212b12020-05-10 14:14:03 +02001115 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\r\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001116 signal_info[i].name);
1117#else
Bram Moolenaar69212b12020-05-10 14:14:03 +02001118 sprintf((char *)IObuff, "Vim: Caught deadly signal\r\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001119#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001120
Bram Moolenaar0f873732019-12-05 20:28:46 +01001121 // Preserve files and exit. This sets the really_exiting flag to prevent
1122 // calling free().
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001123 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124
Bram Moolenaar0f873732019-12-05 20:28:46 +01001125 // NOTREACHED
Bram Moolenaare429e702016-06-10 19:49:14 +02001126
Bram Moolenaar009b2592004-10-24 19:18:58 +00001127#ifdef NBDEBUG
1128 reset_signals();
1129 may_core_dump();
1130 abort();
1131#endif
1132
Bram Moolenaar071d4272004-06-13 20:20:40 +00001133 SIGRETURN;
1134}
1135
Bram Moolenaar071d4272004-06-13 20:20:40 +00001136/*
Bram Moolenaar2e310482018-08-21 13:09:10 +02001137 * Invoked after receiving SIGCONT. We don't know what happened while
1138 * sleeping, deal with part of that.
1139 */
1140 static void
1141after_sigcont(void)
1142{
1143# ifdef FEAT_TITLE
1144 // Don't change "oldtitle" in a signal handler, set a flag to obtain it
1145 // again later.
1146 oldtitle_outdated = TRUE;
1147# endif
1148 settmode(TMODE_RAW);
1149 need_check_timestamps = TRUE;
1150 did_check_timestamps = FALSE;
1151}
1152
1153#if defined(SIGCONT)
1154static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar8e82c052018-08-21 19:47:48 +02001155static volatile sig_atomic_t in_mch_suspend = FALSE;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001156
1157/*
1158 * With multi-threading, suspending might not work immediately. Catch the
1159 * SIGCONT signal, which will be used as an indication whether the suspending
1160 * has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001161 *
1162 * On Linux, signal is not always handled immediately either.
1163 * See https://bugs.launchpad.net/bugs/291373
Bram Moolenaar2e310482018-08-21 13:09:10 +02001164 * Probably because the signal is handled in another thread.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001165 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001166 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001167 */
Bram Moolenaar8e82c052018-08-21 19:47:48 +02001168static volatile sig_atomic_t sigcont_received;
Bram Moolenaarf1883472018-08-20 21:58:57 +02001169static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001170
1171/*
1172 * signal handler for SIGCONT
1173 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001174 static RETSIGTYPE
1175sigcont_handler SIGDEFARG(sigarg)
1176{
Bram Moolenaar2e310482018-08-21 13:09:10 +02001177 if (in_mch_suspend)
1178 {
1179 sigcont_received = TRUE;
1180 }
1181 else
1182 {
1183 // We didn't suspend ourselves, assume we were stopped by a SIGSTOP
1184 // signal (which can't be intercepted) and get a SIGCONT. Need to get
1185 // back to a sane mode. We should redraw, but we can't really do that
1186 // in a signal handler, do a redraw later.
1187 after_sigcont();
1188 redraw_later(CLEAR);
1189 cursor_on_force();
1190 out_flush();
1191 }
1192
Bram Moolenaar071d4272004-06-13 20:20:40 +00001193 SIGRETURN;
1194}
1195#endif
1196
Bram Moolenaar6dff58f2018-09-30 21:43:26 +02001197#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001198# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001199static void *clip_star_save = NULL;
1200static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001201# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001202
1203/*
1204 * Called when Vim is going to sleep or execute a shell command.
1205 * We can't respond to requests for the X selections. Lose them, otherwise
1206 * other applications will hang. But first copy the text to cut buffer 0.
1207 */
1208 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001209loose_clipboard(void)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001210{
1211 if (clip_star.owned || clip_plus.owned)
1212 {
1213 x11_export_final_selection();
1214 if (clip_star.owned)
1215 clip_lose_selection(&clip_star);
1216 if (clip_plus.owned)
1217 clip_lose_selection(&clip_plus);
1218 if (x11_display != NULL)
1219 XFlush(x11_display);
1220 }
1221}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001222
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001223# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001224/*
1225 * Save clipboard text to restore later.
1226 */
1227 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001228save_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001229{
1230 if (clip_star.owned)
1231 clip_star_save = get_register('*', TRUE);
1232 if (clip_plus.owned)
1233 clip_plus_save = get_register('+', TRUE);
1234}
1235
1236/*
1237 * Restore clipboard text if no one own the X selection.
1238 */
1239 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001240restore_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001241{
1242 if (clip_star_save != NULL)
1243 {
1244 if (!clip_gen_owner_exists(&clip_star))
1245 put_register('*', clip_star_save);
1246 else
1247 free_register(clip_star_save);
1248 clip_star_save = NULL;
1249 }
1250 if (clip_plus_save != NULL)
1251 {
1252 if (!clip_gen_owner_exists(&clip_plus))
1253 put_register('+', clip_plus_save);
1254 else
1255 free_register(clip_plus_save);
1256 clip_plus_save = NULL;
1257 }
1258}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001259# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001260#endif
1261
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262/*
1263 * If the machine has job control, use it to suspend the program,
1264 * otherwise fake it by starting a new shell.
1265 */
1266 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001267mch_suspend(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001268{
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001269 if (ignore_sigtstp)
1270 return;
1271
Bram Moolenaar041c7102020-05-30 18:14:57 +02001272#if defined(SIGTSTP)
Bram Moolenaar2e310482018-08-21 13:09:10 +02001273 in_mch_suspend = TRUE;
1274
Bram Moolenaar0f873732019-12-05 20:28:46 +01001275 out_flush(); // needed to make cursor visible on some systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00001276 settmode(TMODE_COOK);
Bram Moolenaar0f873732019-12-05 20:28:46 +01001277 out_flush(); // needed to disable mouse on some systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00001278
1279# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001280 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001282# if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001283 sigcont_received = FALSE;
1284# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001285
Bram Moolenaar0f873732019-12-05 20:28:46 +01001286 kill(0, SIGTSTP); // send ourselves a STOP signal
Bram Moolenaar2e310482018-08-21 13:09:10 +02001287
1288# if defined(SIGCONT)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001289 /*
1290 * Wait for the SIGCONT signal to be handled. It generally happens
Bram Moolenaar2e310482018-08-21 13:09:10 +02001291 * immediately, but somehow not all the time, probably because it's handled
1292 * in another thread. Do not call pause() because there would be race
1293 * condition which would hang Vim if signal happened in between the test of
1294 * sigcont_received and the call to pause(). If signal is not yet received,
1295 * sleep 0, 1, 2, 3 ms. Don't bother waiting further if signal is not
1296 * received after 1+2+3 ms (not expected to happen).
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001297 */
1298 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001299 long wait_time;
Bram Moolenaar2e310482018-08-21 13:09:10 +02001300
Bram Moolenaar262735e2009-07-14 10:20:22 +00001301 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar0981c872020-08-23 14:28:37 +02001302 mch_delay(wait_time, 0);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001303 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001304# endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001305 in_mch_suspend = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001306
Bram Moolenaar2e310482018-08-21 13:09:10 +02001307 after_sigcont();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308#else
1309 suspend_shell();
1310#endif
1311}
1312
1313 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001314mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315{
1316 Columns = 80;
1317 Rows = 24;
1318
1319 out_flush();
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001320
1321#ifdef SIGTSTP
1322 // Check whether we were invoked with SIGTSTP set to be ignored. If it is
1323 // that indicates the shell (or program) that launched us does not support
1324 // tty job control and thus we should ignore that signal. If invoked as a
1325 // restricted editor (e.g., as "rvim") SIGTSTP is always ignored.
1326 ignore_sigtstp = restricted || SIG_IGN == signal(SIGTSTP, SIG_ERR);
1327#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001328 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001329
Bram Moolenaar56718732006-03-15 22:53:57 +00001330#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001331 mac_conv_init();
1332#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001333#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1334 win_clip_init();
1335#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001336}
1337
1338 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001339set_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001340{
1341#if defined(SIGWINCH)
1342 /*
1343 * WINDOW CHANGE signal is handled with sig_winch().
1344 */
1345 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1346#endif
1347
Bram Moolenaar071d4272004-06-13 20:20:40 +00001348#ifdef SIGTSTP
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001349 // See mch_init() for the conditions under which we ignore SIGTSTP.
1350 signal(SIGTSTP, ignore_sigtstp ? SIG_IGN : SIG_DFL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001351#endif
Bram Moolenaar2e310482018-08-21 13:09:10 +02001352#if defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353 signal(SIGCONT, sigcont_handler);
1354#endif
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001355#ifdef SIGPIPE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001356 /*
1357 * We want to ignore breaking of PIPEs.
1358 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359 signal(SIGPIPE, SIG_IGN);
1360#endif
1361
Bram Moolenaar071d4272004-06-13 20:20:40 +00001362#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001363 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001364#endif
1365
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001366#ifdef SIGUSR1
1367 /*
1368 * Call user's handler on SIGUSR1
1369 */
1370 signal(SIGUSR1, (RETSIGTYPE (*)())catch_sigusr1);
1371#endif
1372
Bram Moolenaar071d4272004-06-13 20:20:40 +00001373 /*
1374 * Ignore alarm signals (Perl's alarm() generates it).
1375 */
1376#ifdef SIGALRM
1377 signal(SIGALRM, SIG_IGN);
1378#endif
1379
Bram Moolenaarbe5ee862020-06-10 20:56:58 +02001380#ifdef SIGPWR
Bram Moolenaar071d4272004-06-13 20:20:40 +00001381 /*
1382 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1383 * work will be lost.
1384 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001385 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1386#endif
1387
1388 /*
1389 * Arrange for other signals to gracefully shutdown Vim.
1390 */
1391 catch_signals(deathtrap, SIG_ERR);
1392
1393#if defined(FEAT_GUI) && defined(SIGHUP)
1394 /*
1395 * When the GUI is running, ignore the hangup signal.
1396 */
1397 if (gui.in_use)
1398 signal(SIGHUP, SIG_IGN);
1399#endif
1400}
1401
Bram Moolenaardf177f62005-02-22 08:39:57 +00001402#if defined(SIGINT) || defined(PROTO)
1403/*
1404 * Catch CTRL-C (only works while in Cooked mode).
1405 */
1406 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001407catch_int_signal(void)
Bram Moolenaardf177f62005-02-22 08:39:57 +00001408{
1409 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1410}
1411#endif
1412
Bram Moolenaar071d4272004-06-13 20:20:40 +00001413 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001414reset_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001415{
1416 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar2e310482018-08-21 13:09:10 +02001417#if defined(SIGCONT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001418 // SIGCONT isn't in the list, because its default action is ignore
Bram Moolenaar071d4272004-06-13 20:20:40 +00001419 signal(SIGCONT, SIG_DFL);
1420#endif
1421}
1422
1423 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001424catch_signals(
1425 RETSIGTYPE (*func_deadly)(),
1426 RETSIGTYPE (*func_other)())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001427{
1428 int i;
1429
1430 for (i = 0; signal_info[i].sig != -1; i++)
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001431 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001432 if (signal_info[i].deadly)
1433 {
1434#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1435 struct sigaction sa;
1436
Bram Moolenaar0f873732019-12-05 20:28:46 +01001437 // Setup to use the alternate stack for the signal function.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001438 sa.sa_handler = func_deadly;
1439 sigemptyset(&sa.sa_mask);
1440# if defined(__linux__) && defined(_REENTRANT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001441 // On Linux, with glibc compiled for kernel 2.2, there is a bug in
1442 // thread handling in combination with using the alternate stack:
1443 // pthread library functions try to use the stack pointer to
1444 // identify the current thread, causing a SEGV signal, which
1445 // recursively calls deathtrap() and hangs.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446 sa.sa_flags = 0;
1447# else
1448 sa.sa_flags = SA_ONSTACK;
1449# endif
1450 sigaction(signal_info[i].sig, &sa, NULL);
1451#else
1452# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1453 struct sigvec sv;
1454
Bram Moolenaar0f873732019-12-05 20:28:46 +01001455 // Setup to use the alternate stack for the signal function.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001456 sv.sv_handler = func_deadly;
1457 sv.sv_mask = 0;
1458 sv.sv_flags = SV_ONSTACK;
1459 sigvec(signal_info[i].sig, &sv, NULL);
1460# else
1461 signal(signal_info[i].sig, func_deadly);
1462# endif
1463#endif
1464 }
1465 else if (func_other != SIG_ERR)
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001466 {
1467 // Deal with non-deadly signals.
1468#ifdef SIGTSTP
1469 signal(signal_info[i].sig,
1470 signal_info[i].sig == SIGTSTP && ignore_sigtstp
1471 ? SIG_IGN : func_other);
1472#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001473 signal(signal_info[i].sig, func_other);
Bram Moolenaar5c3128e2020-05-11 20:54:42 +02001474#endif
1475 }
1476 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001477}
1478
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001479#ifdef HAVE_SIGPROCMASK
1480 static void
1481block_signals(sigset_t *set)
1482{
1483 sigset_t newset;
1484 int i;
1485
1486 sigemptyset(&newset);
1487
1488 for (i = 0; signal_info[i].sig != -1; i++)
1489 sigaddset(&newset, signal_info[i].sig);
1490
Bram Moolenaar2e310482018-08-21 13:09:10 +02001491# if defined(SIGCONT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001492 // SIGCONT isn't in the list, because its default action is ignore
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001493 sigaddset(&newset, SIGCONT);
1494# endif
1495
1496 sigprocmask(SIG_BLOCK, &newset, set);
1497}
1498
1499 static void
1500unblock_signals(sigset_t *set)
1501{
1502 sigprocmask(SIG_SETMASK, set, NULL);
1503}
1504#endif
1505
Bram Moolenaar071d4272004-06-13 20:20:40 +00001506/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001507 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001508 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1509 * return TRUE
1510 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1511 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001512 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001513 * Returns TRUE when Vim should exit.
1514 */
1515 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001516vim_handle_signal(int sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001517{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001518 static int got_signal = 0;
1519 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001520
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001521 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001522 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001523 case SIGNAL_BLOCK: blocked = TRUE;
1524 break;
1525
1526 case SIGNAL_UNBLOCK: blocked = FALSE;
1527 if (got_signal != 0)
1528 {
1529 kill(getpid(), got_signal);
1530 got_signal = 0;
1531 }
1532 break;
1533
1534 default: if (!blocked)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001535 return TRUE; // exit!
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001536 got_signal = sig;
1537#ifdef SIGPWR
1538 if (sig != SIGPWR)
1539#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01001540 got_int = TRUE; // break any loops
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001541 break;
1542 }
1543 return FALSE;
1544}
1545
1546/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001547 * Check_win checks whether we have an interactive stdout.
1548 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001549 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001550mch_check_win(int argc UNUSED, char **argv UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001551{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001552 if (isatty(1))
1553 return OK;
1554 return FAIL;
1555}
1556
1557/*
1558 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1559 */
1560 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001561mch_input_isatty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001562{
1563 if (isatty(read_cmd_fd))
1564 return TRUE;
1565 return FALSE;
1566}
1567
1568#ifdef FEAT_X11
1569
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001570# if defined(ELAPSED_TIMEVAL) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001571 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1572
Bram Moolenaar071d4272004-06-13 20:20:40 +00001573/*
1574 * Give a message about the elapsed time for opening the X window.
1575 */
1576 static void
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001577xopen_message(long elapsed_msec)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001578{
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001579 smsg(_("Opening the X display took %ld msec"), elapsed_msec);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001580}
1581# endif
1582#endif
1583
1584#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1585/*
1586 * A few functions shared by X11 title and clipboard code.
1587 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588
1589static int got_x_error = FALSE;
1590
1591/*
1592 * X Error handler, otherwise X just exits! (very rude) -- webb
1593 */
1594 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001595x_error_handler(Display *dpy, XErrorEvent *error_event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001597 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001598 STRCAT(IObuff, _("\nVim: Got X error\n"));
1599
Bram Moolenaarb1062eb2020-05-09 16:11:33 +02001600 // In the GUI we cannot print a message and continue, because no X calls
1601 // are allowed here (causes my system to hang). Silently continuing seems
1602 // like the best alternative. Do preserve files, in case we crash.
1603 ml_sync_all(FALSE, FALSE);
1604
1605#ifdef FEAT_GUI
1606 if (!gui.in_use)
1607#endif
1608 msg((char *)IObuff);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001609
Bram Moolenaar0f873732019-12-05 20:28:46 +01001610 return 0; // NOTREACHED
Bram Moolenaar071d4272004-06-13 20:20:40 +00001611}
1612
1613/*
1614 * Another X Error handler, just used to check for errors.
1615 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001617x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001618{
1619 got_x_error = TRUE;
1620 return 0;
1621}
1622
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001623/*
1624 * Return TRUE when connection to the X server is desired.
1625 */
1626 static int
1627x_connect_to_server(void)
1628{
1629 // No point in connecting if we are exiting or dying.
1630 if (exiting || v_dying)
1631 return FALSE;
1632
1633#if defined(FEAT_CLIENTSERVER)
1634 if (x_force_connect)
1635 return TRUE;
1636#endif
1637 if (x_no_connect)
1638 return FALSE;
1639
Bram Moolenaara8bfa172018-12-29 22:28:46 +01001640 // Check for a match with "exclude:" from 'clipboard'.
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001641 if (clip_exclude_prog != NULL)
1642 {
Bram Moolenaara8bfa172018-12-29 22:28:46 +01001643 // Just in case we get called recursively, return FALSE. This could
1644 // happen if vpeekc() is used while executing the prog and it causes a
1645 // related callback to be invoked.
1646 if (regprog_in_use(clip_exclude_prog))
1647 return FALSE;
1648
Bram Moolenaarc0c75492018-12-29 11:03:23 +01001649 if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
1650 return FALSE;
1651 }
1652 return TRUE;
1653}
1654
Bram Moolenaar071d4272004-06-13 20:20:40 +00001655#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaarb2148f52019-01-20 23:43:57 +01001656# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001657/*
1658 * An X IO Error handler, used to catch error while opening the display.
1659 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001660 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001661x_IOerror_check(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001662{
Bram Moolenaar0f873732019-12-05 20:28:46 +01001663 // This function should not return, it causes exit(). Longjump instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001664 LONGJMP(lc_jump_env, 1);
Bram Moolenaar1eed5322019-02-26 17:03:54 +01001665# if defined(VMS) || defined(__CYGWIN__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001666 return 0; // avoid the compiler complains about missing return value
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001667# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001668}
1669# endif
1670
1671/*
1672 * An X IO Error handler, used to catch terminal errors.
1673 */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001674static int xterm_dpy_retry_count = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675
Bram Moolenaar071d4272004-06-13 20:20:40 +00001676 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001677x_IOerror_handler(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678{
1679 xterm_dpy = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001680 xterm_dpy_retry_count = 5; // Try reconnecting five times
Bram Moolenaar071d4272004-06-13 20:20:40 +00001681 x11_window = 0;
1682 x11_display = NULL;
1683 xterm_Shell = (Widget)0;
1684
Bram Moolenaar0f873732019-12-05 20:28:46 +01001685 // This function should not return, it causes exit(). Longjump instead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686 LONGJMP(x_jump_env, 1);
Bram Moolenaar1eed5322019-02-26 17:03:54 +01001687# if defined(VMS) || defined(__CYGWIN__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01001688 return 0; // avoid the compiler complains about missing return value
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001689# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690}
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001691
1692/*
1693 * If the X11 connection was lost try to restore it.
1694 * Helps when the X11 server was stopped and restarted while Vim was inactive
Bram Moolenaarcaad4f02014-12-17 14:36:14 +01001695 * (e.g. through tmux).
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001696 */
1697 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001698may_restore_clipboard(void)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001699{
Bram Moolenaar01e51e52018-12-29 13:09:46 +01001700 // No point in restoring the connecting if we are exiting or dying.
1701 if (!exiting && !v_dying && xterm_dpy_retry_count > 0)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001702 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001703 --xterm_dpy_retry_count;
Bram Moolenaar527a6782014-12-17 17:59:31 +01001704
1705# ifndef LESSTIF_VERSION
Bram Moolenaar0f873732019-12-05 20:28:46 +01001706 // This has been reported to avoid Vim getting stuck.
Bram Moolenaar527a6782014-12-17 17:59:31 +01001707 if (app_context != (XtAppContext)NULL)
1708 {
1709 XtDestroyApplicationContext(app_context);
1710 app_context = (XtAppContext)NULL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01001711 x11_display = NULL; // freed by XtDestroyApplicationContext()
Bram Moolenaar527a6782014-12-17 17:59:31 +01001712 }
1713# endif
1714
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001715 setup_term_clip();
1716 get_x11_title(FALSE);
1717 }
1718}
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001719
1720 void
1721ex_xrestore(exarg_T *eap)
1722{
1723 if (eap->arg != NULL && STRLEN(eap->arg) > 0)
1724 {
1725 if (xterm_display_allocated)
1726 vim_free(xterm_display);
1727 xterm_display = (char *)vim_strsave(eap->arg);
1728 xterm_display_allocated = TRUE;
1729 }
1730 smsg(_("restoring display %s"), xterm_display == NULL
Bram Moolenaar0c5c3fa2019-11-30 22:38:16 +01001731 ? (char *)mch_getenv((char_u *)"DISPLAY") : xterm_display);
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001732
1733 clear_xterm_clip();
1734 x11_window = 0;
1735 xterm_dpy_retry_count = 5; // Try reconnecting five times
1736 may_restore_clipboard();
1737}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001738#endif
1739
1740/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741 * Test if "dpy" and x11_window are valid by getting the window title.
1742 * I don't actually want it yet, so there may be a simpler call to use, but
1743 * this will cause the error handler x_error_check() to be called if anything
1744 * is wrong, such as the window pointer being invalid (as can happen when the
1745 * user changes his DISPLAY, but not his WINDOWID) -- webb
1746 */
1747 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001748test_x11_window(Display *dpy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001749{
1750 int (*old_handler)();
1751 XTextProperty text_prop;
1752
1753 old_handler = XSetErrorHandler(x_error_check);
1754 got_x_error = FALSE;
1755 if (XGetWMName(dpy, x11_window, &text_prop))
1756 XFree((void *)text_prop.value);
1757 XSync(dpy, False);
1758 (void)XSetErrorHandler(old_handler);
1759
1760 if (p_verbose > 0 && got_x_error)
Bram Moolenaar32526b32019-01-19 17:43:09 +01001761 verb_msg(_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762
1763 return (got_x_error ? FAIL : OK);
1764}
1765#endif
1766
1767#ifdef FEAT_TITLE
1768
1769#ifdef FEAT_X11
1770
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001771static int get_x11_thing(int get_title, int test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772
1773/*
1774 * try to get x11 window and display
1775 *
1776 * return FAIL for failure, OK otherwise
1777 */
1778 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001779get_x11_windis(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001780{
1781 char *winid;
1782 static int result = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01001783#define XD_NONE 0 // x11_display not set here
1784#define XD_HERE 1 // x11_display opened here
1785#define XD_GUI 2 // x11_display used from gui.dpy
1786#define XD_XTERM 3 // x11_display used from xterm_dpy
Bram Moolenaar071d4272004-06-13 20:20:40 +00001787 static int x11_display_from = XD_NONE;
1788 static int did_set_error_handler = FALSE;
1789
1790 if (!did_set_error_handler)
1791 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001792 // X just exits if it finds an error otherwise!
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793 (void)XSetErrorHandler(x_error_handler);
1794 did_set_error_handler = TRUE;
1795 }
1796
Bram Moolenaar9372a112005-12-06 19:59:18 +00001797#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798 if (gui.in_use)
1799 {
1800 /*
1801 * If the X11 display was opened here before, for the window where Vim
1802 * was started, close that one now to avoid a memory leak.
1803 */
1804 if (x11_display_from == XD_HERE && x11_display != NULL)
1805 {
1806 XCloseDisplay(x11_display);
1807 x11_display_from = XD_NONE;
1808 }
1809 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1810 {
1811 x11_display_from = XD_GUI;
1812 return OK;
1813 }
1814 x11_display = NULL;
1815 return FAIL;
1816 }
1817 else if (x11_display_from == XD_GUI)
1818 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001819 // GUI must have stopped somehow, clear x11_display
Bram Moolenaar071d4272004-06-13 20:20:40 +00001820 x11_window = 0;
1821 x11_display = NULL;
1822 x11_display_from = XD_NONE;
1823 }
1824#endif
1825
Bram Moolenaar0f873732019-12-05 20:28:46 +01001826 // When started with the "-X" argument, don't try connecting.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001827 if (!x_connect_to_server())
1828 return FAIL;
1829
1830 /*
1831 * If WINDOWID not set, should try another method to find out
1832 * what the current window number is. The only code I know for
1833 * this is very complicated.
1834 * We assume that zero is invalid for WINDOWID.
1835 */
1836 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1837 x11_window = (Window)atol(winid);
1838
1839#ifdef FEAT_XCLIPBOARD
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02001840 if (xterm_dpy == x11_display)
1841 // x11_display may have been set to xterm_dpy elsewhere
1842 x11_display_from = XD_XTERM;
1843
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844 if (xterm_dpy != NULL && x11_window != 0)
1845 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001846 // We may have checked it already, but Gnome terminal can move us to
1847 // another window, so we need to check every time.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001848 if (x11_display_from != XD_XTERM)
1849 {
1850 /*
1851 * If the X11 display was opened here before, for the window where
1852 * Vim was started, close that one now to avoid a memory leak.
1853 */
1854 if (x11_display_from == XD_HERE && x11_display != NULL)
1855 XCloseDisplay(x11_display);
1856 x11_display = xterm_dpy;
1857 x11_display_from = XD_XTERM;
1858 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859 if (test_x11_window(x11_display) == FAIL)
1860 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001861 // probably bad $WINDOWID
Bram Moolenaar071d4272004-06-13 20:20:40 +00001862 x11_window = 0;
1863 x11_display = NULL;
1864 x11_display_from = XD_NONE;
1865 return FAIL;
1866 }
1867 return OK;
1868 }
1869#endif
1870
1871 if (x11_window == 0 || x11_display == NULL)
1872 result = -1;
1873
Bram Moolenaar0f873732019-12-05 20:28:46 +01001874 if (result != -1) // Have already been here and set this
1875 return result; // Don't do all these X calls again
Bram Moolenaar071d4272004-06-13 20:20:40 +00001876
1877 if (x11_window != 0 && x11_display == NULL)
1878 {
1879#ifdef SET_SIG_ALARM
1880 RETSIGTYPE (*sig_save)();
1881#endif
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01001882#ifdef ELAPSED_FUNC
1883 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001884
1885 if (p_verbose > 0)
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01001886 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001887#endif
1888
1889#ifdef SET_SIG_ALARM
1890 /*
1891 * Opening the Display may hang if the DISPLAY setting is wrong, or
1892 * the network connection is bad. Set an alarm timer to get out.
1893 */
1894 sig_alarm_called = FALSE;
1895 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1896 (RETSIGTYPE (*)())sig_alarm);
1897 alarm(2);
1898#endif
1899 x11_display = XOpenDisplay(NULL);
1900
1901#ifdef SET_SIG_ALARM
1902 alarm(0);
1903 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1904 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaar563bbea2019-01-22 21:45:40 +01001905 verb_msg(_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001906#endif
1907 if (x11_display != NULL)
1908 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001909# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001911 {
1912 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01001913 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001914 verbose_leave();
1915 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001916# endif
1917 if (test_x11_window(x11_display) == FAIL)
1918 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001919 // Maybe window id is bad
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920 x11_window = 0;
1921 XCloseDisplay(x11_display);
1922 x11_display = NULL;
1923 }
1924 else
1925 x11_display_from = XD_HERE;
1926 }
1927 }
1928 if (x11_window == 0 || x11_display == NULL)
1929 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001930
1931# ifdef FEAT_EVAL
1932 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1933# endif
1934
Bram Moolenaar071d4272004-06-13 20:20:40 +00001935 return (result = OK);
1936}
1937
1938/*
1939 * Determine original x11 Window Title
1940 */
1941 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001942get_x11_title(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001944 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945}
1946
1947/*
1948 * Determine original x11 Window icon
1949 */
1950 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001951get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952{
1953 int retval = FALSE;
1954
1955 retval = get_x11_thing(FALSE, test_only);
1956
Bram Moolenaar0f873732019-12-05 20:28:46 +01001957 // could not get old icon, use terminal name
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958 if (oldicon == NULL && !test_only)
1959 {
1960 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001961 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001962 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001963 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001964 }
1965
1966 return retval;
1967}
1968
1969 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001970get_x11_thing(
Bram Moolenaar0f873732019-12-05 20:28:46 +01001971 int get_title, // get title string
Bram Moolenaar05540972016-01-30 20:31:25 +01001972 int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001973{
1974 XTextProperty text_prop;
1975 int retval = FALSE;
1976 Status status;
1977
1978 if (get_x11_windis() == OK)
1979 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01001980 // Get window/icon name if any
Bram Moolenaar071d4272004-06-13 20:20:40 +00001981 if (get_title)
1982 status = XGetWMName(x11_display, x11_window, &text_prop);
1983 else
1984 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1985
1986 /*
1987 * If terminal is xterm, then x11_window may be a child window of the
1988 * outer xterm window that actually contains the window/icon name, so
1989 * keep traversing up the tree until a window with a title/icon is
1990 * found.
1991 */
Bram Moolenaar4b96df52020-01-26 22:00:26 +01001992 // Previously this was only done for xterm and alike. I don't see a
Bram Moolenaar0f873732019-12-05 20:28:46 +01001993 // reason why it would fail for other terminal emulators.
1994 // if (term_is_xterm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995 {
1996 Window root;
1997 Window parent;
1998 Window win = x11_window;
1999 Window *children;
2000 unsigned int num_children;
2001
2002 while (!status || text_prop.value == NULL)
2003 {
2004 if (!XQueryTree(x11_display, win, &root, &parent, &children,
2005 &num_children))
2006 break;
2007 if (children)
2008 XFree((void *)children);
2009 if (parent == root || parent == 0)
2010 break;
2011
2012 win = parent;
2013 if (get_title)
2014 status = XGetWMName(x11_display, win, &text_prop);
2015 else
2016 status = XGetWMIconName(x11_display, win, &text_prop);
2017 }
2018 }
2019 if (status && text_prop.value != NULL)
2020 {
2021 retval = TRUE;
2022 if (!test_only)
2023 {
Bram Moolenaar6b649ac2019-12-07 17:47:22 +01002024 if (get_title)
2025 vim_free(oldtitle);
2026 else
2027 vim_free(oldicon);
Bram Moolenaara12a1612019-01-24 16:39:02 +01002028 if (text_prop.encoding == XA_STRING && !has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002029 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002030 if (get_title)
2031 oldtitle = vim_strsave((char_u *)text_prop.value);
2032 else
2033 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002034 }
2035 else
2036 {
2037 char **cl;
2038 Status transform_status;
2039 int n = 0;
2040
2041 transform_status = XmbTextPropertyToTextList(x11_display,
2042 &text_prop,
2043 &cl, &n);
2044 if (transform_status >= Success && n > 0 && cl[0])
2045 {
2046 if (get_title)
2047 oldtitle = vim_strsave((char_u *) cl[0]);
2048 else
2049 oldicon = vim_strsave((char_u *) cl[0]);
2050 XFreeStringList(cl);
2051 }
2052 else
2053 {
2054 if (get_title)
2055 oldtitle = vim_strsave((char_u *)text_prop.value);
2056 else
2057 oldicon = vim_strsave((char_u *)text_prop.value);
2058 }
2059 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060 }
2061 XFree((void *)text_prop.value);
2062 }
2063 }
2064 return retval;
2065}
2066
Bram Moolenaar0f873732019-12-05 20:28:46 +01002067// Xutf8 functions are not available on older systems. Note that on some
2068// systems X_HAVE_UTF8_STRING may be defined in a header file but
2069// Xutf8SetWMProperties() is not in the X11 library. Configure checks for
2070// that and defines HAVE_XUTF8SETWMPROPERTIES.
Bram Moolenaara12a1612019-01-24 16:39:02 +01002071#if defined(X_HAVE_UTF8_STRING)
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002072# if X_HAVE_UTF8_STRING && HAVE_XUTF8SETWMPROPERTIES
Bram Moolenaar071d4272004-06-13 20:20:40 +00002073# define USE_UTF8_STRING
2074# endif
2075#endif
2076
2077/*
2078 * Set x11 Window Title
2079 *
2080 * get_x11_windis() must be called before this and have returned OK
2081 */
2082 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002083set_x11_title(char_u *title)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002084{
Bram Moolenaar0f873732019-12-05 20:28:46 +01002085 // XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
2086 // when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
2087 // supported everywhere and STRING doesn't work for multi-byte titles.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088#ifdef USE_UTF8_STRING
2089 if (enc_utf8)
2090 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
2091 NULL, NULL, 0, NULL, NULL, NULL);
2092 else
2093#endif
2094 {
2095#if XtSpecificationRelease >= 4
2096# ifdef FEAT_XFONTSET
2097 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
2098 NULL, NULL, 0, NULL, NULL, NULL);
2099# else
2100 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002101 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002102
Bram Moolenaar0f873732019-12-05 20:28:46 +01002103 // directly from example 3-18 "basicwin" of Xlib Programming Manual
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002104 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002105 XSetWMProperties(x11_display, x11_window, &text_prop,
2106 NULL, NULL, 0, NULL, NULL, NULL);
2107# endif
2108#else
2109 XStoreName(x11_display, x11_window, (char *)title);
2110#endif
2111 }
2112 XFlush(x11_display);
2113}
2114
2115/*
2116 * Set x11 Window icon
2117 *
2118 * get_x11_windis() must be called before this and have returned OK
2119 */
2120 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002121set_x11_icon(char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002122{
Bram Moolenaar0f873732019-12-05 20:28:46 +01002123 // See above for comments about using X*SetWMProperties().
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124#ifdef USE_UTF8_STRING
2125 if (enc_utf8)
2126 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2127 NULL, 0, NULL, NULL, NULL);
2128 else
2129#endif
2130 {
2131#if XtSpecificationRelease >= 4
2132# ifdef FEAT_XFONTSET
2133 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2134 NULL, 0, NULL, NULL, NULL);
2135# else
2136 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002137 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002138
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002139 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002140 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2141 NULL, 0, NULL, NULL, NULL);
2142# endif
2143#else
2144 XSetIconName(x11_display, x11_window, (char *)icon);
2145#endif
2146 }
2147 XFlush(x11_display);
2148}
2149
Bram Moolenaar0f873732019-12-05 20:28:46 +01002150#else // FEAT_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002151
Bram Moolenaar071d4272004-06-13 20:20:40 +00002152 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002153get_x11_title(int test_only UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002154{
2155 return FALSE;
2156}
2157
2158 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002159get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002160{
2161 if (!test_only)
2162 {
2163 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002164 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002166 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002167 }
2168 return FALSE;
2169}
2170
Bram Moolenaar0f873732019-12-05 20:28:46 +01002171#endif // FEAT_X11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172
2173 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002174mch_can_restore_title(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002175{
2176 return get_x11_title(TRUE);
2177}
2178
2179 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002180mch_can_restore_icon(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002181{
2182 return get_x11_icon(TRUE);
2183}
2184
2185/*
2186 * Set the window title and icon.
2187 */
2188 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002189mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002190{
2191 int type = 0;
2192 static int recursive = 0;
2193
Bram Moolenaar0f873732019-12-05 20:28:46 +01002194 if (T_NAME == NULL) // no terminal name (yet)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002195 return;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002196 if (title == NULL && icon == NULL) // nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00002197 return;
2198
Bram Moolenaar0f873732019-12-05 20:28:46 +01002199 // When one of the X11 functions causes a deadly signal, we get here again
2200 // recursively. Avoid hanging then (something is probably locked).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002201 if (recursive)
2202 return;
2203 ++recursive;
2204
2205 /*
2206 * if the window ID and the display is known, we may use X11 calls
2207 */
2208#ifdef FEAT_X11
2209 if (get_x11_windis() == OK)
2210 type = 1;
2211#else
Bram Moolenaar097148e2020-08-11 21:58:20 +02002212# if defined(FEAT_GUI_PHOTON) \
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002213 || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002214 if (gui.in_use)
2215 type = 1;
2216# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002217#endif
2218
2219 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002220 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221 * than x11 calls, because the x11 calls don't always work
2222 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002223 if ((type || *T_TS != NUL) && title != NULL)
2224 {
Bram Moolenaard8f0cef2018-08-19 22:20:16 +02002225 if (oldtitle_outdated)
2226 {
2227 oldtitle_outdated = FALSE;
2228 VIM_CLEAR(oldtitle);
2229 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002230 if (oldtitle == NULL
2231#ifdef FEAT_GUI
2232 && !gui.in_use
2233#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002234 ) // first call but not in GUI, save title
Bram Moolenaar071d4272004-06-13 20:20:40 +00002235 (void)get_x11_title(FALSE);
2236
Bram Moolenaar0f873732019-12-05 20:28:46 +01002237 if (*T_TS != NUL) // it's OK if t_fs is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00002238 term_settitle(title);
2239#ifdef FEAT_X11
2240 else
2241# ifdef FEAT_GUI_GTK
Bram Moolenaar0f873732019-12-05 20:28:46 +01002242 if (!gui.in_use) // don't do this if GTK+ is running
Bram Moolenaar071d4272004-06-13 20:20:40 +00002243# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002244 set_x11_title(title); // x11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002245#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01002246#if defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) \
Bram Moolenaar097148e2020-08-11 21:58:20 +02002247 || defined(FEAT_GUI_PHOTON)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248 else
2249 gui_mch_settitle(title, icon);
2250#endif
Bram Moolenaardac13472019-09-16 21:06:21 +02002251 unix_did_set_title = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252 }
2253
2254 if ((type || *T_CIS != NUL) && icon != NULL)
2255 {
2256 if (oldicon == NULL
2257#ifdef FEAT_GUI
2258 && !gui.in_use
2259#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002260 ) // first call, save icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002261 get_x11_icon(FALSE);
2262
2263 if (*T_CIS != NUL)
2264 {
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02002265 out_str(T_CIS); // set icon start
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 out_str_nf(icon);
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02002267 out_str(T_CIE); // set icon end
Bram Moolenaar071d4272004-06-13 20:20:40 +00002268 out_flush();
2269 }
2270#ifdef FEAT_X11
2271 else
2272# ifdef FEAT_GUI_GTK
Bram Moolenaar0f873732019-12-05 20:28:46 +01002273 if (!gui.in_use) // don't do this if GTK+ is running
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002275 set_x11_icon(icon); // x11
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276#endif
2277 did_set_icon = TRUE;
2278 }
2279 --recursive;
2280}
2281
2282/*
2283 * Restore the window/icon title.
2284 * "which" is one of:
Bram Moolenaar40385db2018-08-07 22:31:44 +02002285 * SAVE_RESTORE_TITLE only restore title
2286 * SAVE_RESTORE_ICON only restore icon
2287 * SAVE_RESTORE_BOTH restore title and icon
Bram Moolenaar071d4272004-06-13 20:20:40 +00002288 */
2289 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002290mch_restore_title(int which)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002291{
Bram Moolenaardac13472019-09-16 21:06:21 +02002292 int do_push_pop = unix_did_set_title || did_set_icon;
Bram Moolenaare5c83282019-05-03 23:15:37 +02002293
Bram Moolenaar0f873732019-12-05 20:28:46 +01002294 // only restore the title or icon when it has been set
Bram Moolenaardac13472019-09-16 21:06:21 +02002295 mch_settitle(((which & SAVE_RESTORE_TITLE) && unix_did_set_title) ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296 (oldtitle ? oldtitle : p_titleold) : NULL,
Bram Moolenaar40385db2018-08-07 22:31:44 +02002297 ((which & SAVE_RESTORE_ICON) && did_set_icon) ? oldicon : NULL);
2298
Bram Moolenaare5c83282019-05-03 23:15:37 +02002299 if (do_push_pop)
2300 {
2301 // pop and push from/to the stack
2302 term_pop_title(which);
2303 term_push_title(which);
2304 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305}
2306
Bram Moolenaar0f873732019-12-05 20:28:46 +01002307#endif // FEAT_TITLE
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308
2309/*
2310 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002311 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002312 */
2313 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002314vim_is_xterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002315{
2316 if (name == NULL)
2317 return FALSE;
2318 return (STRNICMP(name, "xterm", 5) == 0
2319 || STRNICMP(name, "nxterm", 6) == 0
2320 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002321 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322 || STRNICMP(name, "rxvt", 4) == 0
Bram Moolenaar995e4af2017-09-01 20:24:03 +02002323 || STRNICMP(name, "screen.xterm", 12) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324 || STRCMP(name, "builtin_xterm") == 0);
2325}
2326
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002327#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2328/*
2329 * Return TRUE if "name" appears to be that of a terminal
2330 * known to support the xterm-style mouse protocol.
2331 * Relies on term_is_xterm having been set to its correct value.
2332 */
2333 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002334use_xterm_like_mouse(char_u *name)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002335{
2336 return (name != NULL
Bram Moolenaare56132b2016-08-14 18:23:21 +02002337 && (term_is_xterm
2338 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002339 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaare56132b2016-08-14 18:23:21 +02002340 || STRICMP(name, "st") == 0
2341 || STRNICMP(name, "st-", 3) == 0
2342 || STRNICMP(name, "stterm", 6) == 0));
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002343}
2344#endif
2345
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346/*
2347 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2348 * Return 1 for "xterm".
2349 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002350 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002351 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352 */
2353 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002354use_xterm_mouse(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002355{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002356 if (ttym_flags == TTYM_SGR)
2357 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002358 if (ttym_flags == TTYM_URXVT)
2359 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 if (ttym_flags == TTYM_XTERM2)
2361 return 2;
2362 if (ttym_flags == TTYM_XTERM)
2363 return 1;
2364 return 0;
2365}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366
2367 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002368vim_is_iris(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369{
2370 if (name == NULL)
2371 return FALSE;
2372 return (STRNICMP(name, "iris-ansi", 9) == 0
2373 || STRCMP(name, "builtin_iris-ansi") == 0);
2374}
2375
2376 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002377vim_is_vt300(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002378{
2379 if (name == NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01002380 return FALSE; // actually all ANSI comp. terminals should be here
2381 // catch VT100 - VT5xx
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002382 return ((STRNICMP(name, "vt", 2) == 0
2383 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384 || STRCMP(name, "builtin_vt320") == 0);
2385}
2386
2387/*
2388 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2389 * This should include all windowed terminal emulators.
2390 */
2391 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002392vim_is_fastterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393{
2394 if (name == NULL)
2395 return FALSE;
2396 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2397 return TRUE;
2398 return ( STRNICMP(name, "hpterm", 6) == 0
2399 || STRNICMP(name, "sun-cmd", 7) == 0
2400 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002401 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402 || STRNICMP(name, "dtterm", 6) == 0);
2403}
2404
2405/*
2406 * Insert user name in s[len].
2407 * Return OK if a name found.
2408 */
2409 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002410mch_get_user_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002411{
2412#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002413 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414 return OK;
2415#else
2416 return mch_get_uname(getuid(), s, len);
2417#endif
2418}
2419
2420/*
2421 * Insert user name for "uid" in s[len].
2422 * Return OK if a name found.
2423 */
2424 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002425mch_get_uname(uid_t uid, char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426{
2427#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2428 struct passwd *pw;
2429
2430 if ((pw = getpwuid(uid)) != NULL
2431 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2432 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002433 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434 return OK;
2435 }
2436#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002437 sprintf((char *)s, "%d", (int)uid); // assumes s is long enough
2438 return FAIL; // a number is not a name
Bram Moolenaar071d4272004-06-13 20:20:40 +00002439}
2440
2441/*
2442 * Insert host name is s[len].
2443 */
2444
2445#ifdef HAVE_SYS_UTSNAME_H
2446 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002447mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002448{
2449 struct utsname vutsname;
2450
2451 if (uname(&vutsname) < 0)
2452 *s = NUL;
2453 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002454 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002455}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002456#else // HAVE_SYS_UTSNAME_H
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457
2458# ifdef HAVE_SYS_SYSTEMINFO_H
2459# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2460# endif
2461
2462 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002463mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464{
2465# ifdef VAXC
2466 vaxc$gethostname((char *)s, len);
2467# else
2468 gethostname((char *)s, len);
2469# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01002470 s[len - 1] = NUL; // make sure it's terminated
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002472#endif // HAVE_SYS_UTSNAME_H
Bram Moolenaar071d4272004-06-13 20:20:40 +00002473
2474/*
2475 * return process ID
2476 */
2477 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002478mch_get_pid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479{
2480 return (long)getpid();
2481}
2482
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002483/*
2484 * return TRUE if process "pid" is still running
2485 */
2486 int
Bram Moolenaar1b243ea2019-04-28 22:50:40 +02002487mch_process_running(long pid)
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002488{
Bram Moolenaar44dea9d2021-06-23 21:13:20 +02002489 // If there is no error the process must be running.
2490 if (kill(pid, 0) == 0)
2491 return TRUE;
2492#ifdef ESRCH
2493 // If the error is ESRCH then the process is not running.
2494 if (errno == ESRCH)
2495 return FALSE;
2496#endif
2497 // If the process is running and owned by another user we get EPERM. With
2498 // other errors the process might be running, assuming it is then.
2499 return TRUE;
Bram Moolenaar67cf86b2019-04-28 22:25:38 +02002500}
2501
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503 static char *
Bram Moolenaar05540972016-01-30 20:31:25 +01002504strerror(int err)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002505{
2506 extern int sys_nerr;
2507 extern char *sys_errlist[];
2508 static char er[20];
2509
2510 if (err > 0 && err < sys_nerr)
2511 return (sys_errlist[err]);
2512 sprintf(er, "Error %d", err);
2513 return er;
2514}
2515#endif
2516
2517/*
Bram Moolenaar964b3742019-05-24 18:54:09 +02002518 * Get name of current directory into buffer "buf" of length "len" bytes.
2519 * "len" must be at least PATH_MAX.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002520 * Return OK for success, FAIL for failure.
2521 */
2522 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002523mch_dirname(char_u *buf, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002524{
2525#if defined(USE_GETCWD)
2526 if (getcwd((char *)buf, len) == NULL)
2527 {
2528 STRCPY(buf, strerror(errno));
2529 return FAIL;
2530 }
2531 return OK;
2532#else
2533 return (getwd((char *)buf) != NULL ? OK : FAIL);
2534#endif
2535}
2536
Bram Moolenaar071d4272004-06-13 20:20:40 +00002537/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002538 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002539 *
2540 * return FAIL for failure, OK for success
2541 */
2542 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002543mch_FullName(
2544 char_u *fname,
2545 char_u *buf,
2546 int len,
Bram Moolenaar0f873732019-12-05 20:28:46 +01002547 int force) // also expand when already absolute path
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548{
2549 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002550#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002551 int fd = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002552 static int dont_fchdir = FALSE; // TRUE when fchdir() doesn't work
Bram Moolenaar38323e42007-03-06 19:22:53 +00002553#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002554 char_u olddir[MAXPATHL];
2555 char_u *p;
2556 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002557#ifdef __CYGWIN__
Bram Moolenaar0f873732019-12-05 20:28:46 +01002558 char_u posix_fname[MAXPATHL]; // Cygwin docs mention MAX_PATH, but
2559 // it's not always defined
Bram Moolenaarbf820722008-06-21 11:12:49 +00002560#endif
2561
Bram Moolenaar38323e42007-03-06 19:22:53 +00002562#ifdef VMS
2563 fname = vms_fixfilename(fname);
2564#endif
2565
Bram Moolenaara2442432007-04-26 14:26:37 +00002566#ifdef __CYGWIN__
2567 /*
2568 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2569 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002570# if CYGWIN_VERSION_DLL_MAJOR >= 1007
Bram Moolenaar0f873732019-12-05 20:28:46 +01002571 // Use CCP_RELATIVE to avoid that it sometimes returns a path that ends in
2572 // a forward slash.
Bram Moolenaar06b07342015-12-31 22:26:28 +01002573 cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE,
2574 fname, posix_fname, MAXPATHL);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002575# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002576 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002577# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002578 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002579#endif
2580
Bram Moolenaar0f873732019-12-05 20:28:46 +01002581 // Expand it if forced or not an absolute path.
2582 // Do not do it for "/file", the result is always "/".
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002583 if ((force || !mch_isFullName(fname))
2584 && ((p = vim_strrchr(fname, '/')) == NULL || p != fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002585 {
2586 /*
2587 * If the file name has a path, change to that directory for a moment,
Bram Moolenaar964b3742019-05-24 18:54:09 +02002588 * and then get the directory (and get back to where we were).
Bram Moolenaar071d4272004-06-13 20:20:40 +00002589 * This will get the correct path name with "../" things.
2590 */
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002591 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002592 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002593#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594 /*
2595 * Use fchdir() if possible, it's said to be faster and more
2596 * reliable. But on SunOS 4 it might not work. Check this by
2597 * doing a fchdir() right now.
2598 */
2599 if (!dont_fchdir)
2600 {
2601 fd = open(".", O_RDONLY | O_EXTRA, 0);
2602 if (fd >= 0 && fchdir(fd) < 0)
2603 {
2604 close(fd);
2605 fd = -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01002606 dont_fchdir = TRUE; // don't try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607 }
2608 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002609#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610
Bram Moolenaar0f873732019-12-05 20:28:46 +01002611 // Only change directory when we are sure we can return to where
2612 // we are now. After doing "su" chdir(".") might not work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002613 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002614#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002615 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002616#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002617 (mch_dirname(olddir, MAXPATHL) == FAIL
2618 || mch_chdir((char *)olddir) != 0))
2619 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002620 p = NULL; // can't get current dir: don't chdir
Bram Moolenaar071d4272004-06-13 20:20:40 +00002621 retval = FAIL;
2622 }
2623 else
2624 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002625 // The directory is copied into buf[], to be able to remove
2626 // the file name without changing it (could be a string in
2627 // read-only memory)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002628 if (p - fname >= len)
2629 retval = FAIL;
2630 else
2631 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002632 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002633 if (mch_chdir((char *)buf))
2634 retval = FAIL;
2635 else
2636 fname = p + 1;
2637 *buf = NUL;
2638 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002639 }
2640 }
2641 if (mch_dirname(buf, len) == FAIL)
2642 {
2643 retval = FAIL;
2644 *buf = NUL;
2645 }
2646 if (p != NULL)
2647 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002648#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002649 if (fd >= 0)
2650 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002651 if (p_verbose >= 5)
2652 {
2653 verbose_enter();
Bram Moolenaar32526b32019-01-19 17:43:09 +01002654 msg("fchdir() to previous dir");
Bram Moolenaar25724922009-07-14 15:38:41 +00002655 verbose_leave();
2656 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002657 l = fchdir(fd);
2658 close(fd);
2659 }
2660 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002661#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002662 l = mch_chdir((char *)olddir);
2663 if (l != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002664 emsg(_(e_prev_dir));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002665 }
2666
2667 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002668 if (l >= len - 1)
Bram Moolenaar0f873732019-12-05 20:28:46 +01002669 retval = FAIL; // no space for trailing "/"
Bram Moolenaar38323e42007-03-06 19:22:53 +00002670#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002671 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002672 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002673 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002674#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002675 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002676
Bram Moolenaar0f873732019-12-05 20:28:46 +01002677 // Catch file names which are too long.
Bram Moolenaar78a15312009-05-15 19:33:18 +00002678 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002679 return FAIL;
2680
Bram Moolenaar0f873732019-12-05 20:28:46 +01002681 // Do not append ".", "/dir/." is equal to "/dir".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682 if (STRCMP(fname, ".") != 0)
2683 STRCAT(buf, fname);
2684
2685 return OK;
2686}
2687
2688/*
2689 * Return TRUE if "fname" does not depend on the current directory.
2690 */
2691 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002692mch_isFullName(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693{
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002694#ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002695 return ( fname[0] == '/' || fname[0] == '.' ||
2696 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2697 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2698 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002699#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700 return (*fname == '/' || *fname == '~');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002701#endif
2702}
2703
Bram Moolenaar24552be2005-12-10 20:17:30 +00002704#if defined(USE_FNAME_CASE) || defined(PROTO)
2705/*
2706 * Set the case of the file name, if it already exists. This will cause the
2707 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002708 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002709 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002710 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002711fname_case(
2712 char_u *name,
Bram Moolenaar0f873732019-12-05 20:28:46 +01002713 int len UNUSED) // buffer size, only used when name gets longer
Bram Moolenaar24552be2005-12-10 20:17:30 +00002714{
2715 struct stat st;
2716 char_u *slash, *tail;
2717 DIR *dirp;
2718 struct dirent *dp;
2719
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002720 if (mch_lstat((char *)name, &st) >= 0)
Bram Moolenaar24552be2005-12-10 20:17:30 +00002721 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002722 // Open the directory where the file is located.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002723 slash = vim_strrchr(name, '/');
2724 if (slash == NULL)
2725 {
2726 dirp = opendir(".");
2727 tail = name;
2728 }
2729 else
2730 {
2731 *slash = NUL;
2732 dirp = opendir((char *)name);
2733 *slash = '/';
2734 tail = slash + 1;
2735 }
2736
2737 if (dirp != NULL)
2738 {
2739 while ((dp = readdir(dirp)) != NULL)
2740 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002741 // Only accept names that differ in case and are the same byte
2742 // length. TODO: accept different length name.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002743 if (STRICMP(tail, dp->d_name) == 0
2744 && STRLEN(tail) == STRLEN(dp->d_name))
2745 {
2746 char_u newname[MAXPATHL + 1];
2747 struct stat st2;
2748
Bram Moolenaar0f873732019-12-05 20:28:46 +01002749 // Verify the inode is equal.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002750 vim_strncpy(newname, name, MAXPATHL);
2751 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2752 MAXPATHL - (tail - name));
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002753 if (mch_lstat((char *)newname, &st2) >= 0
Bram Moolenaar24552be2005-12-10 20:17:30 +00002754 && st.st_ino == st2.st_ino
2755 && st.st_dev == st2.st_dev)
2756 {
2757 STRCPY(tail, dp->d_name);
2758 break;
2759 }
2760 }
2761 }
2762
2763 closedir(dirp);
2764 }
2765 }
2766}
2767#endif
2768
Bram Moolenaar071d4272004-06-13 20:20:40 +00002769/*
2770 * Get file permissions for 'name'.
2771 * Returns -1 when it doesn't exist.
2772 */
2773 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002774mch_getperm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775{
2776 struct stat statb;
2777
Bram Moolenaar0f873732019-12-05 20:28:46 +01002778 // Keep the #ifdef outside of stat(), it may be a macro.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779#ifdef VMS
2780 if (stat((char *)vms_fixfilename(name), &statb))
2781#else
2782 if (stat((char *)name, &statb))
2783#endif
2784 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002785#ifdef __INTERIX
Bram Moolenaar0f873732019-12-05 20:28:46 +01002786 // The top bit makes the value negative, which means the file doesn't
2787 // exist. Remove the bit, we don't use it.
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002788 return statb.st_mode & ~S_ADDACE;
2789#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002790 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002791#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792}
2793
2794/*
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002795 * Set file permission for "name" to "perm".
2796 * Return FAIL for failure, OK otherwise.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002797 */
2798 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002799mch_setperm(char_u *name, long perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002800{
2801 return (chmod((char *)
2802#ifdef VMS
2803 vms_fixfilename(name),
2804#else
2805 name,
2806#endif
2807 (mode_t)perm) == 0 ? OK : FAIL);
2808}
2809
Bram Moolenaarcd142e32017-11-16 17:03:45 +01002810#if defined(HAVE_FCHMOD) || defined(PROTO)
2811/*
2812 * Set file permission for open file "fd" to "perm".
2813 * Return FAIL for failure, OK otherwise.
2814 */
2815 int
2816mch_fsetperm(int fd, long perm)
2817{
2818 return (fchmod(fd, (mode_t)perm) == 0 ? OK : FAIL);
2819}
2820#endif
2821
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822#if defined(HAVE_ACL) || defined(PROTO)
2823# ifdef HAVE_SYS_ACL_H
2824# include <sys/acl.h>
2825# endif
2826# ifdef HAVE_SYS_ACCESS_H
2827# include <sys/access.h>
2828# endif
2829
2830# ifdef HAVE_SOLARIS_ACL
2831typedef struct vim_acl_solaris_T {
2832 int acl_cnt;
2833 aclent_t *acl_entry;
2834} vim_acl_solaris_T;
2835# endif
2836
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002837#if defined(HAVE_SELINUX) || defined(PROTO)
2838/*
2839 * Copy security info from "from_file" to "to_file".
2840 */
2841 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002842mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002843{
2844 if (from_file == NULL)
2845 return;
2846
2847 if (selinux_enabled == -1)
2848 selinux_enabled = is_selinux_enabled();
2849
2850 if (selinux_enabled > 0)
2851 {
Bram Moolenaar89560232020-10-09 23:04:47 +02002852 // Use "char *" instead of "security_context_t" to avoid a deprecation
2853 // warning.
2854 char *from_context = NULL;
2855 char *to_context = NULL;
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002856
2857 if (getfilecon((char *)from_file, &from_context) < 0)
2858 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002859 // If the filesystem doesn't support extended attributes,
2860 // the original had no special security context and the
2861 // target cannot have one either.
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002862 if (errno == EOPNOTSUPP)
2863 return;
2864
Bram Moolenaar32526b32019-01-19 17:43:09 +01002865 msg_puts(_("\nCould not get security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002866 msg_outtrans(from_file);
2867 msg_putchar('\n');
2868 return;
2869 }
2870 if (getfilecon((char *)to_file, &to_context) < 0)
2871 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01002872 msg_puts(_("\nCould not get security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002873 msg_outtrans(to_file);
2874 msg_putchar('\n');
2875 freecon (from_context);
2876 return ;
2877 }
2878 if (strcmp(from_context, to_context) != 0)
2879 {
2880 if (setfilecon((char *)to_file, from_context) < 0)
2881 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01002882 msg_puts(_("\nCould not set security context for "));
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002883 msg_outtrans(to_file);
2884 msg_putchar('\n');
2885 }
2886 }
2887 freecon(to_context);
2888 freecon(from_context);
2889 }
2890}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002891#endif // HAVE_SELINUX
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002892
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002893#if defined(HAVE_SMACK) && !defined(PROTO)
2894/*
2895 * Copy security info from "from_file" to "to_file".
2896 */
2897 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002898mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002899{
Bram Moolenaar62f167f2014-04-23 12:52:40 +02002900 static const char * const smack_copied_attributes[] =
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002901 {
2902 XATTR_NAME_SMACK,
2903 XATTR_NAME_SMACKEXEC,
2904 XATTR_NAME_SMACKMMAP
2905 };
2906
2907 char buffer[SMACK_LABEL_LEN];
2908 const char *name;
2909 int index;
2910 int ret;
2911 ssize_t size;
2912
2913 if (from_file == NULL)
2914 return;
2915
2916 for (index = 0 ; index < (int)(sizeof(smack_copied_attributes)
2917 / sizeof(smack_copied_attributes)[0]) ; index++)
2918 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002919 // get the name of the attribute to copy
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002920 name = smack_copied_attributes[index];
2921
Bram Moolenaar0f873732019-12-05 20:28:46 +01002922 // get the value of the attribute in buffer
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002923 size = getxattr((char*)from_file, name, buffer, sizeof(buffer));
2924 if (size >= 0)
2925 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002926 // copy the attribute value of buffer
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002927 ret = setxattr((char*)to_file, name, buffer, (size_t)size, 0);
2928 if (ret < 0)
2929 {
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002930 vim_snprintf((char *)IObuff, IOSIZE,
2931 _("Could not set security context %s for %s"),
2932 name, to_file);
2933 msg_outtrans(IObuff);
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002934 msg_putchar('\n');
2935 }
2936 }
2937 else
2938 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01002939 // what reason of not having the attribute value?
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002940 switch (errno)
2941 {
2942 case ENOTSUP:
Bram Moolenaar0f873732019-12-05 20:28:46 +01002943 // extended attributes aren't supported or enabled
2944 // should a message be echoed? not sure...
2945 return; // leave because it isn't useful to continue
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002946
2947 case ERANGE:
2948 default:
Bram Moolenaar0f873732019-12-05 20:28:46 +01002949 // no enough size OR unexpected error
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002950 vim_snprintf((char *)IObuff, IOSIZE,
2951 _("Could not get security context %s for %s. Removing it!"),
2952 name, from_file);
Bram Moolenaar32526b32019-01-19 17:43:09 +01002953 msg_puts((char *)IObuff);
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002954 msg_putchar('\n');
Bram Moolenaar0f873732019-12-05 20:28:46 +01002955 // FALLTHROUGH to remove the attribute
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002956
2957 case ENODATA:
Bram Moolenaar0f873732019-12-05 20:28:46 +01002958 // no attribute of this name
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002959 ret = removexattr((char*)to_file, name);
Bram Moolenaar0f873732019-12-05 20:28:46 +01002960 // Silently ignore errors, apparently this happens when
2961 // smack is not actually being used.
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002962 break;
2963 }
2964 }
2965 }
2966}
Bram Moolenaar0f873732019-12-05 20:28:46 +01002967#endif // HAVE_SMACK
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002968
Bram Moolenaar071d4272004-06-13 20:20:40 +00002969/*
2970 * Return a pointer to the ACL of file "fname" in allocated memory.
2971 * Return NULL if the ACL is not available for whatever reason.
2972 */
2973 vim_acl_T
Bram Moolenaar05540972016-01-30 20:31:25 +01002974mch_get_acl(char_u *fname UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002975{
2976 vim_acl_T ret = NULL;
2977#ifdef HAVE_POSIX_ACL
2978 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2979#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002980#ifdef HAVE_SOLARIS_ZFS_ACL
2981 acl_t *aclent;
2982
2983 if (acl_get((char *)fname, 0, &aclent) < 0)
2984 return NULL;
2985 ret = (vim_acl_T)aclent;
2986#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002987#ifdef HAVE_SOLARIS_ACL
2988 vim_acl_solaris_T *aclent;
2989
2990 aclent = malloc(sizeof(vim_acl_solaris_T));
2991 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2992 {
2993 free(aclent);
2994 return NULL;
2995 }
2996 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2997 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2998 {
2999 free(aclent->acl_entry);
3000 free(aclent);
3001 return NULL;
3002 }
3003 ret = (vim_acl_T)aclent;
3004#else
3005#if defined(HAVE_AIX_ACL)
3006 int aclsize;
3007 struct acl *aclent;
3008
3009 aclsize = sizeof(struct acl);
3010 aclent = malloc(aclsize);
3011 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
3012 {
3013 if (errno == ENOSPC)
3014 {
3015 aclsize = aclent->acl_len;
3016 aclent = realloc(aclent, aclsize);
3017 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
3018 {
3019 free(aclent);
3020 return NULL;
3021 }
3022 }
3023 else
3024 {
3025 free(aclent);
3026 return NULL;
3027 }
3028 }
3029 ret = (vim_acl_T)aclent;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003030#endif // HAVE_AIX_ACL
3031#endif // HAVE_SOLARIS_ACL
3032#endif // HAVE_SOLARIS_ZFS_ACL
3033#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034 return ret;
3035}
3036
3037/*
3038 * Set the ACL of file "fname" to "acl" (unless it's NULL).
3039 */
3040 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003041mch_set_acl(char_u *fname UNUSED, vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003042{
3043 if (aclent == NULL)
3044 return;
3045#ifdef HAVE_POSIX_ACL
3046 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
3047#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003048#ifdef HAVE_SOLARIS_ZFS_ACL
3049 acl_set((char *)fname, (acl_t *)aclent);
3050#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003051#ifdef HAVE_SOLARIS_ACL
3052 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
3053 ((vim_acl_solaris_T *)aclent)->acl_entry);
3054#else
3055#ifdef HAVE_AIX_ACL
3056 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003057#endif // HAVE_AIX_ACL
3058#endif // HAVE_SOLARIS_ACL
3059#endif // HAVE_SOLARIS_ZFS_ACL
3060#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061}
3062
3063 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003064mch_free_acl(vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003065{
3066 if (aclent == NULL)
3067 return;
3068#ifdef HAVE_POSIX_ACL
3069 acl_free((acl_t)aclent);
3070#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003071#ifdef HAVE_SOLARIS_ZFS_ACL
3072 acl_free((acl_t *)aclent);
3073#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003074#ifdef HAVE_SOLARIS_ACL
3075 free(((vim_acl_solaris_T *)aclent)->acl_entry);
3076 free(aclent);
3077#else
3078#ifdef HAVE_AIX_ACL
3079 free(aclent);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003080#endif // HAVE_AIX_ACL
3081#endif // HAVE_SOLARIS_ACL
3082#endif // HAVE_SOLARIS_ZFS_ACL
3083#endif // HAVE_POSIX_ACL
Bram Moolenaar071d4272004-06-13 20:20:40 +00003084}
3085#endif
3086
3087/*
3088 * Set hidden flag for "name".
3089 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003090 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003091mch_hide(char_u *name UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092{
Bram Moolenaar0f873732019-12-05 20:28:46 +01003093 // can't hide a file
Bram Moolenaar071d4272004-06-13 20:20:40 +00003094}
3095
3096/*
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003097 * return TRUE if "name" is a directory or a symlink to a directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098 * return FALSE if "name" is not a directory
3099 * return FALSE for error
3100 */
3101 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003102mch_isdir(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103{
3104 struct stat statb;
3105
Bram Moolenaar0f873732019-12-05 20:28:46 +01003106 if (*name == NUL) // Some stat()s don't flag "" as an error.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003107 return FALSE;
3108 if (stat((char *)name, &statb))
3109 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003110 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003111}
3112
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003113/*
3114 * return TRUE if "name" is a directory, NOT a symlink to a directory
3115 * return FALSE if "name" is not a directory
3116 * return FALSE for error
3117 */
3118 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003119mch_isrealdir(char_u *name)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003120{
3121 struct stat statb;
3122
Bram Moolenaar0f873732019-12-05 20:28:46 +01003123 if (*name == NUL) // Some stat()s don't flag "" as an error.
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003124 return FALSE;
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01003125 if (mch_lstat((char *)name, &statb))
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003126 return FALSE;
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003127 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003128}
3129
Bram Moolenaar071d4272004-06-13 20:20:40 +00003130/*
3131 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
3132 */
3133 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003134executable_file(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135{
3136 struct stat st;
3137
3138 if (stat((char *)name, &st))
3139 return 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003140#ifdef VMS
Bram Moolenaar0f873732019-12-05 20:28:46 +01003141 // Like on Unix system file can have executable rights but not necessarily
3142 // be an executable, but on Unix is not a default for an ordinary file to
3143 // have an executable flag - on VMS it is in most cases.
3144 // Therefore, this check does not have any sense - let keep us to the
3145 // conventions instead:
3146 // *.COM and *.EXE files are the executables - the rest are not. This is
3147 // not ideal but better then it was.
Bram Moolenaar206f0112014-03-12 16:51:55 +01003148 int vms_executable = 0;
3149 if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
3150 {
3151 if (strstr(vms_tolower((char*)name),".exe") != NULL
3152 || strstr(vms_tolower((char*)name),".com")!= NULL)
3153 vms_executable = 1;
3154 }
3155 return vms_executable;
3156#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003157 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003158#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159}
3160
3161/*
Bram Moolenaar2fcf6682017-03-11 20:03:42 +01003162 * Return TRUE if "name" can be found in $PATH and executed, FALSE if not.
Bram Moolenaarb5971142015-03-21 17:32:19 +01003163 * If "use_path" is FALSE only check if "name" is executable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003164 * Return -1 if unknown.
3165 */
3166 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003167mch_can_exe(char_u *name, char_u **path, int use_path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168{
3169 char_u *buf;
3170 char_u *p, *e;
3171 int retval;
3172
Bram Moolenaar0f873732019-12-05 20:28:46 +01003173 // When "use_path" is false and if it's an absolute or relative path don't
3174 // need to use $PATH.
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003175 if (!use_path || gettail(name) != name)
Bram Moolenaar206f0112014-03-12 16:51:55 +01003176 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003177 // There must be a path separator, files in the current directory
3178 // can't be executed.
Bram Moolenaard08b8c42019-07-24 14:59:45 +02003179 if ((use_path || gettail(name) != name) && executable_file(name))
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003180 {
3181 if (path != NULL)
3182 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003183 if (name[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003184 *path = FullName_save(name, TRUE);
3185 else
3186 *path = vim_strsave(name);
3187 }
3188 return TRUE;
3189 }
3190 return FALSE;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003191 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192
3193 p = (char_u *)getenv("PATH");
3194 if (p == NULL || *p == NUL)
3195 return -1;
Bram Moolenaar964b3742019-05-24 18:54:09 +02003196 buf = alloc(STRLEN(name) + STRLEN(p) + 2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197 if (buf == NULL)
3198 return -1;
3199
3200 /*
3201 * Walk through all entries in $PATH to check if "name" exists there and
3202 * is an executable file.
3203 */
3204 for (;;)
3205 {
3206 e = (char_u *)strchr((char *)p, ':');
3207 if (e == NULL)
3208 e = p + STRLEN(p);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003209 if (e - p <= 1) // empty entry means current dir
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210 STRCPY(buf, "./");
3211 else
3212 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003213 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214 add_pathsep(buf);
3215 }
3216 STRCAT(buf, name);
3217 retval = executable_file(buf);
3218 if (retval == 1)
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003219 {
3220 if (path != NULL)
3221 {
Bram Moolenaar43663192017-03-05 14:29:12 +01003222 if (buf[0] != '/')
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003223 *path = FullName_save(buf, TRUE);
3224 else
3225 *path = vim_strsave(buf);
3226 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003227 break;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003228 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003229
3230 if (*e != ':')
3231 break;
3232 p = e + 1;
3233 }
3234
3235 vim_free(buf);
3236 return retval;
3237}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003238
3239/*
3240 * Check what "name" is:
3241 * NODE_NORMAL: file or directory (or doesn't exist)
3242 * NODE_WRITABLE: writable device, socket, fifo, etc.
3243 * NODE_OTHER: non-writable things
3244 */
3245 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003246mch_nodetype(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003247{
3248 struct stat st;
3249
3250 if (stat((char *)name, &st))
3251 return NODE_NORMAL;
3252 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3253 return NODE_NORMAL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003254 if (S_ISBLK(st.st_mode)) // block device isn't writable
Bram Moolenaar071d4272004-06-13 20:20:40 +00003255 return NODE_OTHER;
Bram Moolenaar0f873732019-12-05 20:28:46 +01003256 // Everything else is writable?
Bram Moolenaar071d4272004-06-13 20:20:40 +00003257 return NODE_WRITABLE;
3258}
3259
3260 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003261mch_early_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262{
3263#ifdef HAVE_CHECK_STACK_GROWTH
3264 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265
Bram Moolenaar071d4272004-06-13 20:20:40 +00003266 check_stack_growth((char *)&i);
3267
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003268# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003269 get_stack_limit();
3270# endif
3271
3272#endif
3273
3274 /*
3275 * Setup an alternative stack for signals. Helps to catch signals when
3276 * running out of stack space.
3277 * Use of sigaltstack() is preferred, it's more portable.
3278 * Ignore any errors.
3279 */
3280#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar0e62a672021-02-25 17:17:56 +01003281# ifdef HAVE_SYSCONF_SIGSTKSZ
3282 signal_stack = alloc(sysconf(_SC_SIGSTKSZ));
3283# else
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003284 signal_stack = alloc(SIGSTKSZ);
Bram Moolenaar0e62a672021-02-25 17:17:56 +01003285# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003286 init_signal_stack();
3287#endif
3288}
3289
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003290#if defined(EXITFREE) || defined(PROTO)
3291 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003292mch_free_mem(void)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003293{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003294# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3295 if (clip_star.owned)
3296 clip_lose_selection(&clip_star);
3297 if (clip_plus.owned)
3298 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003299# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003300# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003301 if (xterm_Shell != (Widget)0)
3302 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003303# ifndef LESSTIF_VERSION
Bram Moolenaar0f873732019-12-05 20:28:46 +01003304 // Lesstif crashes here, lose some memory
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003305 if (xterm_dpy != NULL)
3306 XtCloseDisplay(xterm_dpy);
3307 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003308 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003309 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003310# ifdef FEAT_X11
Bram Moolenaar0f873732019-12-05 20:28:46 +01003311 x11_display = NULL; // freed by XtDestroyApplicationContext()
Bram Moolenaare8208012008-06-20 09:59:25 +00003312# endif
3313 }
3314# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003315# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003316# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003317 if (x11_display != NULL
3318# ifdef FEAT_XCLIPBOARD
3319 && x11_display != xterm_dpy
3320# endif
3321 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003322 XCloseDisplay(x11_display);
3323# endif
3324# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaard23a8232018-02-10 18:45:26 +01003325 VIM_CLEAR(signal_stack);
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003326# endif
3327# ifdef FEAT_TITLE
3328 vim_free(oldtitle);
3329 vim_free(oldicon);
3330# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003331}
3332#endif
3333
Bram Moolenaar071d4272004-06-13 20:20:40 +00003334/*
3335 * Output a newline when exiting.
3336 * Make sure the newline goes to the same stream as the text.
3337 */
3338 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003339exit_scroll(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003340{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003341 if (silent_mode)
3342 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003343 if (newline_on_exit || msg_didout)
3344 {
3345 if (msg_use_printf())
3346 {
3347 if (info_message)
3348 mch_msg("\n");
3349 else
3350 mch_errmsg("\r\n");
3351 }
3352 else
3353 out_char('\n');
3354 }
Bram Moolenaar7007e312021-03-27 12:11:33 +01003355 else if (!is_not_a_term())
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003357 restore_cterm_colors(); // get original colors back
3358 msg_clr_eos_force(); // clear the rest of the display
3359 windgoto((int)Rows - 1, 0); // may have moved the cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00003360 }
3361}
3362
Bram Moolenaarb4151682020-05-11 22:13:28 +02003363#ifdef USE_GCOV_FLUSH
3364extern void __gcov_flush();
3365#endif
3366
Bram Moolenaar071d4272004-06-13 20:20:40 +00003367 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003368mch_exit(int r)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003369{
3370 exiting = TRUE;
3371
3372#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3373 x11_export_final_selection();
3374#endif
3375
3376#ifdef FEAT_GUI
3377 if (!gui.in_use)
3378#endif
3379 {
3380 settmode(TMODE_COOK);
3381#ifdef FEAT_TITLE
Bram Moolenaar7007e312021-03-27 12:11:33 +01003382 if (!is_not_a_term())
3383 {
3384 // restore xterm title and icon name
3385 mch_restore_title(SAVE_RESTORE_BOTH);
3386 term_pop_title(SAVE_RESTORE_BOTH);
3387 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003388#endif
3389 /*
3390 * When t_ti is not empty but it doesn't cause swapping terminal
3391 * pages, need to output a newline when msg_didout is set. But when
3392 * t_ti does swap pages it should not go to the shell page. Do this
3393 * before stoptermcap().
3394 */
3395 if (swapping_screen() && !newline_on_exit)
3396 exit_scroll();
3397
Bram Moolenaar0f873732019-12-05 20:28:46 +01003398 // Stop termcap: May need to check for T_CRV response, which
3399 // requires RAW mode.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003400 stoptermcap();
3401
3402 /*
3403 * A newline is only required after a message in the alternate screen.
3404 * This is set to TRUE by wait_return().
3405 */
3406 if (!swapping_screen() || newline_on_exit)
3407 exit_scroll();
3408
Bram Moolenaar0f873732019-12-05 20:28:46 +01003409 // Cursor may have been switched off without calling starttermcap()
3410 // when doing "vim -u vimrc" and vimrc contains ":q".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003411 if (full_screen)
3412 cursor_on();
3413 }
3414 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01003415 ml_close_all(TRUE); // remove all memfiles
Bram Moolenaarb4151682020-05-11 22:13:28 +02003416
3417#ifdef USE_GCOV_FLUSH
3418 // Flush coverage info before possibly being killed by a deadly signal.
3419 __gcov_flush();
3420#endif
3421
Bram Moolenaar071d4272004-06-13 20:20:40 +00003422 may_core_dump();
3423#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003424 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425 gui_exit(r);
3426#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003427
Bram Moolenaar56718732006-03-15 22:53:57 +00003428#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003429 mac_conv_cleanup();
3430#endif
3431
Bram Moolenaar071d4272004-06-13 20:20:40 +00003432#ifdef __QNX__
Bram Moolenaar0f873732019-12-05 20:28:46 +01003433 // A core dump won't be created if the signal handler
3434 // doesn't return, so we can't call exit()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003435 if (deadly_signal != 0)
3436 return;
3437#endif
3438
Bram Moolenaar009b2592004-10-24 19:18:58 +00003439#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003440 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003441#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003442
3443#ifdef EXITFREE
3444 free_all_mem();
3445#endif
3446
Bram Moolenaar071d4272004-06-13 20:20:40 +00003447 exit(r);
3448}
3449
3450 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003451may_core_dump(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003452{
3453 if (deadly_signal != 0)
3454 {
3455 signal(deadly_signal, SIG_DFL);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003456 kill(getpid(), deadly_signal); // Die using the signal we caught
Bram Moolenaar071d4272004-06-13 20:20:40 +00003457 }
3458}
3459
3460#ifndef VMS
3461
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003462/*
3463 * Get the file descriptor to use for tty operations.
3464 */
3465 static int
3466get_tty_fd(int fd)
3467{
3468 int tty_fd = fd;
3469
3470#if defined(HAVE_SVR4_PTYS) && defined(SUN_SYSTEM)
3471 // On SunOS: Get the terminal parameters from "fd", or the slave device of
3472 // "fd" when it is a master device.
3473 if (mch_isatty(fd) > 1)
3474 {
3475 char *name;
3476
3477 name = ptsname(fd);
3478 if (name == NULL)
3479 return -1;
3480
3481 tty_fd = open(name, O_RDONLY | O_NOCTTY | O_EXTRA, 0);
3482 if (tty_fd < 0)
3483 return -1;
3484 }
3485#endif
3486 return tty_fd;
3487}
3488
3489 static int
3490mch_tcgetattr(int fd, void *term)
3491{
3492 int tty_fd;
3493 int retval = -1;
3494
3495 tty_fd = get_tty_fd(fd);
3496 if (tty_fd >= 0)
3497 {
3498#ifdef NEW_TTY_SYSTEM
3499# ifdef HAVE_TERMIOS_H
3500 retval = tcgetattr(tty_fd, (struct termios *)term);
3501# else
3502 retval = ioctl(tty_fd, TCGETA, (struct termio *)term);
3503# endif
3504#else
3505 // for "old" tty systems
3506 retval = ioctl(tty_fd, TIOCGETP, (struct sgttyb *)term);
3507#endif
3508 if (tty_fd != fd)
3509 close(tty_fd);
3510 }
3511 return retval;
3512}
3513
Bram Moolenaar071d4272004-06-13 20:20:40 +00003514 void
Bram Moolenaar26e86442020-05-17 14:06:16 +02003515mch_settmode(tmode_T tmode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003516{
3517 static int first = TRUE;
3518
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003519#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520# ifdef HAVE_TERMIOS_H
3521 static struct termios told;
3522 struct termios tnew;
3523# else
3524 static struct termio told;
3525 struct termio tnew;
3526# endif
3527
3528 if (first)
3529 {
3530 first = FALSE;
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003531 mch_tcgetattr(read_cmd_fd, &told);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532 }
3533
3534 tnew = told;
3535 if (tmode == TMODE_RAW)
3536 {
Bram Moolenaar041c7102020-05-30 18:14:57 +02003537 // ~ICRNL enables typing ^V^M
Bram Moolenaar928eec62020-05-31 13:09:47 +02003538 // ~IXON disables CTRL-S stopping output, so that it can be mapped.
3539 tnew.c_iflag &= ~(ICRNL | IXON);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
Bram Moolenaare3f915d2020-07-14 23:02:44 +02003541# if defined(IEXTEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01003542 | IEXTEN // IEXTEN enables typing ^V on SOLARIS
Bram Moolenaar071d4272004-06-13 20:20:40 +00003543# endif
3544 );
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003545# ifdef ONLCR
3546 // Don't map NL -> CR NL, we do it ourselves.
3547 // Also disable expanding tabs if possible.
3548# ifdef XTABS
3549 tnew.c_oflag &= ~(ONLCR | XTABS);
3550# else
3551# ifdef TAB3
3552 tnew.c_oflag &= ~(ONLCR | TAB3);
3553# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554 tnew.c_oflag &= ~ONLCR;
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003555# endif
3556# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003557# endif
Bram Moolenaarfaf626e2019-10-24 17:43:25 +02003558 tnew.c_cc[VMIN] = 1; // return after 1 char
3559 tnew.c_cc[VTIME] = 0; // don't wait
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560 }
3561 else if (tmode == TMODE_SLEEP)
Bram Moolenaar40de4562016-07-01 15:03:46 +02003562 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003563 // Also reset ICANON here, otherwise on Solaris select() won't see
3564 // typeahead characters.
Bram Moolenaar40de4562016-07-01 15:03:46 +02003565 tnew.c_lflag &= ~(ICANON | ECHO);
Bram Moolenaar0f873732019-12-05 20:28:46 +01003566 tnew.c_cc[VMIN] = 1; // return after 1 char
3567 tnew.c_cc[VTIME] = 0; // don't wait
Bram Moolenaar40de4562016-07-01 15:03:46 +02003568 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569
3570# if defined(HAVE_TERMIOS_H)
3571 {
3572 int n = 10;
3573
Bram Moolenaar0f873732019-12-05 20:28:46 +01003574 // A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3575 // few times.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003576 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3577 && errno == EINTR && n > 0)
3578 --n;
3579 }
3580# else
3581 ioctl(read_cmd_fd, TCSETA, &tnew);
3582# endif
3583
3584#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003585 /*
3586 * for "old" tty systems
3587 */
3588# ifndef TIOCSETN
Bram Moolenaar0f873732019-12-05 20:28:46 +01003589# define TIOCSETN TIOCSETP // for hpux 9.0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590# endif
3591 static struct sgttyb ttybold;
3592 struct sgttyb ttybnew;
3593
3594 if (first)
3595 {
3596 first = FALSE;
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003597 mch_tcgetattr(read_cmd_fd, &ttybold);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003598 }
3599
3600 ttybnew = ttybold;
3601 if (tmode == TMODE_RAW)
3602 {
3603 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3604 ttybnew.sg_flags |= RAW;
3605 }
3606 else if (tmode == TMODE_SLEEP)
3607 ttybnew.sg_flags &= ~(ECHO);
3608 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3609#endif
Bram Moolenaar26e86442020-05-17 14:06:16 +02003610 mch_cur_tmode = tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003611}
3612
3613/*
3614 * Try to get the code for "t_kb" from the stty setting
3615 *
3616 * Even if termcap claims a backspace key, the user's setting *should*
3617 * prevail. stty knows more about reality than termcap does, and if
3618 * somebody's usual erase key is DEL (which, for most BSD users, it will
3619 * be), they're going to get really annoyed if their erase key starts
3620 * doing forward deletes for no reason. (Eric Fischer)
3621 */
3622 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003623get_stty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003624{
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003625 ttyinfo_T info;
3626 char_u buf[2];
3627 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003628
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003629 if (get_tty_info(read_cmd_fd, &info) == OK)
3630 {
3631 intr_char = info.interrupt;
3632 buf[0] = info.backspace;
3633 buf[1] = NUL;
3634 add_termcode((char_u *)"kb", buf, FALSE);
3635
Bram Moolenaar0f873732019-12-05 20:28:46 +01003636 // If <BS> and <DEL> are now the same, redefine <DEL>.
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003637 p = find_termcode((char_u *)"kD");
3638 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3639 do_fixdel(NULL);
3640 }
3641}
3642
3643/*
3644 * Obtain the characters that Backspace and Enter produce on "fd".
3645 * Returns OK or FAIL.
3646 */
3647 int
3648get_tty_info(int fd, ttyinfo_T *info)
3649{
3650#ifdef NEW_TTY_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003651# ifdef HAVE_TERMIOS_H
3652 struct termios keys;
3653# else
3654 struct termio keys;
3655# endif
3656
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003657 if (mch_tcgetattr(fd, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003658 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003659 info->backspace = keys.c_cc[VERASE];
3660 info->interrupt = keys.c_cc[VINTR];
3661 if (keys.c_iflag & ICRNL)
3662 info->enter = NL;
3663 else
3664 info->enter = CAR;
3665 if (keys.c_oflag & ONLCR)
3666 info->nl_does_cr = TRUE;
3667 else
3668 info->nl_does_cr = FALSE;
3669 return OK;
3670 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671#else
Bram Moolenaar0f873732019-12-05 20:28:46 +01003672 // for "old" tty systems
Bram Moolenaar071d4272004-06-13 20:20:40 +00003673 struct sgttyb keys;
3674
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01003675 if (mch_tcgetattr(fd, &keys) != -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003676 {
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003677 info->backspace = keys.sg_erase;
3678 info->interrupt = keys.sg_kill;
3679 info->enter = CAR;
3680 info->nl_does_cr = TRUE;
3681 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003682 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003683#endif
Bram Moolenaar4f44b882017-08-13 20:06:18 +02003684 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685}
3686
Bram Moolenaar0f873732019-12-05 20:28:46 +01003687#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00003688
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003689static int mouse_ison = FALSE;
3690
Bram Moolenaar071d4272004-06-13 20:20:40 +00003691/*
3692 * Set mouse clicks on or off.
3693 */
3694 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003695mch_setmouse(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003696{
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003697#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003698 static int bevalterm_ison = FALSE;
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003699#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003700 int xterm_mouse_vers;
3701
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003702#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaara06afc72018-08-27 23:24:16 +02003703 if (!on)
3704 // Make sure not tracing mouse movements. Important when a button-down
3705 // was received but no release yet.
3706 stop_xterm_trace();
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003707#endif
Bram Moolenaara06afc72018-08-27 23:24:16 +02003708
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003709 if (on == mouse_ison
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003710#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003711 && p_bevalterm == bevalterm_ison
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003712#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003713 )
Bram Moolenaar0f873732019-12-05 20:28:46 +01003714 // return quickly if nothing to do
Bram Moolenaar071d4272004-06-13 20:20:40 +00003715 return;
3716
3717 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003718
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003719#ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003720 if (ttym_flags == TTYM_URXVT)
3721 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003722 out_str_nf((char_u *)
3723 (on
3724 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3725 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003726 mouse_ison = on;
Bram Moolenaarc8427482011-10-20 21:09:35 +02003727 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003728#endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003729
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003730 if (ttym_flags == TTYM_SGR)
3731 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003732 // SGR mode supports columns above 223
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003733 out_str_nf((char_u *)
3734 (on
3735 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3736 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003737 mouse_ison = on;
3738 }
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003739
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003740#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003741 if (bevalterm_ison != (p_bevalterm && on))
3742 {
3743 bevalterm_ison = (p_bevalterm && on);
3744 if (xterm_mouse_vers > 1 && !bevalterm_ison)
Bram Moolenaar0f873732019-12-05 20:28:46 +01003745 // disable mouse movement events, enabling is below
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003746 out_str_nf((char_u *)
3747 (IF_EB("\033[?1003l", ESC_STR "[?1003l")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003748 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003749#endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003750
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751 if (xterm_mouse_vers > 0)
3752 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003753 if (on) // enable mouse events, use mouse tracking if available
Bram Moolenaar071d4272004-06-13 20:20:40 +00003754 out_str_nf((char_u *)
3755 (xterm_mouse_vers > 1
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003756 ? (
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003757#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003758 bevalterm_ison
3759 ? IF_EB("\033[?1003h", ESC_STR "[?1003h") :
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003760#endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003761 IF_EB("\033[?1002h", ESC_STR "[?1002h"))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003762 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
Bram Moolenaar0f873732019-12-05 20:28:46 +01003763 else // disable mouse events, could probably always send the same
Bram Moolenaar071d4272004-06-13 20:20:40 +00003764 out_str_nf((char_u *)
3765 (xterm_mouse_vers > 1
3766 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3767 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003768 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769 }
3770
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003771#ifdef FEAT_MOUSE_DEC
Bram Moolenaar071d4272004-06-13 20:20:40 +00003772 else if (ttym_flags == TTYM_DEC)
3773 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003774 if (on) // enable mouse events
Bram Moolenaar071d4272004-06-13 20:20:40 +00003775 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
Bram Moolenaar0f873732019-12-05 20:28:46 +01003776 else // disable mouse events
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777 out_str_nf((char_u *)"\033['z");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003778 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003779 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003780#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003781
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003782#ifdef FEAT_MOUSE_GPM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783 else
3784 {
3785 if (on)
3786 {
3787 if (gpm_open())
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003788 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003789 }
3790 else
3791 {
3792 gpm_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003793 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794 }
3795 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003796#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003797
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003798#ifdef FEAT_SYSMOUSE
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003799 else
3800 {
3801 if (on)
3802 {
3803 if (sysmouse_open() == OK)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003804 mouse_ison = TRUE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003805 }
3806 else
3807 {
3808 sysmouse_close();
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003809 mouse_ison = FALSE;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003810 }
3811 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003812#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003813
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003814#ifdef FEAT_MOUSE_JSB
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815 else
3816 {
3817 if (on)
3818 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003819 // D - Enable Mouse up/down messages
3820 // L - Enable Left Button Reporting
3821 // M - Enable Middle Button Reporting
3822 // R - Enable Right Button Reporting
3823 // K - Enable SHIFT and CTRL key Reporting
3824 // + - Enable Advanced messaging of mouse moves and up/down messages
3825 // Q - Quiet No Ack
3826 // # - Numeric value of mouse pointer required
3827 // 0 = Multiview 2000 cursor, used as standard
3828 // 1 = Windows Arrow
3829 // 2 = Windows I Beam
3830 // 3 = Windows Hour Glass
3831 // 4 = Windows Cross Hair
3832 // 5 = Windows UP Arrow
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003833# ifdef JSBTERM_MOUSE_NONADVANCED
Bram Moolenaar0f873732019-12-05 20:28:46 +01003834 // Disables full feedback of pointer movements
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3836 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003837# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003838 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3839 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003840# endif
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003841 mouse_ison = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003842 }
3843 else
3844 {
3845 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3846 ESC_STR "[0~ZwQ" ESC_STR "\\"));
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003847 mouse_ison = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003848 }
3849 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003850#endif
3851#ifdef FEAT_MOUSE_PTERM
Bram Moolenaar071d4272004-06-13 20:20:40 +00003852 else
3853 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003854 // 1 = button press, 6 = release, 7 = drag, 1h...9l = right button
Bram Moolenaar071d4272004-06-13 20:20:40 +00003855 if (on)
3856 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3857 else
3858 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003859 mouse_ison = on;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003860 }
Bram Moolenaara1cb1d12019-10-17 23:00:07 +02003861#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003862}
3863
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003864#if defined(FEAT_BEVAL_TERM) || defined(PROTO)
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003865/*
3866 * Called when 'balloonevalterm' changed.
3867 */
3868 void
3869mch_bevalterm_changed(void)
3870{
3871 mch_setmouse(mouse_ison);
3872}
3873#endif
3874
Bram Moolenaar071d4272004-06-13 20:20:40 +00003875/*
3876 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3877 */
3878 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003879check_mouse_termcode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003880{
3881# ifdef FEAT_MOUSE_XTERM
3882 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003883# ifdef FEAT_MOUSE_URXVT
3884 && use_xterm_mouse() != 3
3885# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003886# ifdef FEAT_GUI
3887 && !gui.in_use
3888# endif
3889 )
3890 {
3891 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003892 ? IF_EB("\233M", CSI_STR "M")
3893 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003894 if (*p_mouse != NUL)
3895 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01003896 // force mouse off and maybe on to send possibly new mouse
3897 // activation sequence to the xterm, with(out) drag tracing.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003898 mch_setmouse(FALSE);
3899 setmouse();
3900 }
3901 }
3902 else
3903 del_mouse_termcode(KS_MOUSE);
3904# endif
3905
3906# ifdef FEAT_MOUSE_GPM
3907 if (!use_xterm_mouse()
3908# ifdef FEAT_GUI
3909 && !gui.in_use
3910# endif
3911 )
Bram Moolenaarbedf0912019-05-04 16:58:45 +02003912 set_mouse_termcode(KS_GPM_MOUSE,
3913 (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3914 else
3915 del_mouse_termcode(KS_GPM_MOUSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003916# endif
3917
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003918# ifdef FEAT_SYSMOUSE
3919 if (!use_xterm_mouse()
3920# ifdef FEAT_GUI
3921 && !gui.in_use
3922# endif
3923 )
3924 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3925# endif
3926
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927# ifdef FEAT_MOUSE_JSB
Bram Moolenaar0f873732019-12-05 20:28:46 +01003928 // Conflicts with xterm mouse: "\033[" and "\033[M" ???
Bram Moolenaar071d4272004-06-13 20:20:40 +00003929 if (!use_xterm_mouse()
3930# ifdef FEAT_GUI
3931 && !gui.in_use
3932# endif
3933 )
3934 set_mouse_termcode(KS_JSBTERM_MOUSE,
3935 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3936 else
3937 del_mouse_termcode(KS_JSBTERM_MOUSE);
3938# endif
3939
3940# ifdef FEAT_MOUSE_NET
Bram Moolenaar0f873732019-12-05 20:28:46 +01003941 // There is no conflict, but one may type "ESC }" from Insert mode. Don't
3942 // define it in the GUI or when using an xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003943 if (!use_xterm_mouse()
3944# ifdef FEAT_GUI
3945 && !gui.in_use
3946# endif
3947 )
3948 set_mouse_termcode(KS_NETTERM_MOUSE,
3949 (char_u *)IF_EB("\033}", ESC_STR "}"));
3950 else
3951 del_mouse_termcode(KS_NETTERM_MOUSE);
3952# endif
3953
3954# ifdef FEAT_MOUSE_DEC
Bram Moolenaar0f873732019-12-05 20:28:46 +01003955 // Conflicts with xterm mouse: "\033[" and "\033[M"
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003956 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003957# ifdef FEAT_GUI
3958 && !gui.in_use
3959# endif
3960 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003961 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3962 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003963 else
3964 del_mouse_termcode(KS_DEC_MOUSE);
3965# endif
3966# ifdef FEAT_MOUSE_PTERM
Bram Moolenaar0f873732019-12-05 20:28:46 +01003967 // same conflict as the dec mouse
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003968 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003969# ifdef FEAT_GUI
3970 && !gui.in_use
3971# endif
3972 )
3973 set_mouse_termcode(KS_PTERM_MOUSE,
3974 (char_u *) IF_EB("\033[", ESC_STR "["));
3975 else
3976 del_mouse_termcode(KS_PTERM_MOUSE);
3977# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003978# ifdef FEAT_MOUSE_URXVT
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003979 if (use_xterm_mouse() == 3
Bram Moolenaarc8427482011-10-20 21:09:35 +02003980# ifdef FEAT_GUI
3981 && !gui.in_use
3982# endif
3983 )
3984 {
3985 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02003986 ? IF_EB("\233*M", CSI_STR "*M")
3987 : IF_EB("\033[*M", ESC_STR "[*M")));
Bram Moolenaarc8427482011-10-20 21:09:35 +02003988
3989 if (*p_mouse != NUL)
3990 {
3991 mch_setmouse(FALSE);
3992 setmouse();
3993 }
3994 }
3995 else
3996 del_mouse_termcode(KS_URXVT_MOUSE);
3997# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003998 if (use_xterm_mouse() == 4
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003999# ifdef FEAT_GUI
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004000 && !gui.in_use
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01004001# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004002 )
4003 {
4004 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaara529ce02017-06-22 22:37:57 +02004005 ? IF_EB("\233<*M", CSI_STR "<*M")
4006 : IF_EB("\033[<*M", ESC_STR "[<*M")));
4007
4008 set_mouse_termcode(KS_SGR_MOUSE_RELEASE, (char_u *)(term_is_8bit(T_NAME)
4009 ? IF_EB("\233<*m", CSI_STR "<*m")
4010 : IF_EB("\033[<*m", ESC_STR "[<*m")));
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004011
4012 if (*p_mouse != NUL)
4013 {
4014 mch_setmouse(FALSE);
4015 setmouse();
4016 }
4017 }
4018 else
Bram Moolenaara529ce02017-06-22 22:37:57 +02004019 {
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02004020 del_mouse_termcode(KS_SGR_MOUSE);
Bram Moolenaara529ce02017-06-22 22:37:57 +02004021 del_mouse_termcode(KS_SGR_MOUSE_RELEASE);
4022 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024
Bram Moolenaar071d4272004-06-13 20:20:40 +00004025#ifndef VMS
4026
4027/*
4028 * Try to get the current window size:
4029 * 1. with an ioctl(), most accurate method
4030 * 2. from the environment variables LINES and COLUMNS
4031 * 3. from the termcap
4032 * 4. keep using the old values
4033 * Return OK when size could be determined, FAIL otherwise.
4034 */
4035 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004036mch_get_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004037{
4038 long rows = 0;
4039 long columns = 0;
4040 char_u *p;
4041
4042 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004043 * 1. try using an ioctl. It is the most accurate method.
4044 *
4045 * Try using TIOCGWINSZ first, some systems that have it also define
4046 * TIOCGSIZE but don't have a struct ttysize.
4047 */
4048# ifdef TIOCGWINSZ
4049 {
4050 struct winsize ws;
4051 int fd = 1;
4052
Bram Moolenaar0f873732019-12-05 20:28:46 +01004053 // When stdout is not a tty, use stdin for the ioctl().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054 if (!isatty(fd) && isatty(read_cmd_fd))
4055 fd = read_cmd_fd;
4056 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
4057 {
4058 columns = ws.ws_col;
4059 rows = ws.ws_row;
4060 }
4061 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004062# else // TIOCGWINSZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00004063# ifdef TIOCGSIZE
4064 {
4065 struct ttysize ts;
4066 int fd = 1;
4067
Bram Moolenaar0f873732019-12-05 20:28:46 +01004068 // When stdout is not a tty, use stdin for the ioctl().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004069 if (!isatty(fd) && isatty(read_cmd_fd))
4070 fd = read_cmd_fd;
4071 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
4072 {
4073 columns = ts.ts_cols;
4074 rows = ts.ts_lines;
4075 }
4076 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004077# endif // TIOCGSIZE
4078# endif // TIOCGWINSZ
Bram Moolenaar071d4272004-06-13 20:20:40 +00004079
4080 /*
4081 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004082 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
4083 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004084 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004085 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004086 {
4087 if ((p = (char_u *)getenv("LINES")))
4088 rows = atoi((char *)p);
4089 if ((p = (char_u *)getenv("COLUMNS")))
4090 columns = atoi((char *)p);
4091 }
4092
4093#ifdef HAVE_TGETENT
4094 /*
4095 * 3. try reading "co" and "li" entries from termcap
4096 */
4097 if (columns == 0 || rows == 0)
4098 getlinecol(&columns, &rows);
4099#endif
4100
4101 /*
4102 * 4. If everything fails, use the old values
4103 */
4104 if (columns <= 0 || rows <= 0)
4105 return FAIL;
4106
4107 Rows = rows;
4108 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02004109 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004110 return OK;
4111}
4112
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004113#if defined(FEAT_TERMINAL) || defined(PROTO)
4114/*
4115 * Report the windows size "rows" and "cols" to tty "fd".
4116 */
4117 int
4118mch_report_winsize(int fd, int rows, int cols)
4119{
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004120 int tty_fd;
4121 int retval = -1;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004122
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004123 tty_fd = get_tty_fd(fd);
4124 if (tty_fd >= 0)
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004125 {
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004126# if defined(TIOCSWINSZ)
4127 struct winsize ws;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004128
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004129 ws.ws_col = cols;
4130 ws.ws_row = rows;
4131 ws.ws_xpixel = cols * 5;
4132 ws.ws_ypixel = rows * 10;
4133 retval = ioctl(tty_fd, TIOCSWINSZ, &ws);
4134 ch_log(NULL, "ioctl(TIOCSWINSZ) %s",
4135 retval == 0 ? "success" : "failed");
4136# elif defined(TIOCSSIZE)
4137 struct ttysize ts;
4138
4139 ts.ts_cols = cols;
4140 ts.ts_lines = rows;
4141 retval = ioctl(tty_fd, TIOCSSIZE, &ts);
4142 ch_log(NULL, "ioctl(TIOCSSIZE) %s",
4143 retval == 0 ? "success" : "failed");
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004144# endif
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004145 if (tty_fd != fd)
4146 close(tty_fd);
4147 }
4148 return retval == 0 ? OK : FAIL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02004149}
4150#endif
4151
Bram Moolenaar071d4272004-06-13 20:20:40 +00004152/*
4153 * Try to set the window size to Rows and Columns.
4154 */
4155 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004156mch_set_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004157{
4158 if (*T_CWS)
4159 {
4160 /*
4161 * NOTE: if you get an error here that term_set_winsize() is
4162 * undefined, check the output of configure. It could probably not
4163 * find a ncurses, termcap or termlib library.
4164 */
4165 term_set_winsize((int)Rows, (int)Columns);
4166 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01004167 screen_start(); // don't know where cursor is now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168 }
4169}
4170
Bram Moolenaar0f873732019-12-05 20:28:46 +01004171#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172
4173/*
4174 * Rows and/or Columns has changed.
4175 */
4176 void
Bram Moolenaar05540972016-01-30 20:31:25 +01004177mch_new_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178{
Bram Moolenaar0f873732019-12-05 20:28:46 +01004179 // Nothing to do.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004180}
4181
Bram Moolenaar205b8862011-09-07 15:04:31 +02004182/*
4183 * Wait for process "child" to end.
4184 * Return "child" if it exited properly, <= 0 on error.
4185 */
4186 static pid_t
Bram Moolenaar05540972016-01-30 20:31:25 +01004187wait4pid(pid_t child, waitstatus *status)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004188{
4189 pid_t wait_pid = 0;
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004190 long delay_msec = 1;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004191
4192 while (wait_pid != child)
4193 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004194 // When compiled with Python threads are probably used, in which case
4195 // wait() sometimes hangs for no obvious reason. Use waitpid()
4196 // instead and loop (like the GUI). Also needed for other interfaces,
4197 // they might call system().
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004198# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004199 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004200# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02004201 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004202# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02004203 if (wait_pid == 0)
4204 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004205 // Wait for 1 to 10 msec before trying again.
Bram Moolenaar0981c872020-08-23 14:28:37 +02004206 mch_delay(delay_msec, MCH_DELAY_IGNOREINPUT | MCH_DELAY_SETTMODE);
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004207 if (++delay_msec > 10)
4208 delay_msec = 10;
Bram Moolenaar205b8862011-09-07 15:04:31 +02004209 continue;
4210 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004211 if (wait_pid <= 0
4212# ifdef ECHILD
4213 && errno == ECHILD
4214# endif
4215 )
4216 break;
4217 }
4218 return wait_pid;
4219}
4220
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01004221#if !defined(USE_SYSTEM) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar7da34602017-08-01 17:14:21 +02004222/*
4223 * Set the environment for a child process.
4224 */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004225 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004226set_child_environment(
4227 long rows,
4228 long columns,
4229 char *term,
4230 int is_terminal UNUSED)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004231{
4232# ifdef HAVE_SETENV
4233 char envbuf[50];
4234# else
Bram Moolenaar5f7e7bd2017-07-22 14:08:43 +02004235 static char envbuf_Term[30];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004236 static char envbuf_Rows[20];
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004237 static char envbuf_Lines[20];
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004238 static char envbuf_Columns[20];
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004239 static char envbuf_Colors[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004240# ifdef FEAT_TERMINAL
Bram Moolenaard7a137f2018-06-12 18:05:24 +02004241 static char envbuf_Version[20];
Bram Moolenaar493359e2018-06-12 20:25:52 +02004242# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004243# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004244 static char envbuf_Servername[60];
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004245# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004246# endif
4247
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004248# ifdef HAVE_SETENV
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004249 setenv("TERM", term, 1);
4250 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004251 setenv("ROWS", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004252 sprintf((char *)envbuf, "%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004253 setenv("LINES", (char *)envbuf, 1);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004254 sprintf((char *)envbuf, "%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004255 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaar759d8152020-04-26 16:52:49 +02004256 sprintf((char *)envbuf, "%d", t_colors);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004257 setenv("COLORS", (char *)envbuf, 1);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004258# ifdef FEAT_TERMINAL
4259 if (is_terminal)
4260 {
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004261 sprintf((char *)envbuf, "%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004262 setenv("VIM_TERMINAL", (char *)envbuf, 1);
4263 }
4264# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004265# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004266 setenv("VIM_SERVERNAME", serverName == NULL ? "" : (char *)serverName, 1);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004267# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004268# else
4269 /*
4270 * Putenv does not copy the string, it has to remain valid.
4271 * Use a static array to avoid losing allocated memory.
Bram Moolenaar7da34602017-08-01 17:14:21 +02004272 * This won't work well when running multiple children...
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004273 */
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004274 vim_snprintf(envbuf_Term, sizeof(envbuf_Term), "TERM=%s", term);
4275 putenv(envbuf_Term);
4276 vim_snprintf(envbuf_Rows, sizeof(envbuf_Rows), "ROWS=%ld", rows);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004277 putenv(envbuf_Rows);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004278 vim_snprintf(envbuf_Lines, sizeof(envbuf_Lines), "LINES=%ld", rows);
4279 putenv(envbuf_Lines);
4280 vim_snprintf(envbuf_Columns, sizeof(envbuf_Columns),
4281 "COLUMNS=%ld", columns);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004282 putenv(envbuf_Columns);
Bram Moolenaaraffc8fd2020-04-28 21:58:29 +02004283 vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", t_colors);
Bram Moolenaarb7a8dfe2017-07-22 20:33:05 +02004284 putenv(envbuf_Colors);
Bram Moolenaar493359e2018-06-12 20:25:52 +02004285# ifdef FEAT_TERMINAL
4286 if (is_terminal)
4287 {
4288 vim_snprintf(envbuf_Version, sizeof(envbuf_Version),
Bram Moolenaar5ecdf962018-06-13 20:49:50 +02004289 "VIM_TERMINAL=%ld", (long)get_vim_var_nr(VV_VERSION));
Bram Moolenaar493359e2018-06-12 20:25:52 +02004290 putenv(envbuf_Version);
4291 }
4292# endif
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004293# ifdef FEAT_CLIENTSERVER
Bram Moolenaar7da34602017-08-01 17:14:21 +02004294 vim_snprintf(envbuf_Servername, sizeof(envbuf_Servername),
4295 "VIM_SERVERNAME=%s", serverName == NULL ? "" : (char *)serverName);
4296 putenv(envbuf_Servername);
Bram Moolenaar2a4f06f2017-08-01 18:44:29 +02004297# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004298# endif
4299}
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004300
4301 static void
Bram Moolenaar493359e2018-06-12 20:25:52 +02004302set_default_child_environment(int is_terminal)
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004303{
Bram Moolenaar493359e2018-06-12 20:25:52 +02004304 set_child_environment(Rows, Columns, "dumb", is_terminal);
Bram Moolenaar58556cd2017-07-20 23:04:46 +02004305}
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004306#endif
4307
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004308#if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004309/*
4310 * Open a PTY, with FD for the master and slave side.
4311 * When failing "pty_master_fd" and "pty_slave_fd" are -1.
Bram Moolenaar59386482019-02-10 22:43:46 +01004312 * When successful both file descriptors are stored and the allocated pty name
4313 * is stored in both "*name1" and "*name2".
Bram Moolenaar979e8c52017-08-01 15:08:07 +02004314 */
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004315 static void
Bram Moolenaar59386482019-02-10 22:43:46 +01004316open_pty(int *pty_master_fd, int *pty_slave_fd, char_u **name1, char_u **name2)
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004317{
4318 char *tty_name;
4319
Bram Moolenaar59386482019-02-10 22:43:46 +01004320 if (name1 != NULL)
4321 *name1 = NULL;
4322 if (name2 != NULL)
4323 *name2 = NULL;
4324
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004325 *pty_master_fd = mch_openpty(&tty_name); // open pty
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004326 if (*pty_master_fd >= 0)
4327 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004328 // Leaving out O_NOCTTY may lead to waitpid() always returning
4329 // 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4330 // adding O_NOCTTY always works when defined.
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004331#ifdef O_NOCTTY
4332 *pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4333#else
4334 *pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4335#endif
4336 if (*pty_slave_fd < 0)
4337 {
4338 close(*pty_master_fd);
4339 *pty_master_fd = -1;
4340 }
Bram Moolenaar59386482019-02-10 22:43:46 +01004341 else
4342 {
4343 if (name1 != NULL)
4344 *name1 = vim_strsave((char_u *)tty_name);
4345 if (name2 != NULL)
4346 *name2 = vim_strsave((char_u *)tty_name);
4347 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02004348 }
4349}
4350#endif
4351
Bram Moolenaarfae42832017-08-01 22:24:26 +02004352/*
4353 * Send SIGINT to a child process if "c" is an interrupt character.
4354 */
Bram Moolenaar840d16f2019-09-10 21:27:18 +02004355 static void
Bram Moolenaarfae42832017-08-01 22:24:26 +02004356may_send_sigint(int c UNUSED, pid_t pid UNUSED, pid_t wpid UNUSED)
4357{
4358# ifdef SIGINT
4359 if (c == Ctrl_C || c == intr_char)
4360 {
4361# ifdef HAVE_SETSID
4362 kill(-pid, SIGINT);
4363# else
4364 kill(0, SIGINT);
4365# endif
4366 if (wpid > 0)
4367 kill(wpid, SIGINT);
4368 }
4369# endif
4370}
4371
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004372#if !defined(USE_SYSTEM) || defined(FEAT_TERMINAL) || defined(PROTO)
Bram Moolenaar13568252018-03-16 20:46:58 +01004373
Bram Moolenaar0f873732019-12-05 20:28:46 +01004374/*
4375 * Parse "cmd" and return the result in "argvp" which is an allocated array of
4376 * pointers, the last one is NULL.
4377 * The "sh_tofree" and "shcf_tofree" must be later freed by the caller.
4378 */
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004379 int
4380unix_build_argv(
Bram Moolenaar13568252018-03-16 20:46:58 +01004381 char_u *cmd,
4382 char ***argvp,
4383 char_u **sh_tofree,
4384 char_u **shcf_tofree)
4385{
4386 char **argv = NULL;
4387 int argc;
4388
4389 *sh_tofree = vim_strsave(p_sh);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004390 if (*sh_tofree == NULL) // out of memory
Bram Moolenaar13568252018-03-16 20:46:58 +01004391 return FAIL;
4392
4393 if (mch_parse_cmd(*sh_tofree, TRUE, &argv, &argc) == FAIL)
4394 return FAIL;
4395 *argvp = argv;
4396
4397 if (cmd != NULL)
4398 {
4399 char_u *s;
4400 char_u *p;
4401
4402 if (extra_shell_arg != NULL)
4403 argv[argc++] = (char *)extra_shell_arg;
4404
Bram Moolenaar0f873732019-12-05 20:28:46 +01004405 // Break 'shellcmdflag' into white separated parts. This doesn't
4406 // handle quoted strings, they are very unlikely to appear.
Bram Moolenaar964b3742019-05-24 18:54:09 +02004407 *shcf_tofree = alloc(STRLEN(p_shcf) + 1);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004408 if (*shcf_tofree == NULL) // out of memory
Bram Moolenaar13568252018-03-16 20:46:58 +01004409 return FAIL;
4410 s = *shcf_tofree;
4411 p = p_shcf;
4412 while (*p != NUL)
4413 {
4414 argv[argc++] = (char *)s;
4415 while (*p && *p != ' ' && *p != TAB)
4416 *s++ = *p++;
4417 *s++ = NUL;
4418 p = skipwhite(p);
4419 }
4420
4421 argv[argc++] = (char *)cmd;
4422 }
4423 argv[argc] = NULL;
4424 return OK;
4425}
4426#endif
4427
4428#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
4429/*
4430 * Use a terminal window to run a shell command in.
4431 */
4432 static int
4433mch_call_shell_terminal(
4434 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004435 int options UNUSED) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01004436{
4437 jobopt_T opt;
4438 char **argv = NULL;
4439 char_u *tofree1 = NULL;
4440 char_u *tofree2 = NULL;
4441 int retval = -1;
4442 buf_T *buf;
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004443 job_T *job;
Bram Moolenaar13568252018-03-16 20:46:58 +01004444 aco_save_T aco;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004445 oparg_T oa; // operator arguments
Bram Moolenaar13568252018-03-16 20:46:58 +01004446
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004447 if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar13568252018-03-16 20:46:58 +01004448 goto theend;
4449
4450 init_job_options(&opt);
4451 ch_log(NULL, "starting terminal for system command '%s'", cmd);
4452 buf = term_start(NULL, argv, &opt, TERM_START_SYSTEM);
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004453 if (buf == NULL)
4454 goto theend;
4455
4456 job = term_getjob(buf->b_term);
4457 ++job->jv_refcount;
Bram Moolenaar13568252018-03-16 20:46:58 +01004458
Bram Moolenaar0f873732019-12-05 20:28:46 +01004459 // Find a window to make "buf" curbuf.
Bram Moolenaar13568252018-03-16 20:46:58 +01004460 aucmd_prepbuf(&aco, buf);
4461
4462 clear_oparg(&oa);
4463 while (term_use_loop())
4464 {
4465 if (oa.op_type == OP_NOP && oa.regname == NUL && !VIsual_active)
4466 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004467 // If terminal_loop() returns OK we got a key that is handled
4468 // in Normal model. We don't do redrawing anyway.
Bram Moolenaar13568252018-03-16 20:46:58 +01004469 if (terminal_loop(TRUE) == OK)
4470 normal_cmd(&oa, TRUE);
4471 }
4472 else
4473 normal_cmd(&oa, TRUE);
4474 }
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004475 retval = job->jv_exitval;
Bram Moolenaar13568252018-03-16 20:46:58 +01004476 ch_log(NULL, "system command finished");
4477
Bram Moolenaarf9c38832018-06-19 19:59:20 +02004478 job_unref(job);
4479
Bram Moolenaar0f873732019-12-05 20:28:46 +01004480 // restore curwin/curbuf and a few other things
Bram Moolenaar13568252018-03-16 20:46:58 +01004481 aucmd_restbuf(&aco);
4482
4483 wait_return(TRUE);
4484 do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
4485
4486theend:
4487 vim_free(argv);
4488 vim_free(tofree1);
4489 vim_free(tofree2);
4490 return retval;
4491}
4492#endif
4493
4494#ifdef USE_SYSTEM
4495/*
4496 * Use system() to start the shell: simple but slow.
4497 */
4498 static int
4499mch_call_shell_system(
Bram Moolenaar05540972016-01-30 20:31:25 +01004500 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004501 int options) // SHELL_*, see vim.h
Bram Moolenaar071d4272004-06-13 20:20:40 +00004502{
4503#ifdef VMS
4504 char *ifn = NULL;
4505 char *ofn = NULL;
4506#endif
Bram Moolenaar26e86442020-05-17 14:06:16 +02004507 tmode_T tmode = cur_tmode;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004508 char_u *newcmd; // only needed for unix
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01004509 int x;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004510
4511 out_flush();
4512
4513 if (options & SHELL_COOKED)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004514 settmode(TMODE_COOK); // set to normal mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00004515
Bram Moolenaar62b42182010-09-21 22:09:37 +02004516# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004517 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02004518 loose_clipboard();
4519# endif
4520
Bram Moolenaar071d4272004-06-13 20:20:40 +00004521 if (cmd == NULL)
4522 x = system((char *)p_sh);
4523 else
4524 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004525# ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004526 if (ofn = strchr((char *)cmd, '>'))
4527 *ofn++ = '\0';
4528 if (ifn = strchr((char *)cmd, '<'))
4529 {
4530 char *p;
4531
4532 *ifn++ = '\0';
Bram Moolenaar0f873732019-12-05 20:28:46 +01004533 p = strchr(ifn,' '); // chop off any trailing spaces
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 if (p)
4535 *p = '\0';
4536 }
4537 if (ofn)
4538 x = vms_sys((char *)cmd, ofn, ifn);
4539 else
4540 x = system((char *)cmd);
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004541# else
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004542 newcmd = alloc(STRLEN(p_sh)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
Bram Moolenaar18a4ba22019-05-24 19:39:03 +02004544 + STRLEN(p_shcf) + STRLEN(cmd) + 4);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004545 if (newcmd == NULL)
4546 x = 0;
4547 else
4548 {
4549 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
4550 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
4551 (char *)p_shcf,
4552 (char *)cmd);
4553 x = system((char *)newcmd);
4554 vim_free(newcmd);
4555 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004556# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557 }
4558# ifdef VMS
4559 x = vms_sys_status(x);
4560# endif
4561 if (emsg_silent)
4562 ;
4563 else if (x == 127)
Bram Moolenaar32526b32019-01-19 17:43:09 +01004564 msg_puts(_("\nCannot execute shell sh\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565 else if (x && !(options & SHELL_SILENT))
4566 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004567 msg_puts(_("\nshell returned "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004568 msg_outnum((long)x);
4569 msg_putchar('\n');
4570 }
4571
4572 if (tmode == TMODE_RAW)
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004573 {
4574 // The shell may have messed with the mode, always set it.
4575 cur_tmode = TMODE_UNKNOWN;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004576 settmode(TMODE_RAW); // set to raw mode
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004577 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004578# ifdef FEAT_TITLE
4579 resettitle();
4580# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004581# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4582 restore_clipboard();
4583# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584 return x;
Bram Moolenaar13568252018-03-16 20:46:58 +01004585}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004586
Bram Moolenaar0f873732019-12-05 20:28:46 +01004587#else // USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00004588
Bram Moolenaar0f873732019-12-05 20:28:46 +01004589# define EXEC_FAILED 122 // Exit code when shell didn't execute. Don't use
4590 // 127, some shells use that already
4591# define OPEN_NULL_FAILED 123 // Exit code if /dev/null can't be opened
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592
Bram Moolenaar13568252018-03-16 20:46:58 +01004593/*
4594 * Don't use system(), use fork()/exec().
4595 */
4596 static int
4597mch_call_shell_fork(
4598 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01004599 int options) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01004600{
Bram Moolenaar26e86442020-05-17 14:06:16 +02004601 tmode_T tmode = cur_tmode;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004602 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004603 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604 pid_t wait_pid = 0;
4605# ifdef HAVE_UNION_WAIT
4606 union wait status;
4607# else
4608 int status = -1;
4609# endif
4610 int retval = -1;
4611 char **argv = NULL;
Bram Moolenaar13568252018-03-16 20:46:58 +01004612 char_u *tofree1 = NULL;
4613 char_u *tofree2 = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004614 int i;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004615 int pty_master_fd = -1; // for pty's
Bram Moolenaardf177f62005-02-22 08:39:57 +00004616# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 int pty_slave_fd = -1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004618# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01004619 int fd_toshell[2]; // for pipes
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620 int fd_fromshell[2];
4621 int pipe_error = FALSE;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004622 int did_settmode = FALSE; // settmode(TMODE_RAW) called
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623
4624 out_flush();
4625 if (options & SHELL_COOKED)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004626 settmode(TMODE_COOK); // set to normal mode
Bram Moolenaar3b1f18f2020-05-16 23:15:08 +02004627 if (tmode == TMODE_RAW)
4628 // The shell may have messed with the mode, always set it later.
4629 cur_tmode = TMODE_UNKNOWN;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004630
Bram Moolenaar197c6b72019-11-03 23:37:12 +01004631 if (unix_build_argv(cmd, &argv, &tofree1, &tofree2) == FAIL)
Bram Moolenaar835dc632016-02-07 14:27:38 +01004632 goto error;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004633
Bram Moolenaar071d4272004-06-13 20:20:40 +00004634 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004635 * For the GUI, when writing the output into the buffer and when reading
4636 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4637 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004638 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004639 if ((options & (SHELL_READ|SHELL_WRITE))
4640# ifdef FEAT_GUI
4641 || (gui.in_use && show_shell_mess)
4642# endif
4643 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004645# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004646 /*
4647 * Try to open a master pty.
4648 * If this works, open the slave pty.
4649 * If the slave can't be opened, close the master pty.
4650 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004651 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar59386482019-02-10 22:43:46 +01004652 open_pty(&pty_master_fd, &pty_slave_fd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653 /*
4654 * If not opening a pty or it didn't work, try using pipes.
4655 */
4656 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004657# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004658 {
4659 pipe_error = (pipe(fd_toshell) < 0);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004660 if (!pipe_error) // pipe create OK
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661 {
4662 pipe_error = (pipe(fd_fromshell) < 0);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004663 if (pipe_error) // pipe create failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00004664 {
4665 close(fd_toshell[0]);
4666 close(fd_toshell[1]);
4667 }
4668 }
4669 if (pipe_error)
4670 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004671 msg_puts(_("\nCannot create pipes\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004672 out_flush();
4673 }
4674 }
4675 }
4676
Bram Moolenaar0f873732019-12-05 20:28:46 +01004677 if (!pipe_error) // pty or pipe opened or not used
Bram Moolenaar071d4272004-06-13 20:20:40 +00004678 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004679 SIGSET_DECL(curset)
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004680 BLOCK_SIGNALS(&curset);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004681 pid = fork(); // maybe we should use vfork()
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004682 if (pid == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004683 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004684 UNBLOCK_SIGNALS(&curset);
4685
Bram Moolenaar32526b32019-01-19 17:43:09 +01004686 msg_puts(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004687 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004688# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004689 || (gui.in_use && show_shell_mess)
4690# endif
4691 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004692 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004693# ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01004694 if (pty_master_fd >= 0) // close the pseudo tty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004695 {
4696 close(pty_master_fd);
4697 close(pty_slave_fd);
4698 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004699 else // close the pipes
Bram Moolenaardf177f62005-02-22 08:39:57 +00004700# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004701 {
4702 close(fd_toshell[0]);
4703 close(fd_toshell[1]);
4704 close(fd_fromshell[0]);
4705 close(fd_fromshell[1]);
4706 }
4707 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004708 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004709 else if (pid == 0) // child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004710 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004711 reset_signals(); // handle signals normally
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004712 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713
Bram Moolenaar819524702018-02-27 19:10:00 +01004714# ifdef FEAT_JOB_CHANNEL
4715 if (ch_log_active())
Bram Moolenaar76603ba2020-08-30 17:24:37 +02004716 {
4717 ch_log(NULL, "closing channel log in the child process");
Bram Moolenaar819524702018-02-27 19:10:00 +01004718 ch_logfile((char_u *)"", (char_u *)"");
Bram Moolenaar76603ba2020-08-30 17:24:37 +02004719 }
Bram Moolenaar819524702018-02-27 19:10:00 +01004720# endif
4721
Bram Moolenaar071d4272004-06-13 20:20:40 +00004722 if (!show_shell_mess || (options & SHELL_EXPAND))
4723 {
4724 int fd;
4725
4726 /*
4727 * Don't want to show any message from the shell. Can't just
4728 * close stdout and stderr though, because some systems will
4729 * break if you try to write to them after that, so we must
4730 * use dup() to replace them with something else -- webb
4731 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4732 * waiting for input.
4733 */
4734 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4735 fclose(stdin);
4736 fclose(stdout);
4737 fclose(stderr);
4738
4739 /*
4740 * If any of these open()'s and dup()'s fail, we just continue
4741 * anyway. It's not fatal, and on most systems it will make
4742 * no difference at all. On a few it will cause the execvp()
4743 * to exit with a non-zero status even when the completion
4744 * could be done, which is nothing too serious. If the open()
4745 * or dup() failed we'd just do the same thing ourselves
4746 * anyway -- webb
4747 */
4748 if (fd >= 0)
4749 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004750 vim_ignored = dup(fd); // To replace stdin (fd 0)
4751 vim_ignored = dup(fd); // To replace stdout (fd 1)
4752 vim_ignored = dup(fd); // To replace stderr (fd 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004753
Bram Moolenaar0f873732019-12-05 20:28:46 +01004754 // Don't need this now that we've duplicated it
Bram Moolenaar071d4272004-06-13 20:20:40 +00004755 close(fd);
4756 }
4757 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004758 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004760 || gui.in_use
4761# endif
4762 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004763 {
4764
Bram Moolenaardf177f62005-02-22 08:39:57 +00004765# ifdef HAVE_SETSID
Bram Moolenaar0f873732019-12-05 20:28:46 +01004766 // Create our own process group, so that the child and all its
4767 // children can be kill()ed. Don't do this when using pipes,
4768 // because stdin is not a tty, we would lose /dev/tty.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004769 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004770 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004771 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004772# if defined(SIGHUP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004773 // When doing "!xterm&" and 'shell' is bash: the shell
4774 // will exit and send SIGHUP to all processes in its
4775 // group, killing the just started process. Ignore SIGHUP
4776 // to avoid that. (suggested by Simon Schubert)
Bram Moolenaar07256082009-02-04 13:19:42 +00004777 signal(SIGHUP, SIG_IGN);
4778# endif
4779 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004780# endif
4781# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004782 if (pty_slave_fd >= 0)
4783 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004784 // push stream discipline modules
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004785 if (options & SHELL_COOKED)
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01004786 setup_slavepty(pty_slave_fd);
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004787 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004788# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02004789 set_default_child_environment(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004790
Bram Moolenaara5792f52005-11-23 21:25:05 +00004791 /*
4792 * stderr is only redirected when using the GUI, so that a
4793 * program like gpg can still access the terminal to get a
4794 * passphrase using stderr.
4795 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004796# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797 if (pty_master_fd >= 0)
4798 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004799 close(pty_master_fd); // close master side of pty
Bram Moolenaar071d4272004-06-13 20:20:40 +00004800
Bram Moolenaar0f873732019-12-05 20:28:46 +01004801 // set up stdin/stdout/stderr for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004802 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004803 vim_ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004804 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004805 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004806 if (gui.in_use)
4807 {
4808 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004809 vim_ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004810 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811
Bram Moolenaar0f873732019-12-05 20:28:46 +01004812 close(pty_slave_fd); // has been dupped, close it now
Bram Moolenaar071d4272004-06-13 20:20:40 +00004813 }
4814 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004815# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004816 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004817 // set up stdin for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004818 close(fd_toshell[1]);
4819 close(0);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004820 vim_ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004821 close(fd_toshell[0]);
4822
Bram Moolenaar0f873732019-12-05 20:28:46 +01004823 // set up stdout for the child
Bram Moolenaar071d4272004-06-13 20:20:40 +00004824 close(fd_fromshell[0]);
4825 close(1);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004826 vim_ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004827 close(fd_fromshell[1]);
4828
Bram Moolenaara5792f52005-11-23 21:25:05 +00004829# ifdef FEAT_GUI
4830 if (gui.in_use)
4831 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004832 // set up stderr for the child
Bram Moolenaara5792f52005-11-23 21:25:05 +00004833 close(2);
Bram Moolenaar42335f52018-09-13 15:33:43 +02004834 vim_ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004835 }
4836# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004837 }
4838 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004839
Bram Moolenaar071d4272004-06-13 20:20:40 +00004840 /*
4841 * There is no type cast for the argv, because the type may be
4842 * different on different machines. This may cause a warning
4843 * message with strict compilers, don't worry about it.
4844 * Call _exit() instead of exit() to avoid closing the connection
4845 * to the X server (esp. with GTK, which uses atexit()).
4846 */
4847 execvp(argv[0], argv);
Bram Moolenaar0f873732019-12-05 20:28:46 +01004848 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar071d4272004-06-13 20:20:40 +00004849 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004850 else // parent
Bram Moolenaar071d4272004-06-13 20:20:40 +00004851 {
4852 /*
4853 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004854 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004855 */
4856 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004857 catch_int_signal();
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004858 UNBLOCK_SIGNALS(&curset);
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01004859# ifdef FEAT_JOB_CHANNEL
4860 ++dont_check_job_ended;
4861# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862 /*
4863 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004864 * This is also used to pipe stdin/stdout to/from the external
4865 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004866 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004867 if ((options & (SHELL_READ|SHELL_WRITE))
4868# ifdef FEAT_GUI
4869 || (gui.in_use && show_shell_mess)
4870# endif
4871 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004872 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004873# define BUFLEN 100 // length for buffer, pseudo tty limit is 128
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874 char_u buffer[BUFLEN + 1];
Bram Moolenaar0f873732019-12-05 20:28:46 +01004875 int buffer_off = 0; // valid bytes in buffer[]
4876 char_u ta_buf[BUFLEN + 1]; // TypeAHead
4877 int ta_len = 0; // valid bytes in ta_buf[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00004878 int len;
4879 int p_more_save;
4880 int old_State;
4881 int c;
4882 int toshell_fd;
4883 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004884 garray_T ga;
4885 int noread_cnt;
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01004886# ifdef ELAPSED_FUNC
4887 elapsed_T start_tv;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004888# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004889
Bram Moolenaardf177f62005-02-22 08:39:57 +00004890# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004891 if (pty_master_fd >= 0)
4892 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004893 fromshell_fd = pty_master_fd;
4894 toshell_fd = dup(pty_master_fd);
4895 }
4896 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004897# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004898 {
4899 close(fd_toshell[0]);
4900 close(fd_fromshell[1]);
4901 toshell_fd = fd_toshell[1];
4902 fromshell_fd = fd_fromshell[0];
4903 }
4904
4905 /*
4906 * Write to the child if there are typed characters.
4907 * Read from the child if there are characters available.
4908 * Repeat the reading a few times if more characters are
4909 * available. Need to check for typed keys now and then, but
4910 * not too often (delays when no chars are available).
4911 * This loop is quit if no characters can be read from the pty
4912 * (WaitForChar detected special condition), or there are no
4913 * characters available and the child has exited.
4914 * Only check if the child has exited when there is no more
4915 * output. The child may exit before all the output has
4916 * been printed.
4917 *
4918 * Currently this busy loops!
4919 * This can probably dead-lock when the write blocks!
4920 */
4921 p_more_save = p_more;
4922 p_more = FALSE;
4923 old_State = State;
Bram Moolenaar0f873732019-12-05 20:28:46 +01004924 State = EXTERNCMD; // don't redraw at window resize
Bram Moolenaar071d4272004-06-13 20:20:40 +00004925
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004926 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004927 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004928 // Fork a process that will write the lines to the
4929 // external program.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004930 if ((wpid = fork()) == -1)
4931 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004932 msg_puts(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004933 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004934 else if (wpid == 0) // child
Bram Moolenaardf177f62005-02-22 08:39:57 +00004935 {
4936 linenr_T lnum = curbuf->b_op_start.lnum;
4937 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004938 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004939 size_t l;
4940
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004941 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004942 for (;;)
4943 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004944 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004945 if (l == 0)
4946 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004947 else if (lp[written] == NL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01004948 // NL -> NUL translation
Bram Moolenaardf177f62005-02-22 08:39:57 +00004949 len = write(toshell_fd, "", (size_t)1);
4950 else
4951 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004952 char_u *s = vim_strchr(lp + written, NL);
4953
Bram Moolenaar89d40322006-08-29 15:30:07 +00004954 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004955 s == NULL ? l
4956 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004957 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004958 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004959 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004960 // Finished a line, add a NL, unless this line
4961 // should not have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004962 if (lnum != curbuf->b_op_end.lnum
Bram Moolenaar34d72d42015-07-17 14:18:08 +02004963 || (!curbuf->b_p_bin
4964 && curbuf->b_p_fixeol)
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004965 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004966 && (lnum !=
4967 curbuf->b_ml.ml_line_count
4968 || curbuf->b_p_eol)))
Bram Moolenaar42335f52018-09-13 15:33:43 +02004969 vim_ignored = write(toshell_fd, "\n",
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004970 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004971 ++lnum;
4972 if (lnum > curbuf->b_op_end.lnum)
4973 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01004974 // finished all the lines, close pipe
Bram Moolenaardf177f62005-02-22 08:39:57 +00004975 close(toshell_fd);
4976 toshell_fd = -1;
4977 break;
4978 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004979 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004980 written = 0;
4981 }
4982 else if (len > 0)
4983 written += len;
4984 }
4985 _exit(0);
4986 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01004987 else // parent
Bram Moolenaardf177f62005-02-22 08:39:57 +00004988 {
4989 close(toshell_fd);
4990 toshell_fd = -1;
4991 }
4992 }
4993
4994 if (options & SHELL_READ)
4995 ga_init2(&ga, 1, BUFLEN);
4996
4997 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01004998# ifdef ELAPSED_FUNC
4999 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005000# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005001 for (;;)
5002 {
5003 /*
5004 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005005 * if there are any.
5006 * Don't do this if we are expanding wild cards (would eat
5007 * typeahead).
5008 * Don't do this when filtering and terminal is in cooked
5009 * mode, the shell command will handle the I/O. Avoids
5010 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005011 * Don't get characters when the child has already
5012 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00005013 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005014 * while (noread_cnt > 4), avoids that ":r !ls" eats
5015 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005016 */
5017 len = 0;
5018 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005019 && ((options &
5020 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
5021 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005022# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005023 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005024# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00005025 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005026 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005027 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005028 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005029 if (ta_len == 0)
5030 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005031 // Get extra characters when we don't have any.
5032 // Reset the counter and timer.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005033 noread_cnt = 0;
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005034# ifdef ELAPSED_FUNC
5035 ELAPSED_INIT(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005036# endif
5037 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
5038 }
5039 if (ta_len > 0 || len > 0)
5040 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005041 /*
5042 * For pipes:
5043 * Check for CTRL-C: send interrupt signal to child.
5044 * Check for CTRL-D: EOF, close pipe to child.
5045 */
5046 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
5047 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005048 /*
5049 * Send SIGINT to the child's group or all
5050 * processes in our group.
5051 */
Bram Moolenaarfae42832017-08-01 22:24:26 +02005052 may_send_sigint(ta_buf[ta_len], pid, wpid);
5053
Bram Moolenaar071d4272004-06-13 20:20:40 +00005054 if (pty_master_fd < 0 && toshell_fd >= 0
5055 && ta_buf[ta_len] == Ctrl_D)
5056 {
5057 close(toshell_fd);
5058 toshell_fd = -1;
5059 }
5060 }
5061
Bram Moolenaarf4140482020-02-15 23:06:45 +01005062 term_replace_bs_del_keycode(ta_buf, ta_len, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005063
5064 /*
5065 * For pipes: echo the typed characters.
5066 * For a pty this does not seem to work.
5067 */
5068 if (pty_master_fd < 0)
5069 {
5070 for (i = ta_len; i < ta_len + len; ++i)
5071 {
5072 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
5073 msg_putchar(ta_buf[i]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005074 else if (has_mbyte)
5075 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005076 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005077
5078 msg_outtrans_len(ta_buf + i, l);
5079 i += l - 1;
5080 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005081 else
5082 msg_outtrans_len(ta_buf + i, 1);
5083 }
5084 windgoto(msg_row, msg_col);
5085 out_flush();
5086 }
5087
5088 ta_len += len;
5089
5090 /*
5091 * Write the characters to the child, unless EOF has
5092 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005093 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005094 * When writing buffer lines, drop the typed
5095 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005096 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005097 if (options & SHELL_WRITE)
5098 ta_len = 0;
5099 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005100 {
5101 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
5102 if (len > 0)
5103 {
5104 ta_len -= len;
5105 mch_memmove(ta_buf, ta_buf + len, ta_len);
5106 }
5107 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005108 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005109 }
5110
Bram Moolenaardf177f62005-02-22 08:39:57 +00005111 if (got_int)
5112 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005113 // CTRL-C sends a signal to the child, we ignore it
5114 // ourselves
Bram Moolenaardf177f62005-02-22 08:39:57 +00005115# ifdef HAVE_SETSID
5116 kill(-pid, SIGINT);
5117# else
5118 kill(0, SIGINT);
5119# endif
5120 if (wpid > 0)
5121 kill(wpid, SIGINT);
5122 got_int = FALSE;
5123 }
5124
Bram Moolenaar071d4272004-06-13 20:20:40 +00005125 /*
5126 * Check if the child has any characters to be printed.
5127 * Read them and write them to our window. Repeat this as
5128 * long as there is something to do, avoid the 10ms wait
5129 * for mch_inchar(), or sending typeahead characters to
5130 * the external process.
5131 * TODO: This should handle escape sequences, compatible
5132 * to some terminal (vt52?).
5133 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005134 ++noread_cnt;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005135 while (RealWaitForChar(fromshell_fd, 10L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005136 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01005137 len = read_eintr(fromshell_fd, buffer
Bram Moolenaar071d4272004-06-13 20:20:40 +00005138 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005139 );
Bram Moolenaar0f873732019-12-05 20:28:46 +01005140 if (len <= 0) // end of file or error
Bram Moolenaar071d4272004-06-13 20:20:40 +00005141 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005142
5143 noread_cnt = 0;
5144 if (options & SHELL_READ)
5145 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005146 // Do NUL -> NL translation, append NL separated
5147 // lines to the current buffer.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005148 for (i = 0; i < len; ++i)
5149 {
5150 if (buffer[i] == NL)
5151 append_ga_line(&ga);
5152 else if (buffer[i] == NUL)
5153 ga_append(&ga, NL);
5154 else
5155 ga_append(&ga, buffer[i]);
5156 }
5157 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005158 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005159 {
5160 int l;
Bram Moolenaara2150ac2018-03-17 13:15:17 +01005161 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005162
Bram Moolenaardf177f62005-02-22 08:39:57 +00005163 len += buffer_off;
5164 buffer[len] = NUL;
5165
Bram Moolenaar0f873732019-12-05 20:28:46 +01005166 // Check if the last character in buffer[] is
5167 // incomplete, keep these bytes for the next
5168 // round.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005169 for (p = buffer; p < buffer + len; p += l)
5170 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02005171 l = MB_CPTR2LEN(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005172 if (l == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005173 l = 1; // NUL byte?
Bram Moolenaar071d4272004-06-13 20:20:40 +00005174 else if (MB_BYTE2LEN(*p) != l)
5175 break;
5176 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01005177 if (p == buffer) // no complete character
Bram Moolenaar071d4272004-06-13 20:20:40 +00005178 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005179 // avoid getting stuck at an illegal byte
Bram Moolenaar071d4272004-06-13 20:20:40 +00005180 if (len >= 12)
5181 ++p;
5182 else
5183 {
5184 buffer_off = len;
5185 continue;
5186 }
5187 }
5188 c = *p;
5189 *p = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005190 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005191 if (p < buffer + len)
5192 {
5193 *p = c;
5194 buffer_off = (buffer + len) - p;
5195 mch_memmove(buffer, p, buffer_off);
5196 continue;
5197 }
5198 buffer_off = 0;
5199 }
5200 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005201 {
5202 buffer[len] = NUL;
Bram Moolenaar32526b32019-01-19 17:43:09 +01005203 msg_puts((char *)buffer);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005204 }
5205
5206 windgoto(msg_row, msg_col);
5207 cursor_on();
5208 out_flush();
5209 if (got_int)
5210 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005211
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005212# ifdef ELAPSED_FUNC
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005213 if (wait_pid == 0)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005214 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01005215 long msec = ELAPSED_FUNC(start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005216
Bram Moolenaar0f873732019-12-05 20:28:46 +01005217 // Avoid that we keep looping here without
5218 // checking for a CTRL-C for a long time. Don't
5219 // break out too often to avoid losing typeahead.
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00005220 if (msec > 2000)
5221 {
5222 noread_cnt = 5;
5223 break;
5224 }
5225 }
5226# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005227 }
5228
Bram Moolenaar0f873732019-12-05 20:28:46 +01005229 // If we already detected the child has finished, continue
5230 // reading output for a short while. Some text may be
5231 // buffered.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005232 if (wait_pid == pid)
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005233 {
5234 if (noread_cnt < 5)
5235 continue;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005236 break;
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02005237 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005238
Bram Moolenaar071d4272004-06-13 20:20:40 +00005239 /*
5240 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00005241 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00005242 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00005243# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02005244 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005245# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005246 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00005247# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005248 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5249 || (wait_pid == pid && WIFEXITED(status)))
5250 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005251 // Don't break the loop yet, try reading more
5252 // characters from "fromshell_fd" first. When using
5253 // pipes there might still be something to read and
5254 // then we'll break the loop at the "break" above.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005255 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005256 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00005257 else
5258 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005259
Bram Moolenaar95a51352013-03-21 22:53:50 +01005260# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005261 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005262 clip_update();
5263# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005264 }
5265finished:
5266 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005267 if (options & SHELL_READ)
5268 {
5269 if (ga.ga_len > 0)
5270 {
5271 append_ga_line(&ga);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005272 // remember that the NL was missing
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005273 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005274 }
5275 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01005276 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00005277 ga_clear(&ga);
5278 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005279
Bram Moolenaar071d4272004-06-13 20:20:40 +00005280 /*
5281 * Give all typeahead that wasn't used back to ui_inchar().
5282 */
5283 if (ta_len)
5284 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005285 State = old_State;
5286 if (toshell_fd >= 0)
5287 close(toshell_fd);
5288 close(fromshell_fd);
5289 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01005290# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005291 else
5292 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005293 long delay_msec = 1;
5294
Bram Moolenaar8a3da6a2020-12-08 19:18:37 +01005295 if (tmode == TMODE_RAW)
5296 // possibly disables modifyOtherKeys, so that the system
5297 // can recognize CTRL-C
5298 out_str(T_CTE);
Bram Moolenaar0981c872020-08-23 14:28:37 +02005299
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005300 /*
5301 * Similar to the loop above, but only handle X events, no
5302 * I/O.
5303 */
5304 for (;;)
5305 {
5306 if (got_int)
5307 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005308 // CTRL-C sends a signal to the child, we ignore it
5309 // ourselves
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005310# ifdef HAVE_SETSID
5311 kill(-pid, SIGINT);
5312# else
5313 kill(0, SIGINT);
5314# endif
5315 got_int = FALSE;
5316 }
5317# ifdef __NeXT__
5318 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
5319# else
5320 wait_pid = waitpid(pid, &status, WNOHANG);
5321# endif
5322 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5323 || (wait_pid == pid && WIFEXITED(status)))
5324 {
5325 wait_pid = pid;
5326 break;
5327 }
5328
Bram Moolenaar0f873732019-12-05 20:28:46 +01005329 // Handle any X events, e.g. serving the clipboard.
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005330 clip_update();
5331
Bram Moolenaar0f873732019-12-05 20:28:46 +01005332 // Wait for 1 to 10 msec. 1 is faster but gives the child
Bram Moolenaar0981c872020-08-23 14:28:37 +02005333 // less time, gradually wait longer.
5334 mch_delay(delay_msec,
5335 MCH_DELAY_IGNOREINPUT | MCH_DELAY_SETTMODE);
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005336 if (++delay_msec > 10)
5337 delay_msec = 10;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005338 }
Bram Moolenaar0981c872020-08-23 14:28:37 +02005339
Bram Moolenaar8a3da6a2020-12-08 19:18:37 +01005340 if (tmode == TMODE_RAW)
5341 // possibly enables modifyOtherKeys again
5342 out_str(T_CTI);
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005343 }
5344# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005345
5346 /*
5347 * Wait until our child has exited.
5348 * Ignore wait() returning pids of other children and returning
5349 * because of some signal like SIGWINCH.
5350 * Don't wait if wait_pid was already set above, indicating the
5351 * child already exited.
5352 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02005353 if (wait_pid != pid)
5354 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005355
Bram Moolenaar624891f2010-10-13 16:22:09 +02005356# ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01005357 // Close slave side of pty. Only do this after the child has
5358 // exited, otherwise the child may hang when it tries to write on
5359 // the pty.
Bram Moolenaar624891f2010-10-13 16:22:09 +02005360 if (pty_master_fd >= 0)
5361 close(pty_slave_fd);
5362# endif
5363
Bram Moolenaar0f873732019-12-05 20:28:46 +01005364 // Make sure the child that writes to the external program is
5365 // dead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00005366 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02005367 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00005368 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02005369 wait4pid(wpid, NULL);
5370 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005371
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005372# ifdef FEAT_JOB_CHANNEL
5373 --dont_check_job_ended;
5374# endif
5375
Bram Moolenaar071d4272004-06-13 20:20:40 +00005376 /*
5377 * Set to raw mode right now, otherwise a CTRL-C after
5378 * catch_signals() will kill Vim.
5379 */
5380 if (tmode == TMODE_RAW)
5381 settmode(TMODE_RAW);
5382 did_settmode = TRUE;
5383 set_signals();
5384
5385 if (WIFEXITED(status))
5386 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005387 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar071d4272004-06-13 20:20:40 +00005388 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01005389 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005390 {
5391 if (retval == EXEC_FAILED)
5392 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005393 msg_puts(_("\nCannot execute shell "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005394 msg_outtrans(p_sh);
5395 msg_putchar('\n');
5396 }
5397 else if (!(options & SHELL_SILENT))
5398 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005399 msg_puts(_("\nshell returned "));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005400 msg_outnum((long)retval);
5401 msg_putchar('\n');
5402 }
5403 }
5404 }
5405 else
Bram Moolenaar32526b32019-01-19 17:43:09 +01005406 msg_puts(_("\nCommand terminated\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407 }
5408 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005409
5410error:
5411 if (!did_settmode)
5412 if (tmode == TMODE_RAW)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005413 settmode(TMODE_RAW); // set to raw mode
Bram Moolenaar071d4272004-06-13 20:20:40 +00005414# ifdef FEAT_TITLE
5415 resettitle();
5416# endif
Bram Moolenaar13568252018-03-16 20:46:58 +01005417 vim_free(argv);
5418 vim_free(tofree1);
5419 vim_free(tofree2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005420
5421 return retval;
Bram Moolenaar13568252018-03-16 20:46:58 +01005422}
Bram Moolenaar0f873732019-12-05 20:28:46 +01005423#endif // USE_SYSTEM
Bram Moolenaar13568252018-03-16 20:46:58 +01005424
5425 int
5426mch_call_shell(
5427 char_u *cmd,
Bram Moolenaar0f873732019-12-05 20:28:46 +01005428 int options) // SHELL_*, see vim.h
Bram Moolenaar13568252018-03-16 20:46:58 +01005429{
5430#if defined(FEAT_GUI) && defined(FEAT_TERMINAL)
5431 if (gui.in_use && vim_strchr(p_go, GO_TERMINAL) != NULL)
5432 return mch_call_shell_terminal(cmd, options);
5433#endif
5434#ifdef USE_SYSTEM
5435 return mch_call_shell_system(cmd, options);
5436#else
5437 return mch_call_shell_fork(cmd, options);
5438#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005439}
5440
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005441#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005442 void
Bram Moolenaar493359e2018-06-12 20:25:52 +02005443mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005444{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005445 pid_t pid;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005446 int fd_in[2] = {-1, -1}; // for stdin
5447 int fd_out[2] = {-1, -1}; // for stdout
5448 int fd_err[2] = {-1, -1}; // for stderr
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005449 int pty_master_fd = -1;
5450 int pty_slave_fd = -1;
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01005451 channel_T *channel = NULL;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005452 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
5453 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
5454 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005455 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005456 int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
5457 int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
Bram Moolenaarb2412082017-08-20 18:09:14 +02005458 int use_buffer_for_in = options->jo_io[PART_IN] == JIO_BUFFER;
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005459 int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005460 SIGSET_DECL(curset)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005461
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005462 if (use_out_for_err && use_null_for_out)
5463 use_null_for_err = TRUE;
5464
Bram Moolenaar0f873732019-12-05 20:28:46 +01005465 // default is to fail
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005466 job->jv_status = JOB_FAILED;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005467
Bram Moolenaarb2412082017-08-20 18:09:14 +02005468 if (options->jo_pty
5469 && (!(use_file_for_in || use_null_for_in)
Bram Moolenaar59386482019-02-10 22:43:46 +01005470 || !(use_file_for_out || use_null_for_out)
Bram Moolenaarb2412082017-08-20 18:09:14 +02005471 || !(use_out_for_err || use_file_for_err || use_null_for_err)))
Bram Moolenaar59386482019-02-10 22:43:46 +01005472 open_pty(&pty_master_fd, &pty_slave_fd,
5473 &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005474
Bram Moolenaar0f873732019-12-05 20:28:46 +01005475 // TODO: without the channel feature connect the child to /dev/null?
5476 // Open pipes for stdin, stdout, stderr.
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005477 if (use_file_for_in)
5478 {
5479 char_u *fname = options->jo_io_name[PART_IN];
5480
5481 fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
5482 if (fd_in[0] < 0)
5483 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005484 semsg(_(e_notopen), fname);
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005485 goto failed;
5486 }
5487 }
Bram Moolenaarb2412082017-08-20 18:09:14 +02005488 else
Bram Moolenaar0f873732019-12-05 20:28:46 +01005489 // When writing buffer lines to the input don't use the pty, so that
5490 // the pipe can be closed when all lines were written.
Bram Moolenaarb2412082017-08-20 18:09:14 +02005491 if (!use_null_for_in && (pty_master_fd < 0 || use_buffer_for_in)
5492 && pipe(fd_in) < 0)
5493 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005494
5495 if (use_file_for_out)
5496 {
5497 char_u *fname = options->jo_io_name[PART_OUT];
5498
5499 fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
5500 if (fd_out[1] < 0)
5501 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005502 semsg(_(e_notopen), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005503 goto failed;
5504 }
5505 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005506 else if (!use_null_for_out && pty_master_fd < 0 && pipe(fd_out) < 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005507 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005508
5509 if (use_file_for_err)
5510 {
5511 char_u *fname = options->jo_io_name[PART_ERR];
5512
5513 fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
5514 if (fd_err[1] < 0)
5515 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005516 semsg(_(e_notopen), fname);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005517 goto failed;
5518 }
5519 }
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005520 else if (!use_out_for_err && !use_null_for_err
5521 && pty_master_fd < 0 && pipe(fd_err) < 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005522 goto failed;
5523
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005524 if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5525 {
Bram Moolenaarde279892016-03-11 22:19:44 +01005526 if (options->jo_set & JO_CHANNEL)
5527 {
5528 channel = options->jo_channel;
5529 if (channel != NULL)
5530 ++channel->ch_refcount;
5531 }
5532 else
5533 channel = add_channel();
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005534 if (channel == NULL)
5535 goto failed;
Bram Moolenaarf3360612017-10-01 16:21:31 +02005536 if (job->jv_tty_out != NULL)
5537 ch_log(channel, "using pty %s on fd %d",
5538 job->jv_tty_out, pty_master_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005539 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005540
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005541 BLOCK_SIGNALS(&curset);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005542 pid = fork(); // maybe we should use vfork()
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005543 if (pid == -1)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005544 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005545 // failed to fork
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005546 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005547 goto failed;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005548 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005549 if (pid == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005550 {
Bram Moolenaar4694a172016-04-21 14:05:23 +02005551 int null_fd = -1;
5552 int stderr_works = TRUE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005553
Bram Moolenaar0f873732019-12-05 20:28:46 +01005554 // child
5555 reset_signals(); // handle signals normally
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005556 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005557
Bram Moolenaar819524702018-02-27 19:10:00 +01005558# ifdef FEAT_JOB_CHANNEL
5559 if (ch_log_active())
Bram Moolenaar0f873732019-12-05 20:28:46 +01005560 // close the log file in the child
Bram Moolenaar819524702018-02-27 19:10:00 +01005561 ch_logfile((char_u *)"", (char_u *)"");
5562# endif
5563
Bram Moolenaar835dc632016-02-07 14:27:38 +01005564# ifdef HAVE_SETSID
Bram Moolenaar0f873732019-12-05 20:28:46 +01005565 // Create our own process group, so that the child and all its
5566 // children can be kill()ed. Don't do this when using pipes,
5567 // because stdin is not a tty, we would lose /dev/tty.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005568 (void)setsid();
5569# endif
5570
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005571# ifdef FEAT_TERMINAL
5572 if (options->jo_term_rows > 0)
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005573 {
5574 char *term = (char *)T_NAME;
5575
5576#ifdef FEAT_GUI
5577 if (term_is_gui(T_NAME))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005578 // In the GUI 'term' is not what we want, use $TERM.
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005579 term = getenv("TERM");
5580#endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005581 // Use 'term' or $TERM if it starts with "xterm", otherwise fall
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005582 // back to "xterm" or "xterm-color".
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005583 if (term == NULL || *term == NUL || STRNCMP(term, "xterm", 5) != 0)
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005584 {
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005585 if (t_colors >= 256)
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005586 // TODO: should we check this name is supported?
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005587 term = "xterm-256color";
Bram Moolenaar4d5d0df2020-04-14 20:56:31 +02005588 else if (t_colors > 16)
5589 term = "xterm-color";
Bram Moolenaar5ba8d352020-04-05 21:42:12 +02005590 else
5591 term = "xterm";
5592 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005593 set_child_environment(
5594 (long)options->jo_term_rows,
5595 (long)options->jo_term_cols,
Bram Moolenaar493359e2018-06-12 20:25:52 +02005596 term,
5597 is_terminal);
Bram Moolenaar9a993e32018-04-05 22:15:22 +02005598 }
Bram Moolenaar58556cd2017-07-20 23:04:46 +02005599 else
5600# endif
Bram Moolenaar493359e2018-06-12 20:25:52 +02005601 set_default_child_environment(is_terminal);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005602
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005603 if (options->jo_env != NULL)
5604 {
5605 dict_T *dict = options->jo_env;
5606 hashitem_T *hi;
5607 int todo = (int)dict->dv_hashtab.ht_used;
5608
5609 for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
5610 if (!HASHITEM_EMPTY(hi))
5611 {
5612 typval_T *item = &dict_lookup(hi)->di_tv;
5613
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005614 vim_setenv((char_u*)hi->hi_key, tv_get_string(item));
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005615 --todo;
5616 }
5617 }
5618
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005619 if (use_null_for_in || use_null_for_out || use_null_for_err)
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005620 {
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005621 null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
Bram Moolenaarb109bb42017-08-21 21:07:29 +02005622 if (null_fd < 0)
5623 {
5624 perror("opening /dev/null failed");
5625 _exit(OPEN_NULL_FAILED);
5626 }
5627 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005628
Bram Moolenaar223896d2017-08-02 22:33:28 +02005629 if (pty_slave_fd >= 0)
5630 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005631 // push stream discipline modules
Bram Moolenaar1ecc5e42019-01-26 15:12:55 +01005632 setup_slavepty(pty_slave_fd);
Bram Moolenaar223896d2017-08-02 22:33:28 +02005633# ifdef TIOCSCTTY
Bram Moolenaar0f873732019-12-05 20:28:46 +01005634 // Try to become controlling tty (probably doesn't work,
5635 // unless run by root)
Bram Moolenaar223896d2017-08-02 22:33:28 +02005636 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
5637# endif
5638 }
5639
Bram Moolenaar0f873732019-12-05 20:28:46 +01005640 // set up stdin for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005641 close(0);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005642 if (use_null_for_in && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005643 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005644 else if (fd_in[0] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005645 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005646 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005647 vim_ignored = dup(fd_in[0]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005648
Bram Moolenaar0f873732019-12-05 20:28:46 +01005649 // set up stderr for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005650 close(2);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005651 if (use_null_for_err && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005652 {
Bram Moolenaar42335f52018-09-13 15:33:43 +02005653 vim_ignored = dup(null_fd);
Bram Moolenaar4694a172016-04-21 14:05:23 +02005654 stderr_works = FALSE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005655 }
5656 else if (use_out_for_err)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005657 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005658 else if (fd_err[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005659 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005660 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005661 vim_ignored = dup(fd_err[1]);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005662
Bram Moolenaar0f873732019-12-05 20:28:46 +01005663 // set up stdout for the child
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005664 close(1);
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005665 if (use_null_for_out && null_fd >= 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005666 vim_ignored = dup(null_fd);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005667 else if (fd_out[1] < 0)
Bram Moolenaar42335f52018-09-13 15:33:43 +02005668 vim_ignored = dup(pty_slave_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005669 else
Bram Moolenaar42335f52018-09-13 15:33:43 +02005670 vim_ignored = dup(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005671
5672 if (fd_in[0] >= 0)
5673 close(fd_in[0]);
5674 if (fd_in[1] >= 0)
5675 close(fd_in[1]);
5676 if (fd_out[0] >= 0)
5677 close(fd_out[0]);
5678 if (fd_out[1] >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005679 close(fd_out[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005680 if (fd_err[0] >= 0)
5681 close(fd_err[0]);
5682 if (fd_err[1] >= 0)
5683 close(fd_err[1]);
5684 if (pty_master_fd >= 0)
5685 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005686 close(pty_master_fd); // not used in the child
5687 close(pty_slave_fd); // was duped above
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005688 }
Bram Moolenaarea83bf02016-05-08 09:40:51 +02005689
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005690 if (null_fd >= 0)
5691 close(null_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005692
Bram Moolenaar05aafed2017-08-11 19:12:11 +02005693 if (options->jo_cwd != NULL && mch_chdir((char *)options->jo_cwd) != 0)
5694 _exit(EXEC_FAILED);
5695
Bram Moolenaar0f873732019-12-05 20:28:46 +01005696 // See above for type of argv.
Bram Moolenaar835dc632016-02-07 14:27:38 +01005697 execvp(argv[0], argv);
5698
Bram Moolenaar4694a172016-04-21 14:05:23 +02005699 if (stderr_works)
5700 perror("executing job failed");
Bram Moolenaarfae42832017-08-01 22:24:26 +02005701# ifdef EXITFREE
Bram Moolenaar0f873732019-12-05 20:28:46 +01005702 // calling free_all_mem() here causes problems. Ignore valgrind
5703 // reporting possibly leaked memory.
Bram Moolenaarfae42832017-08-01 22:24:26 +02005704# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01005705 _exit(EXEC_FAILED); // exec failed, return failure code
Bram Moolenaar835dc632016-02-07 14:27:38 +01005706 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005707
Bram Moolenaar0f873732019-12-05 20:28:46 +01005708 // parent
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005709 UNBLOCK_SIGNALS(&curset);
5710
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005711 job->jv_pid = pid;
5712 job->jv_status = JOB_STARTED;
Bram Moolenaar0f873732019-12-05 20:28:46 +01005713 job->jv_channel = channel; // ch_refcount was set above
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005714
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005715 if (pty_master_fd >= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005716 close(pty_slave_fd); // not used in the parent
5717 // close child stdin, stdout and stderr
Bram Moolenaar819524702018-02-27 19:10:00 +01005718 if (fd_in[0] >= 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005719 close(fd_in[0]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005720 if (fd_out[1] >= 0)
Bram Moolenaare98d1212016-03-08 15:37:41 +01005721 close(fd_out[1]);
Bram Moolenaar819524702018-02-27 19:10:00 +01005722 if (fd_err[1] >= 0)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005723 close(fd_err[1]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005724 if (channel != NULL)
5725 {
Bram Moolenaar652de232019-04-04 20:13:09 +02005726 int in_fd = INVALID_FD;
5727 int out_fd = INVALID_FD;
5728 int err_fd = INVALID_FD;
5729
5730 if (!(use_file_for_in || use_null_for_in))
5731 in_fd = fd_in[1] >= 0 ? fd_in[1] : pty_master_fd;
5732
5733 if (!(use_file_for_out || use_null_for_out))
5734 out_fd = fd_out[0] >= 0 ? fd_out[0] : pty_master_fd;
5735
5736 // When using pty_master_fd only set it for stdout, do not duplicate
5737 // it for stderr, it only needs to be read once.
5738 if (!(use_out_for_err || use_file_for_err || use_null_for_err))
5739 {
5740 if (fd_err[0] >= 0)
5741 err_fd = fd_err[0];
5742 else if (out_fd != pty_master_fd)
5743 err_fd = pty_master_fd;
5744 }
Bram Moolenaar4e9d4432018-04-24 20:54:07 +02005745
5746 channel_set_pipes(channel, in_fd, out_fd, err_fd);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005747 channel_set_job(channel, job, options);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005748 }
Bram Moolenaar979e8c52017-08-01 15:08:07 +02005749 else
5750 {
5751 if (fd_in[1] >= 0)
5752 close(fd_in[1]);
5753 if (fd_out[0] >= 0)
5754 close(fd_out[0]);
5755 if (fd_err[0] >= 0)
5756 close(fd_err[0]);
5757 if (pty_master_fd >= 0)
5758 close(pty_master_fd);
5759 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005760
Bram Moolenaar0f873732019-12-05 20:28:46 +01005761 // success!
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005762 return;
5763
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005764failed:
Bram Moolenaarde279892016-03-11 22:19:44 +01005765 channel_unref(channel);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005766 if (fd_in[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005767 close(fd_in[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005768 if (fd_in[1] >= 0)
5769 close(fd_in[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005770 if (fd_out[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005771 close(fd_out[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005772 if (fd_out[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005773 close(fd_out[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005774 if (fd_err[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005775 close(fd_err[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005776 if (fd_err[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005777 close(fd_err[1]);
Bram Moolenaar5a1feb82017-07-22 18:04:08 +02005778 if (pty_master_fd >= 0)
5779 close(pty_master_fd);
5780 if (pty_slave_fd >= 0)
5781 close(pty_slave_fd);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005782}
5783
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005784 static char_u *
5785get_signal_name(int sig)
5786{
5787 int i;
5788 char_u numbuf[NUMBUFLEN];
5789
5790 if (sig == SIGKILL)
5791 return vim_strsave((char_u *)"kill");
5792
5793 for (i = 0; signal_info[i].sig != -1; i++)
5794 if (sig == signal_info[i].sig)
5795 return strlow_save((char_u *)signal_info[i].name);
5796
5797 vim_snprintf((char *)numbuf, NUMBUFLEN, "%d", sig);
5798 return vim_strsave(numbuf);
5799}
5800
Bram Moolenaar835dc632016-02-07 14:27:38 +01005801 char *
5802mch_job_status(job_T *job)
5803{
5804# ifdef HAVE_UNION_WAIT
5805 union wait status;
5806# else
5807 int status = -1;
5808# endif
5809 pid_t wait_pid = 0;
5810
5811# ifdef __NeXT__
5812 wait_pid = wait4(job->jv_pid, &status, WNOHANG, (struct rusage *)0);
5813# else
5814 wait_pid = waitpid(job->jv_pid, &status, WNOHANG);
5815# endif
5816 if (wait_pid == -1)
5817 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005818 // process must have exited
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005819 if (job->jv_status < JOB_ENDED)
5820 ch_log(job->jv_channel, "Job no longer exists: %s",
5821 strerror(errno));
Bram Moolenaar97792de2016-10-15 18:36:49 +02005822 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005823 }
5824 if (wait_pid == 0)
5825 return "run";
5826 if (WIFEXITED(status))
5827 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01005828 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar835dc632016-02-07 14:27:38 +01005829 job->jv_exitval = WEXITSTATUS(status);
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005830 if (job->jv_status < JOB_ENDED)
5831 ch_log(job->jv_channel, "Job exited with %d", job->jv_exitval);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005832 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005833 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005834 if (WIFSIGNALED(status))
5835 {
5836 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005837 job->jv_termsig = get_signal_name(WTERMSIG(status));
5838 if (job->jv_status < JOB_ENDED && job->jv_termsig != NULL)
5839 ch_log(job->jv_channel, "Job terminated by signal \"%s\"",
5840 job->jv_termsig);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005841 goto return_dead;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005842 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01005843 return "run";
Bram Moolenaar97792de2016-10-15 18:36:49 +02005844
5845return_dead:
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005846 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005847 job->jv_status = JOB_ENDED;
Bram Moolenaar97792de2016-10-15 18:36:49 +02005848 return "dead";
5849}
5850
5851 job_T *
5852mch_detect_ended_job(job_T *job_list)
5853{
5854# ifdef HAVE_UNION_WAIT
5855 union wait status;
5856# else
5857 int status = -1;
5858# endif
5859 pid_t wait_pid = 0;
5860 job_T *job;
5861
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005862# ifndef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01005863 // Do not do this when waiting for a shell command to finish, we would get
5864 // the exit value here (and discard it), the exit value obtained there
5865 // would then be wrong.
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005866 if (dont_check_job_ended > 0)
5867 return NULL;
5868# endif
5869
Bram Moolenaar97792de2016-10-15 18:36:49 +02005870# ifdef __NeXT__
5871 wait_pid = wait4(-1, &status, WNOHANG, (struct rusage *)0);
5872# else
5873 wait_pid = waitpid(-1, &status, WNOHANG);
5874# endif
5875 if (wait_pid <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01005876 // no process ended
Bram Moolenaar97792de2016-10-15 18:36:49 +02005877 return NULL;
5878 for (job = job_list; job != NULL; job = job->jv_next)
5879 {
5880 if (job->jv_pid == wait_pid)
5881 {
5882 if (WIFEXITED(status))
Bram Moolenaar0f873732019-12-05 20:28:46 +01005883 // LINTED avoid "bitwise operation on signed value"
Bram Moolenaar97792de2016-10-15 18:36:49 +02005884 job->jv_exitval = WEXITSTATUS(status);
5885 else if (WIFSIGNALED(status))
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005886 {
Bram Moolenaar97792de2016-10-15 18:36:49 +02005887 job->jv_exitval = -1;
Bram Moolenaarb3051ce2019-01-31 15:52:11 +01005888 job->jv_termsig = get_signal_name(WTERMSIG(status));
5889 }
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005890 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005891 {
5892 ch_log(job->jv_channel, "Job ended");
5893 job->jv_status = JOB_ENDED;
5894 }
5895 return job;
5896 }
5897 }
5898 return NULL;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005899}
5900
Bram Moolenaar3a117e12016-10-30 21:57:52 +01005901/*
5902 * Send a (deadly) signal to "job".
5903 * Return FAIL if "how" is not a valid name.
5904 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01005905 int
Bram Moolenaar2d33e902017-08-11 16:31:54 +02005906mch_signal_job(job_T *job, char_u *how)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005907{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005908 int sig = -1;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005909
Bram Moolenaar923d9262016-02-25 20:56:01 +01005910 if (*how == NUL || STRCMP(how, "term") == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005911 sig = SIGTERM;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005912 else if (STRCMP(how, "hup") == 0)
5913 sig = SIGHUP;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005914 else if (STRCMP(how, "quit") == 0)
5915 sig = SIGQUIT;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005916 else if (STRCMP(how, "int") == 0)
5917 sig = SIGINT;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005918 else if (STRCMP(how, "kill") == 0)
5919 sig = SIGKILL;
Bram Moolenaarb13501f2017-07-22 22:32:56 +02005920#ifdef SIGWINCH
5921 else if (STRCMP(how, "winch") == 0)
5922 sig = SIGWINCH;
5923#endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005924 else if (isdigit(*how))
5925 sig = atoi((char *)how);
5926 else
5927 return FAIL;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005928
Bram Moolenaar76ab4fd2018-12-08 14:39:05 +01005929 // Never kill ourselves!
5930 if (job->jv_pid != 0)
5931 {
5932 // TODO: have an option to only kill the process, not the group?
5933 kill(-job->jv_pid, sig);
5934 kill(job->jv_pid, sig);
5935 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005936
Bram Moolenaar835dc632016-02-07 14:27:38 +01005937 return OK;
5938}
Bram Moolenaar76467df2016-02-12 19:30:26 +01005939
5940/*
5941 * Clear the data related to "job".
5942 */
5943 void
5944mch_clear_job(job_T *job)
5945{
Bram Moolenaar0f873732019-12-05 20:28:46 +01005946 // call waitpid because child process may become zombie
Bram Moolenaar76467df2016-02-12 19:30:26 +01005947# ifdef __NeXT__
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005948 (void)wait4(job->jv_pid, NULL, WNOHANG, (struct rusage *)0);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005949# else
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005950 (void)waitpid(job->jv_pid, NULL, WNOHANG);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005951# endif
5952}
Bram Moolenaar835dc632016-02-07 14:27:38 +01005953#endif
5954
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005955#if defined(FEAT_TERMINAL) || defined(PROTO)
5956 int
5957mch_create_pty_channel(job_T *job, jobopt_T *options)
5958{
5959 int pty_master_fd = -1;
5960 int pty_slave_fd = -1;
5961 channel_T *channel;
5962
Bram Moolenaar59386482019-02-10 22:43:46 +01005963 open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out, &job->jv_tty_in);
Bram Moolenaard0342202020-06-29 22:40:42 +02005964 if (pty_master_fd < 0 || pty_slave_fd < 0)
5965 return FAIL;
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005966 close(pty_slave_fd);
5967
5968 channel = add_channel();
5969 if (channel == NULL)
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005970 {
5971 close(pty_master_fd);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005972 return FAIL;
Bram Moolenaar1b9f9d32017-09-05 23:32:38 +02005973 }
Bram Moolenaarf3360612017-10-01 16:21:31 +02005974 if (job->jv_tty_out != NULL)
5975 ch_log(channel, "using pty %s on fd %d",
5976 job->jv_tty_out, pty_master_fd);
Bram Moolenaar0f873732019-12-05 20:28:46 +01005977 job->jv_channel = channel; // ch_refcount was set by add_channel()
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005978 channel->ch_keep_open = TRUE;
5979
Bram Moolenaar0f873732019-12-05 20:28:46 +01005980 // Only set the pty_master_fd for stdout, do not duplicate it for stderr,
5981 // it only needs to be read once.
Bram Moolenaarb0b98d52018-05-05 21:01:00 +02005982 channel_set_pipes(channel, pty_master_fd, pty_master_fd, INVALID_FD);
Bram Moolenaar13ebb032017-08-26 22:02:51 +02005983 channel_set_job(channel, job, options);
5984 return OK;
5985}
5986#endif
5987
Bram Moolenaar071d4272004-06-13 20:20:40 +00005988/*
5989 * Check for CTRL-C typed by reading all available characters.
5990 * In cooked mode we should get SIGINT, no need to check.
5991 */
5992 void
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005993mch_breakcheck(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005994{
Bram Moolenaar26e86442020-05-17 14:06:16 +02005995 if ((mch_cur_tmode == TMODE_RAW || force)
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005996 && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005997 fill_input_buf(FALSE);
5998}
5999
6000/*
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006001 * Wait "msec" msec until a character is available from the mouse, keyboard,
6002 * from inbuf[].
6003 * "msec" == -1 will block forever.
6004 * Invokes timer callbacks when needed.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006005 * When "ignore_input" is TRUE even check for pending input when input is
6006 * already available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006007 * "interrupted" (if not NULL) is set to TRUE when no character is available
6008 * but something else needs to be done.
Bram Moolenaar40b1b542016-04-20 20:18:23 +02006009 * Returns TRUE when a character is available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006010 * When a GUI is being used, this will never get called -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00006011 */
6012 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006013WaitForChar(long msec, int *interrupted, int ignore_input)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006014{
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006015#ifdef FEAT_TIMERS
Bram Moolenaarc9e649a2017-12-18 18:14:47 +01006016 return ui_wait_for_chars_or_timer(
6017 msec, WaitForCharOrMouse, interrupted, ignore_input) == OK;
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006018#else
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006019 return WaitForCharOrMouse(msec, interrupted, ignore_input);
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006020#endif
6021}
6022
6023/*
6024 * Wait "msec" msec until a character is available from the mouse or keyboard
6025 * or from inbuf[].
6026 * "msec" == -1 will block forever.
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006027 * for "ignore_input" see WaitForCharOr().
Bram Moolenaarcda77642016-06-04 13:32:35 +02006028 * "interrupted" (if not NULL) is set to TRUE when no character is available
6029 * but something else needs to be done.
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006030 * When a GUI is being used, this will never get called -- webb
6031 */
6032 static int
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006033WaitForCharOrMouse(long msec, int *interrupted, int ignore_input)
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01006034{
Bram Moolenaar071d4272004-06-13 20:20:40 +00006035#ifdef FEAT_MOUSE_GPM
6036 int gpm_process_wanted;
6037#endif
6038#ifdef FEAT_XCLIPBOARD
6039 int rest;
6040#endif
6041 int avail;
6042
Bram Moolenaar0f873732019-12-05 20:28:46 +01006043 if (!ignore_input && input_available()) // something in inbuf[]
Bram Moolenaar071d4272004-06-13 20:20:40 +00006044 return 1;
6045
6046#if defined(FEAT_MOUSE_DEC)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006047 // May need to query the mouse position.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006048 if (WantQueryMouse)
6049 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00006050 WantQueryMouse = FALSE;
Bram Moolenaar92fd5992019-05-02 23:00:22 +02006051 if (!no_query_mouse_for_testing)
6052 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006053 }
6054#endif
6055
6056 /*
6057 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
6058 * events. This is a bit complicated, because they might both be defined.
6059 */
6060#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
6061# ifdef FEAT_XCLIPBOARD
6062 rest = 0;
6063 if (do_xterm_trace())
6064 rest = msec;
6065# endif
6066 do
6067 {
6068# ifdef FEAT_XCLIPBOARD
6069 if (rest != 0)
6070 {
6071 msec = XT_TRACE_DELAY;
6072 if (rest >= 0 && rest < XT_TRACE_DELAY)
6073 msec = rest;
6074 if (rest >= 0)
6075 rest -= msec;
6076 }
6077# endif
Bram Moolenaar28e67e02019-08-15 23:05:49 +02006078# ifdef FEAT_SOUND_CANBERRA
6079 // Invoke any pending sound callbacks.
6080 if (has_sound_callback_in_queue())
6081 invoke_sound_callback();
6082# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006083# ifdef FEAT_MOUSE_GPM
6084 gpm_process_wanted = 0;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006085 avail = RealWaitForChar(read_cmd_fd, msec,
Bram Moolenaarcda77642016-06-04 13:32:35 +02006086 &gpm_process_wanted, interrupted);
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006087 if (!avail && !gpm_process_wanted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006088# else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006089 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006090 if (!avail)
Bram Moolenaarb5432d82019-08-30 19:28:25 +02006091# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006092 {
Bram Moolenaare9c21ae2017-08-03 20:44:48 +02006093 if (!ignore_input && input_available())
Bram Moolenaar071d4272004-06-13 20:20:40 +00006094 return 1;
6095# ifdef FEAT_XCLIPBOARD
6096 if (rest == 0 || !do_xterm_trace())
6097# endif
6098 break;
6099 }
6100 }
6101 while (FALSE
6102# ifdef FEAT_MOUSE_GPM
6103 || (gpm_process_wanted && mch_gpm_process() == 0)
6104# endif
6105# ifdef FEAT_XCLIPBOARD
6106 || (!avail && rest != 0)
6107# endif
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01006108 )
6109 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006110
6111#else
Bram Moolenaarcda77642016-06-04 13:32:35 +02006112 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006113#endif
6114 return avail;
6115}
6116
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01006117#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00006118/*
6119 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006120 * "msec" == 0 will check for characters once.
6121 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006122 * When a GUI is being used, this will not be used for input -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00006123 * Or when a Linux GPM mouse event is waiting.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006124 * Or when a clientserver message is on the queue.
Bram Moolenaarcda77642016-06-04 13:32:35 +02006125 * "interrupted" (if not NULL) is set to TRUE when no character is available
6126 * but something else needs to be done.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006127 */
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006128 static int
Bram Moolenaarcda77642016-06-04 13:32:35 +02006129RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006130{
6131 int ret;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006132 int result;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006133#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006134 static int busy = FALSE;
6135
Bram Moolenaar0f873732019-12-05 20:28:46 +01006136 // May retry getting characters after an event was handled.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006137# define MAY_LOOP
6138
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006139# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006140 // Remember at what time we started, so that we know how much longer we
6141 // should wait after being interrupted.
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01006142 long start_msec = msec;
6143 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006144
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02006145 if (msec > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006146 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006147# endif
6148
Bram Moolenaar0f873732019-12-05 20:28:46 +01006149 // Handle being called recursively. This may happen for the session
6150 // manager stuff, it may save the file, which does a breakcheck.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006151 if (busy)
6152 return 0;
6153#endif
6154
6155#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00006156 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006157#endif
6158 {
6159#ifdef MAY_LOOP
Bram Moolenaar0f873732019-12-05 20:28:46 +01006160 int finished = TRUE; // default is to 'loop' just once
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006161# ifdef FEAT_MZSCHEME
6162 int mzquantum_used = FALSE;
6163# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006164#endif
6165#ifndef HAVE_SELECT
Bram Moolenaar0f873732019-12-05 20:28:46 +01006166 // each channel may use in, out and err
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006167 struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006168 int nfd;
6169# ifdef FEAT_XCLIPBOARD
6170 int xterm_idx = -1;
6171# endif
6172# ifdef FEAT_MOUSE_GPM
6173 int gpm_idx = -1;
6174# endif
6175# ifdef USE_XSMP
6176 int xsmp_idx = -1;
6177# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006178 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006179
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006180# ifdef FEAT_MZSCHEME
6181 mzvim_check_threads();
6182 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6183 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006184 towait = (int)p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006185 mzquantum_used = TRUE;
6186 }
6187# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006188 fds[0].fd = fd;
6189 fds[0].events = POLLIN;
6190 nfd = 1;
6191
Bram Moolenaar071d4272004-06-13 20:20:40 +00006192# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006193 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006194 if (xterm_Shell != (Widget)0)
6195 {
6196 xterm_idx = nfd;
6197 fds[nfd].fd = ConnectionNumber(xterm_dpy);
6198 fds[nfd].events = POLLIN;
6199 nfd++;
6200 }
6201# endif
6202# ifdef FEAT_MOUSE_GPM
6203 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6204 {
6205 gpm_idx = nfd;
6206 fds[nfd].fd = gpm_fd;
6207 fds[nfd].events = POLLIN;
6208 nfd++;
6209 }
6210# endif
6211# ifdef USE_XSMP
6212 if (xsmp_icefd != -1)
6213 {
6214 xsmp_idx = nfd;
6215 fds[nfd].fd = xsmp_icefd;
6216 fds[nfd].events = POLLIN;
6217 nfd++;
6218 }
6219# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006220#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006221 nfd = channel_poll_setup(nfd, &fds, &towait);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006222#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006223 if (interrupted != NULL)
6224 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006225
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006226 ret = poll(fds, nfd, towait);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006227
6228 result = ret > 0 && (fds[0].revents & POLLIN);
Bram Moolenaarcda77642016-06-04 13:32:35 +02006229 if (result == 0 && interrupted != NULL && ret > 0)
6230 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006231
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006232# ifdef FEAT_MZSCHEME
6233 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006234 // MzThreads scheduling is required and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006235 finished = FALSE;
6236# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006237
Bram Moolenaar071d4272004-06-13 20:20:40 +00006238# ifdef FEAT_XCLIPBOARD
6239 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
6240 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006241 xterm_update(); // Maybe we should hand out clipboard
Bram Moolenaar071d4272004-06-13 20:20:40 +00006242 if (--ret == 0 && !input_available())
Bram Moolenaar0f873732019-12-05 20:28:46 +01006243 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006244 finished = FALSE;
6245 }
6246# endif
6247# ifdef FEAT_MOUSE_GPM
6248 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006249 *check_for_gpm = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006250# endif
6251# ifdef USE_XSMP
6252 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
6253 {
6254 if (fds[xsmp_idx].revents & POLLIN)
6255 {
6256 busy = TRUE;
6257 xsmp_handle_requests();
6258 busy = FALSE;
6259 }
6260 else if (fds[xsmp_idx].revents & POLLHUP)
6261 {
6262 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006263 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006264 xsmp_close();
6265 }
6266 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006267 finished = FALSE; // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006268 }
6269# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006270#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006271 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006272 if (ret >= 0)
Bram Moolenaar2c519cf2019-03-21 21:45:34 +01006273 channel_poll_check(ret, &fds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006274#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006275
Bram Moolenaar0f873732019-12-05 20:28:46 +01006276#else // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006277
6278 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006279 struct timeval *tvp;
Bram Moolenaar61fb8d82018-11-12 21:45:08 +01006280 // These are static because they can take 8 Kbyte each and cause the
6281 // signal stack to run out with -O3.
6282 static fd_set rfds, wfds, efds;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006283 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006284 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006285
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006286# ifdef FEAT_MZSCHEME
6287 mzvim_check_threads();
6288 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
6289 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006290 towait = p_mzq; // don't wait longer than 'mzquantum'
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006291 mzquantum_used = TRUE;
6292 }
6293# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006294
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006295 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006296 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006297 tv.tv_sec = towait / 1000;
6298 tv.tv_usec = (towait % 1000) * (1000000/1000);
6299 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006300 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006301 else
6302 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006303
6304 /*
6305 * Select on ready for reading and exceptional condition (end of file).
6306 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006307select_eintr:
6308 FD_ZERO(&rfds);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006309 FD_ZERO(&wfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006310 FD_ZERO(&efds);
6311 FD_SET(fd, &rfds);
6312# if !defined(__QNX__) && !defined(__CYGWIN32__)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006313 // For QNX select() always returns 1 if this is set. Why?
Bram Moolenaar071d4272004-06-13 20:20:40 +00006314 FD_SET(fd, &efds);
6315# endif
6316 maxfd = fd;
6317
Bram Moolenaar071d4272004-06-13 20:20:40 +00006318# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01006319 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006320 if (xterm_Shell != (Widget)0)
6321 {
6322 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
6323 if (maxfd < ConnectionNumber(xterm_dpy))
6324 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006325
Bram Moolenaar0f873732019-12-05 20:28:46 +01006326 // An event may have already been read but not handled. In
6327 // particularly, XFlush may cause this.
Bram Moolenaardd82d692012-08-15 17:26:57 +02006328 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006329 }
6330# endif
6331# ifdef FEAT_MOUSE_GPM
6332 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
6333 {
6334 FD_SET(gpm_fd, &rfds);
6335 FD_SET(gpm_fd, &efds);
6336 if (maxfd < gpm_fd)
6337 maxfd = gpm_fd;
6338 }
6339# endif
6340# ifdef USE_XSMP
6341 if (xsmp_icefd != -1)
6342 {
6343 FD_SET(xsmp_icefd, &rfds);
6344 FD_SET(xsmp_icefd, &efds);
6345 if (maxfd < xsmp_icefd)
6346 maxfd = xsmp_icefd;
6347 }
6348# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006349# ifdef FEAT_JOB_CHANNEL
Bram Moolenaarf3360612017-10-01 16:21:31 +02006350 maxfd = channel_select_setup(maxfd, &rfds, &wfds, &tv, &tvp);
Bram Moolenaardd82d692012-08-15 17:26:57 +02006351# endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02006352 if (interrupted != NULL)
6353 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006354
Bram Moolenaar643b6142018-09-12 20:29:09 +02006355 ret = select(maxfd + 1, SELECT_TYPE_ARG234 &rfds,
6356 SELECT_TYPE_ARG234 &wfds, SELECT_TYPE_ARG234 &efds, tvp);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006357 result = ret > 0 && FD_ISSET(fd, &rfds);
6358 if (result)
6359 --ret;
Bram Moolenaarcda77642016-06-04 13:32:35 +02006360 else if (interrupted != NULL && ret > 0)
6361 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006362
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006363# ifdef EINTR
6364 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006365 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006366 // Check whether window has been resized, EINTR may be caused by
6367 // SIGWINCH.
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006368 if (do_resize)
6369 handle_resize();
6370
Bram Moolenaar0f873732019-12-05 20:28:46 +01006371 // Interrupted by a signal, need to try again. We ignore msec
6372 // here, because we do want to check even after a timeout if
6373 // characters are available. Needed for reading output of an
6374 // external command after the process has finished.
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006375 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02006376 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006377# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00006378# ifdef __TANDEM
6379 if (ret == -1 && errno == ENOTSUP)
6380 {
6381 FD_ZERO(&rfds);
6382 FD_ZERO(&efds);
6383 ret = 0;
6384 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02006385# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006386# ifdef FEAT_MZSCHEME
6387 if (ret == 0 && mzquantum_used)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006388 // loop if MzThreads must be scheduled and timeout occurred
Bram Moolenaar325b7a22004-07-05 15:58:32 +00006389 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006390# endif
6391
Bram Moolenaar071d4272004-06-13 20:20:40 +00006392# ifdef FEAT_XCLIPBOARD
6393 if (ret > 0 && xterm_Shell != (Widget)0
6394 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
6395 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006396 xterm_update(); // Maybe we should hand out clipboard
6397 // continue looping when we only got the X event and the input
6398 // buffer is empty
Bram Moolenaar071d4272004-06-13 20:20:40 +00006399 if (--ret == 0 && !input_available())
6400 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006401 // Try again
Bram Moolenaar071d4272004-06-13 20:20:40 +00006402 finished = FALSE;
6403 }
6404 }
6405# endif
6406# ifdef FEAT_MOUSE_GPM
6407 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
6408 {
6409 if (FD_ISSET(gpm_fd, &efds))
6410 gpm_close();
6411 else if (FD_ISSET(gpm_fd, &rfds))
6412 *check_for_gpm = 1;
6413 }
6414# endif
6415# ifdef USE_XSMP
6416 if (ret > 0 && xsmp_icefd != -1)
6417 {
6418 if (FD_ISSET(xsmp_icefd, &efds))
6419 {
6420 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01006421 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006422 xsmp_close();
6423 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006424 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006425 }
6426 else if (FD_ISSET(xsmp_icefd, &rfds))
6427 {
6428 busy = TRUE;
6429 xsmp_handle_requests();
6430 busy = FALSE;
6431 if (--ret == 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006432 finished = FALSE; // keep going if event was only one
Bram Moolenaar071d4272004-06-13 20:20:40 +00006433 }
6434 }
6435# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01006436#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar0f873732019-12-05 20:28:46 +01006437 // also call when ret == 0, we may be polling a keep-open channel
Bram Moolenaarf3360612017-10-01 16:21:31 +02006438 if (ret >= 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02006439 ret = channel_select_check(ret, &rfds, &wfds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02006440#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006441
Bram Moolenaar0f873732019-12-05 20:28:46 +01006442#endif // HAVE_SELECT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006443
6444#ifdef MAY_LOOP
6445 if (finished || msec == 0)
6446 break;
6447
Bram Moolenaar93c88e02015-09-15 14:12:05 +02006448# ifdef FEAT_CLIENTSERVER
6449 if (server_waiting())
6450 break;
6451# endif
6452
Bram Moolenaar0f873732019-12-05 20:28:46 +01006453 // We're going to loop around again, find out for how long
Bram Moolenaar071d4272004-06-13 20:20:40 +00006454 if (msec > 0)
6455 {
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006456# ifdef ELAPSED_FUNC
Bram Moolenaar0f873732019-12-05 20:28:46 +01006457 // Compute remaining wait time.
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01006458 msec = start_msec - ELAPSED_FUNC(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006459# else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006460 // Guess we got interrupted halfway.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006461 msec = msec / 2;
6462# endif
6463 if (msec <= 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006464 break; // waited long enough
Bram Moolenaar071d4272004-06-13 20:20:40 +00006465 }
6466#endif
6467 }
6468
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01006469 return result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006470}
6471
Bram Moolenaar071d4272004-06-13 20:20:40 +00006472/*
Bram Moolenaar02743632005-07-25 20:42:36 +00006473 * Expand a path into all matching files and/or directories. Handles "*",
6474 * "?", "[a-z]", "**", etc.
6475 * "path" has backslashes before chars that are not to be expanded.
6476 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006477 */
6478 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006479mch_expandpath(
6480 garray_T *gap,
6481 char_u *path,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006482 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006483{
Bram Moolenaar02743632005-07-25 20:42:36 +00006484 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006485}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006486
6487/*
6488 * mch_expand_wildcards() - this code does wild-card pattern matching using
6489 * the shell
6490 *
6491 * return OK for success, FAIL for error (you may lose some memory) and put
6492 * an error message in *file.
6493 *
6494 * num_pat is number of input patterns
6495 * pat is array of pointers to input patterns
6496 * num_file is pointer to number of matched file names
6497 * file is pointer to array of pointers to matched file names
6498 */
6499
6500#ifndef SEEK_SET
6501# define SEEK_SET 0
6502#endif
6503#ifndef SEEK_END
6504# define SEEK_END 2
6505#endif
6506
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006507#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00006508
Bram Moolenaar071d4272004-06-13 20:20:40 +00006509 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006510mch_expand_wildcards(
6511 int num_pat,
6512 char_u **pat,
6513 int *num_file,
6514 char_u ***file,
Bram Moolenaar0f873732019-12-05 20:28:46 +01006515 int flags) // EW_* flags
Bram Moolenaar071d4272004-06-13 20:20:40 +00006516{
6517 int i;
6518 size_t len;
Bram Moolenaar85325f82017-03-30 21:18:45 +02006519 long llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006520 char_u *p;
6521 int dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006522
Bram Moolenaarc7247912008-01-13 12:54:11 +00006523 /*
6524 * This is the non-OS/2 implementation (really Unix).
6525 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006526 int j;
6527 char_u *tempname;
6528 char_u *command;
6529 FILE *fd;
6530 char_u *buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006531#define STYLE_ECHO 0 // use "echo", the default
6532#define STYLE_GLOB 1 // use "glob", for csh
6533#define STYLE_VIMGLOB 2 // use "vimglob", for Posix sh
6534#define STYLE_PRINT 3 // use "print -N", for zsh
6535#define STYLE_BT 4 // `cmd` expansion, execute the pattern
6536 // directly
Bram Moolenaar071d4272004-06-13 20:20:40 +00006537 int shell_style = STYLE_ECHO;
6538 int check_spaces;
6539 static int did_find_nul = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006540 int ampersand = FALSE;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006541 // vimglob() function to define for Posix shell
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006542 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006543
Bram Moolenaar0f873732019-12-05 20:28:46 +01006544 *num_file = 0; // default: no files found
Bram Moolenaar071d4272004-06-13 20:20:40 +00006545 *file = NULL;
6546
6547 /*
6548 * If there are no wildcards, just copy the names to allocated memory.
6549 * Saves a lot of time, because we don't have to start a new shell.
6550 */
6551 if (!have_wildcard(num_pat, pat))
6552 return save_patterns(num_pat, pat, num_file, file);
6553
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006554# ifdef HAVE_SANDBOX
Bram Moolenaar0f873732019-12-05 20:28:46 +01006555 // Don't allow any shell command in the sandbox.
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006556 if (sandbox != 0 && check_secure())
6557 return FAIL;
6558# endif
6559
Bram Moolenaar071d4272004-06-13 20:20:40 +00006560 /*
6561 * Don't allow the use of backticks in secure and restricted mode.
6562 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006563 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006564 for (i = 0; i < num_pat; ++i)
6565 if (vim_strchr(pat[i], '`') != NULL
6566 && (check_restricted() || check_secure()))
6567 return FAIL;
6568
6569 /*
6570 * get a name for the temp file
6571 */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02006572 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006573 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006574 emsg(_(e_notmp));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006575 return FAIL;
6576 }
6577
6578 /*
6579 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00006580 * file.
6581 * STYLE_BT: NL separated
6582 * If expanding `cmd` execute it directly.
6583 * STYLE_GLOB: NUL separated
6584 * If we use *csh, "glob" will work better than "echo".
6585 * STYLE_PRINT: NL or NUL separated
6586 * If we use *zsh, "print -N" will work better than "glob".
6587 * STYLE_VIMGLOB: NL separated
6588 * If we use *sh*, we define "vimglob()".
6589 * STYLE_ECHO: space separated.
6590 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006591 */
6592 if (num_pat == 1 && *pat[0] == '`'
6593 && (len = STRLEN(pat[0])) > 2
6594 && *(pat[0] + len - 1) == '`')
6595 shell_style = STYLE_BT;
6596 else if ((len = STRLEN(p_sh)) >= 3)
6597 {
6598 if (STRCMP(p_sh + len - 3, "csh") == 0)
6599 shell_style = STYLE_GLOB;
6600 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
6601 shell_style = STYLE_PRINT;
6602 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006603 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
6604 "sh") != NULL)
6605 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006606
Bram Moolenaar0f873732019-12-05 20:28:46 +01006607 // Compute the length of the command. We need 2 extra bytes: for the
6608 // optional '&' and for the NUL.
6609 // Worst case: "unset nonomatch; print -N >" plus two is 29
Bram Moolenaar071d4272004-06-13 20:20:40 +00006610 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006611 if (shell_style == STYLE_VIMGLOB)
6612 len += STRLEN(sh_vimglob_func);
6613
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006614 for (i = 0; i < num_pat; ++i)
6615 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006616 // Count the length of the patterns in the same way as they are put in
6617 // "command" below.
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006618#ifdef USE_SYSTEM
Bram Moolenaar0f873732019-12-05 20:28:46 +01006619 len += STRLEN(pat[i]) + 3; // add space and two quotes
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006620#else
Bram Moolenaar0f873732019-12-05 20:28:46 +01006621 ++len; // add space
Bram Moolenaar316059c2006-01-14 21:18:42 +00006622 for (j = 0; pat[i][j] != NUL; ++j)
6623 {
6624 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006625 ++len; // may add a backslash
Bram Moolenaar316059c2006-01-14 21:18:42 +00006626 ++len;
6627 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006628#endif
6629 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006630 command = alloc(len);
6631 if (command == NULL)
6632 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006633 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006634 vim_free(tempname);
6635 return FAIL;
6636 }
6637
6638 /*
6639 * Build the shell command:
6640 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
6641 * recognizes this).
6642 * - Add the shell command to print the expanded names.
6643 * - Add the temp file name.
6644 * - Add the file name patterns.
6645 */
6646 if (shell_style == STYLE_BT)
6647 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006648 // change `command; command& ` to (command; command )
Bram Moolenaar316059c2006-01-14 21:18:42 +00006649 STRCPY(command, "(");
Bram Moolenaar0f873732019-12-05 20:28:46 +01006650 STRCAT(command, pat[0] + 1); // exclude first backtick
Bram Moolenaar071d4272004-06-13 20:20:40 +00006651 p = command + STRLEN(command) - 1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006652 *p-- = ')'; // remove last backtick
Bram Moolenaar1c465442017-03-12 20:10:05 +01006653 while (p > command && VIM_ISWHITE(*p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006654 --p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006655 if (*p == '&') // remove trailing '&'
Bram Moolenaar071d4272004-06-13 20:20:40 +00006656 {
Bram Moolenaarbdace832019-03-02 10:13:42 +01006657 ampersand = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006658 *p = ' ';
6659 }
6660 STRCAT(command, ">");
6661 }
6662 else
6663 {
6664 if (flags & EW_NOTFOUND)
6665 STRCPY(command, "set nonomatch; ");
6666 else
6667 STRCPY(command, "unset nonomatch; ");
6668 if (shell_style == STYLE_GLOB)
6669 STRCAT(command, "glob >");
6670 else if (shell_style == STYLE_PRINT)
6671 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00006672 else if (shell_style == STYLE_VIMGLOB)
6673 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006674 else
6675 STRCAT(command, "echo >");
6676 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006677
Bram Moolenaar071d4272004-06-13 20:20:40 +00006678 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00006679
Bram Moolenaar071d4272004-06-13 20:20:40 +00006680 if (shell_style != STYLE_BT)
6681 for (i = 0; i < num_pat; ++i)
6682 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006683 // When using system() always add extra quotes, because the shell
6684 // is started twice. Otherwise put a backslash before special
6685 // characters, except inside ``.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006686#ifdef USE_SYSTEM
6687 STRCAT(command, " \"");
6688 STRCAT(command, pat[i]);
6689 STRCAT(command, "\"");
6690#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00006691 int intick = FALSE;
6692
Bram Moolenaar071d4272004-06-13 20:20:40 +00006693 p = command + STRLEN(command);
6694 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00006695 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00006696 {
6697 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00006698 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006699 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
6700 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006701 // Remove a backslash, take char literally. But keep
6702 // backslash inside backticks, before a special character
6703 // and before a backtick.
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006704 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00006705 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
6706 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006707 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006708 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006709 }
Bram Moolenaare4df1642014-08-29 12:58:44 +02006710 else if (!intick
6711 && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
6712 && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006713 // Put a backslash before a special character, but not
6714 // when inside ``. And not for $var when EW_KEEPDOLLAR is
6715 // set.
Bram Moolenaar316059c2006-01-14 21:18:42 +00006716 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006717
Bram Moolenaar0f873732019-12-05 20:28:46 +01006718 // Copy one character.
Bram Moolenaar280f1262006-01-30 00:14:18 +00006719 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00006720 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006721 *p = NUL;
6722#endif
6723 }
6724 if (flags & EW_SILENT)
6725 show_shell_mess = FALSE;
Bram Moolenaarbdace832019-03-02 10:13:42 +01006726 if (ampersand)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006727 STRCAT(command, "&"); // put the '&' after the redirection
Bram Moolenaar071d4272004-06-13 20:20:40 +00006728
6729 /*
6730 * Using zsh -G: If a pattern has no matches, it is just deleted from
6731 * the argument list, otherwise zsh gives an error message and doesn't
6732 * expand any other pattern.
6733 */
6734 if (shell_style == STYLE_PRINT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006735 extra_shell_arg = (char_u *)"-G"; // Use zsh NULL_GLOB option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006736
6737 /*
6738 * If we use -f then shell variables set in .cshrc won't get expanded.
6739 * vi can do it, so we will too, but it is only necessary if there is a "$"
6740 * in one of the patterns, otherwise we can still use the fast option.
6741 */
6742 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
Bram Moolenaar0f873732019-12-05 20:28:46 +01006743 extra_shell_arg = (char_u *)"-f"; // Use csh fast option
Bram Moolenaar071d4272004-06-13 20:20:40 +00006744
6745 /*
6746 * execute the shell command
6747 */
6748 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
6749
Bram Moolenaar0f873732019-12-05 20:28:46 +01006750 // When running in the background, give it some time to create the temp
6751 // file, but don't wait for it to finish.
Bram Moolenaarbdace832019-03-02 10:13:42 +01006752 if (ampersand)
Bram Moolenaar0981c872020-08-23 14:28:37 +02006753 mch_delay(10L, MCH_DELAY_IGNOREINPUT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006754
Bram Moolenaar0f873732019-12-05 20:28:46 +01006755 extra_shell_arg = NULL; // cleanup
Bram Moolenaar071d4272004-06-13 20:20:40 +00006756 show_shell_mess = TRUE;
6757 vim_free(command);
6758
Bram Moolenaar0f873732019-12-05 20:28:46 +01006759 if (i != 0) // mch_call_shell() failed
Bram Moolenaar071d4272004-06-13 20:20:40 +00006760 {
6761 mch_remove(tempname);
6762 vim_free(tempname);
6763 /*
6764 * With interactive completion, the error message is not printed.
6765 * However with USE_SYSTEM, I don't know how to turn off error messages
6766 * from the shell, so screen may still get messed up -- webb.
6767 */
6768#ifndef USE_SYSTEM
6769 if (!(flags & EW_SILENT))
6770#endif
6771 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006772 redraw_later_clear(); // probably messed up screen
6773 msg_putchar('\n'); // clear bottom line quickly
6774 cmdline_row = Rows - 1; // continue on last line
Bram Moolenaar071d4272004-06-13 20:20:40 +00006775#ifdef USE_SYSTEM
6776 if (!(flags & EW_SILENT))
6777#endif
6778 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006779 msg(_(e_wildexpand));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006780 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006781 }
6782 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006783 // If a `cmd` expansion failed, don't list `cmd` as a match, even when
6784 // EW_NOTFOUND is given
Bram Moolenaar071d4272004-06-13 20:20:40 +00006785 if (shell_style == STYLE_BT)
6786 return FAIL;
6787 goto notfound;
6788 }
6789
6790 /*
6791 * read the names from the file into memory
6792 */
6793 fd = fopen((char *)tempname, READBIN);
6794 if (fd == NULL)
6795 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006796 // Something went wrong, perhaps a file name with a special char.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006797 if (!(flags & EW_SILENT))
6798 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006799 msg(_(e_wildexpand));
Bram Moolenaar0f873732019-12-05 20:28:46 +01006800 msg_start(); // don't overwrite this message
Bram Moolenaar071d4272004-06-13 20:20:40 +00006801 }
6802 vim_free(tempname);
6803 goto notfound;
6804 }
6805 fseek(fd, 0L, SEEK_END);
Bram Moolenaar0f873732019-12-05 20:28:46 +01006806 llen = ftell(fd); // get size of temp file
Bram Moolenaar071d4272004-06-13 20:20:40 +00006807 fseek(fd, 0L, SEEK_SET);
Bram Moolenaar85325f82017-03-30 21:18:45 +02006808 if (llen < 0)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006809 // just in case ftell() would fail
Bram Moolenaar85325f82017-03-30 21:18:45 +02006810 buffer = NULL;
6811 else
6812 buffer = alloc(llen + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006813 if (buffer == NULL)
6814 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006815 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006816 mch_remove(tempname);
6817 vim_free(tempname);
6818 fclose(fd);
6819 return FAIL;
6820 }
Bram Moolenaar85325f82017-03-30 21:18:45 +02006821 len = llen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006822 i = fread((char *)buffer, 1, len, fd);
6823 fclose(fd);
6824 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00006825 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006826 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006827 // unexpected read error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006828 semsg(_(e_notread), tempname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006829 vim_free(tempname);
6830 vim_free(buffer);
6831 return FAIL;
6832 }
6833 vim_free(tempname);
6834
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006835# ifdef __CYGWIN__
Bram Moolenaar0f873732019-12-05 20:28:46 +01006836 // Translate <CR><NL> into <NL>. Caution, buffer may contain NUL.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006837 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02006838 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006839 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
6840 *p++ = buffer[i];
6841 len = p - buffer;
6842# endif
6843
6844
Bram Moolenaar0f873732019-12-05 20:28:46 +01006845 // file names are separated with Space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006846 if (shell_style == STYLE_ECHO)
6847 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006848 buffer[len] = '\n'; // make sure the buffer ends in NL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006849 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006850 for (i = 0; *p != '\n'; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006851 {
6852 while (*p != ' ' && *p != '\n')
6853 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006854 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006855 }
6856 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006857 // file names are separated with NL
Bram Moolenaarc7247912008-01-13 12:54:11 +00006858 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006859 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006860 buffer[len] = NUL; // make sure the buffer ends in NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006861 p = buffer;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006862 for (i = 0; *p != NUL; ++i) // count number of entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006863 {
6864 while (*p != '\n' && *p != NUL)
6865 ++p;
6866 if (*p != NUL)
6867 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006868 p = skipwhite(p); // skip leading white space
Bram Moolenaar071d4272004-06-13 20:20:40 +00006869 }
6870 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006871 // file names are separated with NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006872 else
6873 {
6874 /*
6875 * Some versions of zsh use spaces instead of NULs to separate
6876 * results. Only do this when there is no NUL before the end of the
6877 * buffer, otherwise we would never be able to use file names with
6878 * embedded spaces when zsh does use NULs.
6879 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6880 * don't check for spaces again.
6881 */
6882 check_spaces = FALSE;
6883 if (shell_style == STYLE_PRINT && !did_find_nul)
6884 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006885 // If there is a NUL, set did_find_nul, else set check_spaces
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006886 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006887 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006888 did_find_nul = TRUE;
6889 else
6890 check_spaces = TRUE;
6891 }
6892
6893 /*
6894 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6895 * already is one, for STYLE_GLOB it needs to be added.
6896 */
6897 if (len && buffer[len - 1] == NUL)
6898 --len;
6899 else
6900 buffer[len] = NUL;
6901 i = 0;
6902 for (p = buffer; p < buffer + len; ++p)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006903 if (*p == NUL || (*p == ' ' && check_spaces)) // count entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006904 {
6905 ++i;
6906 *p = NUL;
6907 }
6908 if (len)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006909 ++i; // count last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006910 }
6911 if (i == 0)
6912 {
6913 /*
6914 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6915 * /bin/sh will happily expand it to nothing rather than returning an
6916 * error; and hey, it's good to check anyway -- webb.
6917 */
6918 vim_free(buffer);
6919 goto notfound;
6920 }
6921 *num_file = i;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006922 *file = ALLOC_MULT(char_u *, i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006923 if (*file == NULL)
6924 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006925 // out of memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00006926 vim_free(buffer);
6927 return FAIL;
6928 }
6929
6930 /*
6931 * Isolate the individual file names.
6932 */
6933 p = buffer;
6934 for (i = 0; i < *num_file; ++i)
6935 {
6936 (*file)[i] = p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006937 // Space or NL separates
Bram Moolenaarc7247912008-01-13 12:54:11 +00006938 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6939 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006940 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006941 while (!(shell_style == STYLE_ECHO && *p == ' ')
6942 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006943 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006944 if (p == buffer + len) // last entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006945 *p = NUL;
6946 else
6947 {
6948 *p++ = NUL;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006949 p = skipwhite(p); // skip to next entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006950 }
6951 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01006952 else // NUL separates
Bram Moolenaar071d4272004-06-13 20:20:40 +00006953 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006954 while (*p && p < buffer + len) // skip entry
Bram Moolenaar071d4272004-06-13 20:20:40 +00006955 ++p;
Bram Moolenaar0f873732019-12-05 20:28:46 +01006956 ++p; // skip NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00006957 }
6958 }
6959
6960 /*
6961 * Move the file names to allocated memory.
6962 */
6963 for (j = 0, i = 0; i < *num_file; ++i)
6964 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01006965 // Require the files to exist. Helps when using /bin/sh
Bram Moolenaar071d4272004-06-13 20:20:40 +00006966 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6967 continue;
6968
Bram Moolenaar0f873732019-12-05 20:28:46 +01006969 // check if this entry should be included
Bram Moolenaar071d4272004-06-13 20:20:40 +00006970 dir = (mch_isdir((*file)[i]));
6971 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6972 continue;
6973
Bram Moolenaar0f873732019-12-05 20:28:46 +01006974 // Skip files that are not executable if we check for that.
Bram Moolenaarb5971142015-03-21 17:32:19 +01006975 if (!dir && (flags & EW_EXEC)
6976 && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00006977 continue;
6978
Bram Moolenaar964b3742019-05-24 18:54:09 +02006979 p = alloc(STRLEN((*file)[i]) + 1 + dir);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006980 if (p)
6981 {
6982 STRCPY(p, (*file)[i]);
6983 if (dir)
Bram Moolenaar0f873732019-12-05 20:28:46 +01006984 add_pathsep(p); // add '/' to a directory name
Bram Moolenaar071d4272004-06-13 20:20:40 +00006985 (*file)[j++] = p;
6986 }
6987 }
6988 vim_free(buffer);
6989 *num_file = j;
6990
Bram Moolenaar0f873732019-12-05 20:28:46 +01006991 if (*num_file == 0) // rejected all entries
Bram Moolenaar071d4272004-06-13 20:20:40 +00006992 {
Bram Moolenaard23a8232018-02-10 18:45:26 +01006993 VIM_CLEAR(*file);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006994 goto notfound;
6995 }
6996
6997 return OK;
6998
6999notfound:
7000 if (flags & EW_NOTFOUND)
7001 return save_patterns(num_pat, pat, num_file, file);
7002 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007003}
7004
Bram Moolenaar0f873732019-12-05 20:28:46 +01007005#endif // VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00007006
Bram Moolenaar071d4272004-06-13 20:20:40 +00007007 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007008save_patterns(
7009 int num_pat,
7010 char_u **pat,
7011 int *num_file,
7012 char_u ***file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007013{
7014 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00007015 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007016
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007017 *file = ALLOC_MULT(char_u *, num_pat);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007018 if (*file == NULL)
7019 return FAIL;
7020 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00007021 {
7022 s = vim_strsave(pat[i]);
7023 if (s != NULL)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007024 // Be compatible with expand_filename(): halve the number of
7025 // backslashes.
Bram Moolenaard8b02732005-01-14 21:48:43 +00007026 backslash_halve(s);
7027 (*file)[i] = s;
7028 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007029 *num_file = num_pat;
7030 return OK;
7031}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007032
Bram Moolenaar071d4272004-06-13 20:20:40 +00007033/*
7034 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
7035 * expand.
7036 */
7037 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007038mch_has_exp_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007039{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007040 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007041 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007042 if (*p == '\\' && p[1] != NUL)
7043 ++p;
7044 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007045 if (vim_strchr((char_u *)
7046#ifdef VMS
7047 "*?%"
7048#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007049 "*?[{'"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007050#endif
7051 , *p) != NULL)
7052 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007053 }
7054 return FALSE;
7055}
7056
7057/*
7058 * Return TRUE if the string "p" contains a wildcard.
7059 * Don't recognize '~' at the end as a wildcard.
7060 */
7061 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007062mch_has_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007063{
Bram Moolenaar91acfff2017-03-12 19:22:36 +01007064 for ( ; *p; MB_PTR_ADV(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007065 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00007066 if (*p == '\\' && p[1] != NUL)
7067 ++p;
7068 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007069 if (vim_strchr((char_u *)
7070#ifdef VMS
7071 "*?%$"
7072#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00007073 "*?[{`'$"
Bram Moolenaar071d4272004-06-13 20:20:40 +00007074#endif
7075 , *p) != NULL
7076 || (*p == '~' && p[1] != NUL))
7077 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007078 }
7079 return FALSE;
7080}
7081
Bram Moolenaar071d4272004-06-13 20:20:40 +00007082 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007083have_wildcard(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007084{
7085 int i;
7086
7087 for (i = 0; i < num; i++)
7088 if (mch_has_wildcard(file[i]))
7089 return 1;
7090 return 0;
7091}
7092
7093 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007094have_dollars(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007095{
7096 int i;
7097
7098 for (i = 0; i < num; i++)
7099 if (vim_strchr(file[i], '$') != NULL)
7100 return TRUE;
7101 return FALSE;
7102}
Bram Moolenaar071d4272004-06-13 20:20:40 +00007103
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007104#if !defined(HAVE_RENAME) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007105/*
7106 * Scaled-down version of rename(), which is missing in Xenix.
7107 * This version can only move regular files and will fail if the
7108 * destination exists.
7109 */
7110 int
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01007111mch_rename(const char *src, const char *dest)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007112{
7113 struct stat st;
7114
Bram Moolenaar0f873732019-12-05 20:28:46 +01007115 if (stat(dest, &st) >= 0) // fail if destination exists
Bram Moolenaar071d4272004-06-13 20:20:40 +00007116 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007117 if (link(src, dest) != 0) // link file to new name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007118 return -1;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007119 if (mch_remove(src) == 0) // delete link to old name
Bram Moolenaar071d4272004-06-13 20:20:40 +00007120 return 0;
7121 return -1;
7122}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007123#endif // !HAVE_RENAME
Bram Moolenaar071d4272004-06-13 20:20:40 +00007124
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007125#if defined(FEAT_MOUSE_GPM) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007126/*
7127 * Initializes connection with gpm (if it isn't already opened)
7128 * Return 1 if succeeded (or connection already opened), 0 if failed
7129 */
7130 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007131gpm_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007132{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007133 static Gpm_Connect gpm_connect; // Must it be kept till closing ?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007134
7135 if (!gpm_flag)
7136 {
7137 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
7138 gpm_connect.defaultMask = ~GPM_HARD;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007139 // Default handling for mouse move
7140 gpm_connect.minMod = 0; // Handle any modifier keys
Bram Moolenaar071d4272004-06-13 20:20:40 +00007141 gpm_connect.maxMod = 0xffff;
7142 if (Gpm_Open(&gpm_connect, 0) > 0)
7143 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007144 // gpm library tries to handling TSTP causes
7145 // problems. Anyways, we close connection to Gpm whenever
7146 // we are going to suspend or starting an external process
7147 // so we shouldn't have problem with this
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007148# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007149 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00007150# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007151 return 1; // succeed
Bram Moolenaar071d4272004-06-13 20:20:40 +00007152 }
7153 if (gpm_fd == -2)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007154 Gpm_Close(); // We don't want to talk to xterm via gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007155 return 0;
7156 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007157 return 1; // already open
Bram Moolenaar071d4272004-06-13 20:20:40 +00007158}
7159
7160/*
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007161 * Returns TRUE if the GPM mouse is enabled.
7162 */
7163 int
7164gpm_enabled(void)
7165{
7166 return gpm_flag && gpm_fd >= 0;
7167}
7168
7169/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007170 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00007171 */
7172 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007173gpm_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007174{
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02007175 if (gpm_enabled())
Bram Moolenaar071d4272004-06-13 20:20:40 +00007176 Gpm_Close();
7177}
7178
Bram Moolenaarbedf0912019-05-04 16:58:45 +02007179/*
7180 * Reads gpm event and adds special keys to input buf. Returns length of
Bram Moolenaar071d4272004-06-13 20:20:40 +00007181 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02007182 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00007183 */
7184 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007185mch_gpm_process(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007186{
7187 int button;
7188 static Gpm_Event gpm_event;
7189 char_u string[6];
7190 int_u vim_modifiers;
7191 int row,col;
7192 unsigned char buttons_mask;
7193 unsigned char gpm_modifiers;
7194 static unsigned char old_buttons = 0;
7195
7196 Gpm_GetEvent(&gpm_event);
7197
7198#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007199 // Don't put events in the input queue now.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007200 if (hold_gui_events)
7201 return 0;
7202#endif
7203
7204 row = gpm_event.y - 1;
7205 col = gpm_event.x - 1;
7206
Bram Moolenaar0f873732019-12-05 20:28:46 +01007207 string[0] = ESC; // Our termcode
Bram Moolenaar071d4272004-06-13 20:20:40 +00007208 string[1] = 'M';
7209 string[2] = 'G';
7210 switch (GPM_BARE_EVENTS(gpm_event.type))
7211 {
7212 case GPM_DRAG:
7213 string[3] = MOUSE_DRAG;
7214 break;
7215 case GPM_DOWN:
7216 buttons_mask = gpm_event.buttons & ~old_buttons;
7217 old_buttons = gpm_event.buttons;
7218 switch (buttons_mask)
7219 {
7220 case GPM_B_LEFT:
7221 button = MOUSE_LEFT;
7222 break;
7223 case GPM_B_MIDDLE:
7224 button = MOUSE_MIDDLE;
7225 break;
7226 case GPM_B_RIGHT:
7227 button = MOUSE_RIGHT;
7228 break;
7229 default:
7230 return 0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007231 // Don't know what to do. Can more than one button be
7232 // reported in one event?
Bram Moolenaar071d4272004-06-13 20:20:40 +00007233 }
7234 string[3] = (char_u)(button | 0x20);
7235 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
7236 break;
7237 case GPM_UP:
7238 string[3] = MOUSE_RELEASE;
7239 old_buttons &= ~gpm_event.buttons;
7240 break;
7241 default:
7242 return 0;
7243 }
Bram Moolenaar0f873732019-12-05 20:28:46 +01007244 // This code is based on gui_x11_mouse_cb in gui_x11.c
Bram Moolenaar071d4272004-06-13 20:20:40 +00007245 gpm_modifiers = gpm_event.modifiers;
7246 vim_modifiers = 0x0;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007247 // I ignore capslock stats. Aren't we all just hate capslock mixing with
7248 // Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
7249 // K_CAPSSHIFT is defined 8, so it probably isn't even reported
Bram Moolenaar071d4272004-06-13 20:20:40 +00007250 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
7251 vim_modifiers |= MOUSE_SHIFT;
7252
7253 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
7254 vim_modifiers |= MOUSE_CTRL;
7255 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
7256 vim_modifiers |= MOUSE_ALT;
7257 string[3] |= vim_modifiers;
7258 string[4] = (char_u)(col + ' ' + 1);
7259 string[5] = (char_u)(row + ' ' + 1);
7260 add_to_input_buf(string, 6);
7261 return 6;
7262}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007263#endif // FEAT_MOUSE_GPM
Bram Moolenaar071d4272004-06-13 20:20:40 +00007264
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007265#ifdef FEAT_SYSMOUSE
7266/*
7267 * Initialize connection with sysmouse.
7268 * Let virtual console inform us with SIGUSR2 for pending sysmouse
7269 * output, any sysmouse output than will be processed via sig_sysmouse().
7270 * Return OK if succeeded, FAIL if failed.
7271 */
7272 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007273sysmouse_open(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007274{
7275 struct mouse_info mouse;
7276
7277 mouse.operation = MOUSE_MODE;
7278 mouse.u.mode.mode = 0;
7279 mouse.u.mode.signal = SIGUSR2;
7280 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
7281 {
7282 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
7283 mouse.operation = MOUSE_SHOW;
7284 ioctl(1, CONS_MOUSECTL, &mouse);
7285 return OK;
7286 }
7287 return FAIL;
7288}
7289
7290/*
7291 * Stop processing SIGUSR2 signals, and also make sure that
7292 * virtual console do not send us any sysmouse related signal.
7293 */
7294 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007295sysmouse_close(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007296{
7297 struct mouse_info mouse;
7298
7299 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
7300 mouse.operation = MOUSE_MODE;
7301 mouse.u.mode.mode = 0;
7302 mouse.u.mode.signal = 0;
7303 ioctl(1, CONS_MOUSECTL, &mouse);
7304}
7305
7306/*
7307 * Gets info from sysmouse and adds special keys to input buf.
7308 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007309 static RETSIGTYPE
7310sig_sysmouse SIGDEFARG(sigarg)
7311{
7312 struct mouse_info mouse;
7313 struct video_info video;
7314 char_u string[6];
7315 int row, col;
7316 int button;
7317 int buttons;
7318 static int oldbuttons = 0;
7319
7320#ifdef FEAT_GUI
Bram Moolenaar0f873732019-12-05 20:28:46 +01007321 // Don't put events in the input queue now.
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007322 if (hold_gui_events)
7323 return;
7324#endif
7325
7326 mouse.operation = MOUSE_GETINFO;
7327 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
7328 && ioctl(1, FBIO_MODEINFO, &video) != -1
7329 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
7330 && video.vi_cheight > 0 && video.vi_cwidth > 0)
7331 {
7332 row = mouse.u.data.y / video.vi_cheight;
7333 col = mouse.u.data.x / video.vi_cwidth;
7334 buttons = mouse.u.data.buttons;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007335 string[0] = ESC; // Our termcode
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007336 string[1] = 'M';
7337 string[2] = 'S';
7338 if (oldbuttons == buttons && buttons != 0)
7339 {
7340 button = MOUSE_DRAG;
7341 }
7342 else
7343 {
7344 switch (buttons)
7345 {
7346 case 0:
7347 button = MOUSE_RELEASE;
7348 break;
7349 case 1:
7350 button = MOUSE_LEFT;
7351 break;
7352 case 2:
7353 button = MOUSE_MIDDLE;
7354 break;
7355 case 4:
7356 button = MOUSE_RIGHT;
7357 break;
7358 default:
7359 return;
7360 }
7361 oldbuttons = buttons;
7362 }
7363 string[3] = (char_u)(button);
7364 string[4] = (char_u)(col + ' ' + 1);
7365 string[5] = (char_u)(row + ' ' + 1);
7366 add_to_input_buf(string, 6);
7367 }
7368 return;
7369}
Bram Moolenaar0f873732019-12-05 20:28:46 +01007370#endif // FEAT_SYSMOUSE
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00007371
Bram Moolenaar071d4272004-06-13 20:20:40 +00007372#if defined(FEAT_LIBCALL) || defined(PROTO)
Bram Moolenaard99df422016-01-29 23:20:40 +01007373typedef char_u * (*STRPROCSTR)(char_u *);
7374typedef char_u * (*INTPROCSTR)(int);
7375typedef int (*STRPROCINT)(char_u *);
7376typedef int (*INTPROCINT)(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007377
7378/*
7379 * Call a DLL routine which takes either a string or int param
7380 * and returns an allocated string.
7381 */
7382 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007383mch_libcall(
7384 char_u *libname,
7385 char_u *funcname,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007386 char_u *argstring, // NULL when using a argint
Bram Moolenaar05540972016-01-30 20:31:25 +01007387 int argint,
Bram Moolenaar0f873732019-12-05 20:28:46 +01007388 char_u **string_result, // NULL when using number_result
Bram Moolenaar05540972016-01-30 20:31:25 +01007389 int *number_result)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007390{
7391# if defined(USE_DLOPEN)
7392 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007393 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007394# else
7395 shl_t hinstLib;
7396# endif
7397 STRPROCSTR ProcAdd;
7398 INTPROCSTR ProcAddI;
7399 char_u *retval_str = NULL;
7400 int retval_int = 0;
7401 int success = FALSE;
7402
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007403 /*
7404 * Get a handle to the DLL module.
7405 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007406# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007407 // First clear any error, it's not cleared by the dlopen() call.
Bram Moolenaarb39ef122006-06-22 16:19:31 +00007408 (void)dlerror();
7409
Bram Moolenaar071d4272004-06-13 20:20:40 +00007410 hinstLib = dlopen((char *)libname, RTLD_LAZY
7411# ifdef RTLD_LOCAL
7412 | RTLD_LOCAL
7413# endif
7414 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007415 if (hinstLib == NULL)
7416 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007417 // "dlerr" must be used before dlclose()
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007418 dlerr = (char *)dlerror();
7419 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007420 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007421 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007422# else
7423 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
7424# endif
7425
Bram Moolenaar0f873732019-12-05 20:28:46 +01007426 // If the handle is valid, try to get the function address.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007427 if (hinstLib != NULL)
7428 {
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007429# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007430 /*
7431 * Catch a crash when calling the library function. For example when
7432 * using a number where a string pointer is expected.
7433 */
7434 mch_startjmp();
7435 if (SETJMP(lc_jump_env) != 0)
7436 {
7437 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007438# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007439 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00007440# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007441 mch_didjmp();
7442 }
7443 else
7444# endif
7445 {
7446 retval_str = NULL;
7447 retval_int = 0;
7448
7449 if (argstring != NULL)
7450 {
7451# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007452 *(void **)(&ProcAdd) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007453 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007454# else
7455 if (shl_findsym(&hinstLib, (const char *)funcname,
7456 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
7457 ProcAdd = NULL;
7458# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007459 if ((success = (ProcAdd != NULL
7460# if defined(USE_DLOPEN)
7461 && dlerr == NULL
7462# endif
7463 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007464 {
7465 if (string_result == NULL)
Bram Moolenaara4224862020-09-13 22:00:12 +02007466 retval_int = ((STRPROCINT)(void *)ProcAdd)(argstring);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007467 else
7468 retval_str = (ProcAdd)(argstring);
7469 }
7470 }
7471 else
7472 {
7473# if defined(USE_DLOPEN)
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007474 *(void **)(&ProcAddI) = dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007475 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007476# else
7477 if (shl_findsym(&hinstLib, (const char *)funcname,
7478 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
7479 ProcAddI = NULL;
7480# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007481 if ((success = (ProcAddI != NULL
7482# if defined(USE_DLOPEN)
7483 && dlerr == NULL
7484# endif
7485 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007486 {
7487 if (string_result == NULL)
Bram Moolenaara4224862020-09-13 22:00:12 +02007488 retval_int = ((INTPROCINT)(void *)ProcAddI)(argint);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007489 else
7490 retval_str = (ProcAddI)(argint);
7491 }
7492 }
7493
Bram Moolenaar0f873732019-12-05 20:28:46 +01007494 // Save the string before we free the library.
7495 // Assume that a "1" or "-1" result is an illegal pointer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007496 if (string_result == NULL)
7497 *number_result = retval_int;
7498 else if (retval_str != NULL
7499 && retval_str != (char_u *)1
7500 && retval_str != (char_u *)-1)
7501 *string_result = vim_strsave(retval_str);
7502 }
7503
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007504# ifdef USING_SETJMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00007505 mch_endjmp();
7506# ifdef SIGHASARG
7507 if (lc_signal != 0)
7508 {
7509 int i;
7510
Bram Moolenaar0f873732019-12-05 20:28:46 +01007511 // try to find the name of this signal
Bram Moolenaar071d4272004-06-13 20:20:40 +00007512 for (i = 0; signal_info[i].sig != -1; i++)
7513 if (lc_signal == signal_info[i].sig)
7514 break;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007515 semsg("E368: got SIG%s in libcall()", signal_info[i].name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007516 }
7517# endif
7518# endif
7519
Bram Moolenaar071d4272004-06-13 20:20:40 +00007520# if defined(USE_DLOPEN)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007521 // "dlerr" must be used before dlclose()
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007522 if (dlerr != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007523 semsg(_("dlerror = \"%s\""), dlerr);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007524
Bram Moolenaar0f873732019-12-05 20:28:46 +01007525 // Free the DLL module.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007526 (void)dlclose(hinstLib);
7527# else
7528 (void)shl_unload(hinstLib);
7529# endif
7530 }
7531
7532 if (!success)
7533 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007534 semsg(_(e_libcall), funcname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007535 return FAIL;
7536 }
7537
7538 return OK;
7539}
7540#endif
7541
7542#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007543static int xterm_trace = -1; // default: disabled
Bram Moolenaar071d4272004-06-13 20:20:40 +00007544static int xterm_button;
7545
7546/*
7547 * Setup a dummy window for X selections in a terminal.
7548 */
7549 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007550setup_term_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007551{
7552 int z = 0;
7553 char *strp = "";
7554 Widget AppShell;
7555
7556 if (!x_connect_to_server())
7557 return;
7558
7559 open_app_context();
7560 if (app_context != NULL && xterm_Shell == (Widget)0)
7561 {
7562 int (*oldhandler)();
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007563# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007564 int (*oldIOhandler)();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007565# endif
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007566# ifdef ELAPSED_FUNC
Bram Moolenaar1ac56c22019-01-17 22:28:22 +01007567 elapsed_T start_tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007568
7569 if (p_verbose > 0)
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007570 ELAPSED_INIT(start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007571# endif
7572
Bram Moolenaar0f873732019-12-05 20:28:46 +01007573 // Ignore X errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007574 oldhandler = XSetErrorHandler(x_error_check);
7575
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007576# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007577 // Ignore X IO errors while opening the display
Bram Moolenaar071d4272004-06-13 20:20:40 +00007578 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
7579 mch_startjmp();
7580 if (SETJMP(lc_jump_env) != 0)
7581 {
7582 mch_didjmp();
7583 xterm_dpy = NULL;
7584 }
7585 else
Bram Moolenaaredce7422019-01-20 18:39:30 +01007586# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007587 {
7588 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
7589 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007590 if (xterm_dpy != NULL)
7591 xterm_dpy_retry_count = 0;
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007592# if defined(USING_SETJMP)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007593 mch_endjmp();
Bram Moolenaaredce7422019-01-20 18:39:30 +01007594# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007595 }
7596
Bram Moolenaarb2148f52019-01-20 23:43:57 +01007597# if defined(USING_SETJMP)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007598 // Now handle X IO errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007599 (void)XSetIOErrorHandler(oldIOhandler);
Bram Moolenaaredce7422019-01-20 18:39:30 +01007600# endif
Bram Moolenaar0f873732019-12-05 20:28:46 +01007601 // Now handle X errors normally.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007602 (void)XSetErrorHandler(oldhandler);
7603
7604 if (xterm_dpy == NULL)
7605 {
7606 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01007607 verb_msg(_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007608 return;
7609 }
7610
Bram Moolenaar0f873732019-12-05 20:28:46 +01007611 // Catch terminating error of the X server connection.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007612 (void)XSetIOErrorHandler(x_IOerror_handler);
7613
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007614# ifdef ELAPSED_FUNC
Bram Moolenaar071d4272004-06-13 20:20:40 +00007615 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007616 {
7617 verbose_enter();
Bram Moolenaar833eb1d2016-11-24 17:22:50 +01007618 xopen_message(ELAPSED_FUNC(start_tv));
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007619 verbose_leave();
7620 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007621# endif
7622
Bram Moolenaar0f873732019-12-05 20:28:46 +01007623 // Create a Shell to make converters work.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007624 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
7625 applicationShellWidgetClass, xterm_dpy,
7626 NULL);
7627 if (AppShell == (Widget)0)
7628 return;
7629 xterm_Shell = XtVaCreatePopupShell("VIM",
7630 topLevelShellWidgetClass, AppShell,
7631 XtNmappedWhenManaged, 0,
7632 XtNwidth, 1,
7633 XtNheight, 1,
7634 NULL);
7635 if (xterm_Shell == (Widget)0)
7636 return;
7637
7638 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02007639 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007640 if (x11_display == NULL)
7641 x11_display = xterm_dpy;
7642
7643 XtRealizeWidget(xterm_Shell);
7644 XSync(xterm_dpy, False);
7645 xterm_update();
7646 }
7647 if (xterm_Shell != (Widget)0)
7648 {
7649 clip_init(TRUE);
7650 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
7651 x11_window = (Window)atol(strp);
Bram Moolenaar0f873732019-12-05 20:28:46 +01007652 // Check if $WINDOWID is valid.
Bram Moolenaar071d4272004-06-13 20:20:40 +00007653 if (test_x11_window(xterm_dpy) == FAIL)
7654 x11_window = 0;
7655 if (x11_window != 0)
7656 xterm_trace = 0;
7657 }
7658}
7659
7660 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007661start_xterm_trace(int button)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007662{
7663 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
7664 return;
7665 xterm_trace = 1;
7666 xterm_button = button;
7667 do_xterm_trace();
7668}
7669
7670
7671 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007672stop_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007673{
7674 if (xterm_trace < 0)
7675 return;
7676 xterm_trace = 0;
7677}
7678
7679/*
7680 * Query the xterm pointer and generate mouse termcodes if necessary
7681 * return TRUE if dragging is active, else FALSE
7682 */
7683 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007684do_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007685{
7686 Window root, child;
7687 int root_x, root_y;
7688 int win_x, win_y;
7689 int row, col;
7690 int_u mask_return;
7691 char_u buf[50];
7692 char_u *strp;
7693 long got_hints;
7694 static char_u *mouse_code;
7695 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
7696 static int prev_row = 0, prev_col = 0;
7697 static XSizeHints xterm_hints;
7698
7699 if (xterm_trace <= 0)
7700 return FALSE;
7701
7702 if (xterm_trace == 1)
7703 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007704 // Get the hints just before tracking starts. The font size might
7705 // have changed recently.
Bram Moolenaara6c2c912008-01-13 15:31:00 +00007706 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
7707 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007708 || xterm_hints.width_inc <= 1
7709 || xterm_hints.height_inc <= 1)
7710 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007711 xterm_trace = -1; // Not enough data -- disable tracing
Bram Moolenaar071d4272004-06-13 20:20:40 +00007712 return FALSE;
7713 }
7714
Bram Moolenaar0f873732019-12-05 20:28:46 +01007715 // Rely on the same mouse code for the duration of this
Bram Moolenaar071d4272004-06-13 20:20:40 +00007716 mouse_code = find_termcode(mouse_name);
7717 prev_row = mouse_row;
Bram Moolenaarcde88542015-08-11 19:14:00 +02007718 prev_col = mouse_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007719 xterm_trace = 2;
7720
Bram Moolenaar0f873732019-12-05 20:28:46 +01007721 // Find the offset of the chars, there might be a scrollbar on the
7722 // left of the window and/or a menu on the top (eterm etc.)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007723 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7724 &win_x, &win_y, &mask_return);
7725 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
7726 - (xterm_hints.height_inc / 2);
7727 if (xterm_hints.y <= xterm_hints.height_inc / 2)
7728 xterm_hints.y = 2;
7729 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
7730 - (xterm_hints.width_inc / 2);
7731 if (xterm_hints.x <= xterm_hints.width_inc / 2)
7732 xterm_hints.x = 2;
7733 return TRUE;
7734 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02007735 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007736 {
7737 xterm_trace = 0;
7738 return FALSE;
7739 }
7740
7741 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7742 &win_x, &win_y, &mask_return);
7743
7744 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
7745 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
7746 if (row == prev_row && col == prev_col)
7747 return TRUE;
7748
7749 STRCPY(buf, mouse_code);
7750 strp = buf + STRLEN(buf);
7751 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
7752 *strp++ = (char_u)(col + ' ' + 1);
7753 *strp++ = (char_u)(row + ' ' + 1);
7754 *strp = 0;
7755 add_to_input_buf(buf, STRLEN(buf));
7756
7757 prev_row = row;
7758 prev_col = col;
7759 return TRUE;
7760}
7761
Bram Moolenaard4aa83a2019-05-09 18:59:31 +02007762# if defined(FEAT_GUI) || defined(FEAT_XCLIPBOARD) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007763/*
7764 * Destroy the display, window and app_context. Required for GTK.
7765 */
7766 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007767clear_xterm_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007768{
7769 if (xterm_Shell != (Widget)0)
7770 {
7771 XtDestroyWidget(xterm_Shell);
7772 xterm_Shell = (Widget)0;
7773 }
7774 if (xterm_dpy != NULL)
7775 {
Bram Moolenaare8208012008-06-20 09:59:25 +00007776# if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01007777 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007778 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00007779# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007780 if (x11_display == xterm_dpy)
7781 x11_display = NULL;
7782 xterm_dpy = NULL;
7783 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007784# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007785 if (app_context != (XtAppContext)NULL)
7786 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007787 // Lesstif and Solaris crash here, lose some memory
Bram Moolenaar071d4272004-06-13 20:20:40 +00007788 XtDestroyApplicationContext(app_context);
7789 app_context = (XtAppContext)NULL;
7790 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007791# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007792}
7793# endif
7794
7795/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007796 * Catch up with GUI or X events.
7797 */
7798 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007799clip_update(void)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007800{
7801# ifdef FEAT_GUI
7802 if (gui.in_use)
7803 gui_mch_update();
7804 else
7805# endif
7806 if (xterm_Shell != (Widget)0)
7807 xterm_update();
7808}
7809
7810/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007811 * Catch up with any queued X events. This may put keyboard input into the
7812 * input buffer, call resize call-backs, trigger timers etc. If there is
7813 * nothing in the X event queue (& no timers pending), then we return
7814 * immediately.
7815 */
7816 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007817xterm_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007818{
7819 XEvent event;
7820
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007821 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007822 {
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007823 XtInputMask mask = XtAppPending(app_context);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007824
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007825 if (mask == 0 || vim_is_input_buf_full())
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007826 break;
7827
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007828 if (mask & XtIMXEvent)
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007829 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007830 // There is an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007831 XtAppNextEvent(app_context, &event);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007832#ifdef FEAT_CLIENTSERVER
7833 {
7834 XPropertyEvent *e = (XPropertyEvent *)&event;
7835
7836 if (e->type == PropertyNotify && e->window == commWindow
Bram Moolenaar071d4272004-06-13 20:20:40 +00007837 && e->atom == commProperty && e->state == PropertyNewValue)
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007838 serverEventProc(xterm_dpy, &event, 0);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007839 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007840#endif
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007841 XtDispatchEvent(&event);
7842 }
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007843 else
7844 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007845 // There is something else than an event to process.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007846 XtAppProcessEvent(app_context, mask);
7847 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007848 }
7849}
7850
7851 int
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007852clip_xterm_own_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007853{
7854 if (xterm_Shell != (Widget)0)
7855 return clip_x11_own_selection(xterm_Shell, cbd);
7856 return FAIL;
7857}
7858
7859 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007860clip_xterm_lose_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007861{
7862 if (xterm_Shell != (Widget)0)
7863 clip_x11_lose_selection(xterm_Shell, cbd);
7864}
7865
7866 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007867clip_xterm_request_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007868{
7869 if (xterm_Shell != (Widget)0)
7870 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7871}
7872
7873 void
Bram Moolenaar0554fa42019-06-14 21:36:54 +02007874clip_xterm_set_selection(Clipboard_T *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007875{
7876 clip_x11_set_selection(cbd);
7877}
7878#endif
7879
7880
7881#if defined(USE_XSMP) || defined(PROTO)
7882/*
7883 * Code for X Session Management Protocol.
7884 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007885
7886# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007887/*
7888 * This is our chance to ask the user if they want to save,
7889 * or abort the logout
7890 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007891 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007892xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007893{
Bram Moolenaare1004402020-10-24 20:49:43 +02007894 int save_cmod_flags;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007895 int cancel_shutdown = False;
7896
Bram Moolenaare1004402020-10-24 20:49:43 +02007897 save_cmod_flags = cmdmod.cmod_flags;
7898 cmdmod.cmod_flags |= CMOD_CONFIRM;
Bram Moolenaar027387f2016-01-02 22:25:52 +01007899 if (check_changed_any(FALSE, FALSE))
Bram Moolenaar0f873732019-12-05 20:28:46 +01007900 // Mustn't logout
Bram Moolenaar071d4272004-06-13 20:20:40 +00007901 cancel_shutdown = True;
Bram Moolenaare1004402020-10-24 20:49:43 +02007902 cmdmod.cmod_flags = save_cmod_flags;
Bram Moolenaar0f873732019-12-05 20:28:46 +01007903 setcursor(); // position cursor
Bram Moolenaar071d4272004-06-13 20:20:40 +00007904 out_flush();
7905
Bram Moolenaar0f873732019-12-05 20:28:46 +01007906 // Done interaction
Bram Moolenaar071d4272004-06-13 20:20:40 +00007907 SmcInteractDone(smc_conn, cancel_shutdown);
7908
Bram Moolenaar0f873732019-12-05 20:28:46 +01007909 // Finish off
7910 // Only end save-yourself here if we're not cancelling shutdown;
7911 // we'll get a cancelled callback later in which we'll end it.
7912 // Hopefully get around glitchy SMs (like GNOME-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007913 if (!cancel_shutdown)
7914 {
7915 xsmp.save_yourself = False;
7916 SmcSaveYourselfDone(smc_conn, True);
7917 }
7918}
7919# endif
7920
7921/*
7922 * Callback that starts save-yourself.
7923 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007924 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007925xsmp_handle_save_yourself(
7926 SmcConn smc_conn,
7927 SmPointer client_data UNUSED,
7928 int save_type UNUSED,
7929 Bool shutdown,
7930 int interact_style UNUSED,
7931 Bool fast UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007932{
Bram Moolenaar0f873732019-12-05 20:28:46 +01007933 // Handle already being in saveyourself
Bram Moolenaar071d4272004-06-13 20:20:40 +00007934 if (xsmp.save_yourself)
7935 SmcSaveYourselfDone(smc_conn, True);
7936 xsmp.save_yourself = True;
7937 xsmp.shutdown = shutdown;
7938
Bram Moolenaar0f873732019-12-05 20:28:46 +01007939 // First up, preserve all files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007940 out_flush();
Bram Moolenaar0f873732019-12-05 20:28:46 +01007941 ml_sync_all(FALSE, FALSE); // preserve all swap files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007942
7943 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01007944 verb_msg(_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007945
7946# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007947 // Now see if we can ask about unsaved files
Bram Moolenaar071d4272004-06-13 20:20:40 +00007948 if (shutdown && !fast && gui.in_use)
Bram Moolenaar0f873732019-12-05 20:28:46 +01007949 // Need to interact with user, but need SM's permission
Bram Moolenaar071d4272004-06-13 20:20:40 +00007950 SmcInteractRequest(smc_conn, SmDialogError,
7951 xsmp_handle_interaction, client_data);
7952 else
7953# endif
7954 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01007955 // Can stop the cycle here
Bram Moolenaar071d4272004-06-13 20:20:40 +00007956 SmcSaveYourselfDone(smc_conn, True);
7957 xsmp.save_yourself = False;
7958 }
7959}
7960
7961
7962/*
7963 * Callback to warn us of imminent death.
7964 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007965 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007966xsmp_die(SmcConn smc_conn UNUSED, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007967{
7968 xsmp_close();
7969
Bram Moolenaar0f873732019-12-05 20:28:46 +01007970 // quit quickly leaving swapfiles for modified buffers behind
Bram Moolenaar071d4272004-06-13 20:20:40 +00007971 getout_preserve_modified(0);
7972}
7973
7974
7975/*
7976 * Callback to tell us that save-yourself has completed.
7977 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007978 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007979xsmp_save_complete(
7980 SmcConn smc_conn UNUSED,
7981 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007982{
7983 xsmp.save_yourself = False;
7984}
7985
7986
7987/*
7988 * Callback to tell us that an instigated shutdown was cancelled
7989 * (maybe even by us)
7990 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007991 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007992xsmp_shutdown_cancelled(
7993 SmcConn smc_conn,
7994 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007995{
7996 if (xsmp.save_yourself)
7997 SmcSaveYourselfDone(smc_conn, True);
7998 xsmp.save_yourself = False;
7999 xsmp.shutdown = False;
8000}
8001
8002
8003/*
8004 * Callback to tell us that a new ICE connection has been established.
8005 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00008006 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01008007xsmp_ice_connection(
8008 IceConn iceConn,
8009 IcePointer clientData UNUSED,
8010 Bool opening,
8011 IcePointer *watchData UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008012{
Bram Moolenaar0f873732019-12-05 20:28:46 +01008013 // Intercept creation of ICE connection fd
Bram Moolenaar071d4272004-06-13 20:20:40 +00008014 if (opening)
8015 {
8016 xsmp_icefd = IceConnectionNumber(iceConn);
8017 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
8018 }
8019}
8020
8021
Bram Moolenaar0f873732019-12-05 20:28:46 +01008022// Handle any ICE processing that's required; return FAIL if SM lost
Bram Moolenaar071d4272004-06-13 20:20:40 +00008023 int
Bram Moolenaar05540972016-01-30 20:31:25 +01008024xsmp_handle_requests(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008025{
8026 Bool rep;
8027
8028 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
8029 == IceProcessMessagesIOError)
8030 {
Bram Moolenaar0f873732019-12-05 20:28:46 +01008031 // Lost ICE
Bram Moolenaar071d4272004-06-13 20:20:40 +00008032 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008033 verb_msg(_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008034 xsmp_close();
8035 return FAIL;
8036 }
8037 else
8038 return OK;
8039}
8040
8041static int dummy;
8042
Bram Moolenaar0f873732019-12-05 20:28:46 +01008043// Set up X Session Management Protocol
Bram Moolenaar071d4272004-06-13 20:20:40 +00008044 void
8045xsmp_init(void)
8046{
8047 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00008048 SmcCallbacks smcallbacks;
8049#if 0
8050 SmPropValue smname;
8051 SmProp smnameprop;
8052 SmProp *smprops[1];
8053#endif
8054
8055 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008056 verb_msg(_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008057
8058 xsmp.save_yourself = xsmp.shutdown = False;
8059
Bram Moolenaar0f873732019-12-05 20:28:46 +01008060 // Set up SM callbacks - must have all, even if they're not used
Bram Moolenaar071d4272004-06-13 20:20:40 +00008061 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
8062 smcallbacks.save_yourself.client_data = NULL;
8063 smcallbacks.die.callback = xsmp_die;
8064 smcallbacks.die.client_data = NULL;
8065 smcallbacks.save_complete.callback = xsmp_save_complete;
8066 smcallbacks.save_complete.client_data = NULL;
8067 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
8068 smcallbacks.shutdown_cancelled.client_data = NULL;
8069
Bram Moolenaar0f873732019-12-05 20:28:46 +01008070 // Set up a watch on ICE connection creations. The "dummy" argument is
8071 // apparently required for FreeBSD (we get a BUS error when using NULL).
Bram Moolenaar071d4272004-06-13 20:20:40 +00008072 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
8073 {
8074 if (p_verbose > 0)
Bram Moolenaar32526b32019-01-19 17:43:09 +01008075 verb_msg(_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00008076 return;
8077 }
8078
Bram Moolenaar0f873732019-12-05 20:28:46 +01008079 // Create an SM connection
Bram Moolenaar071d4272004-06-13 20:20:40 +00008080 xsmp.smcconn = SmcOpenConnection(
8081 NULL,
8082 NULL,
8083 SmProtoMajor,
8084 SmProtoMinor,
8085 SmcSaveYourselfProcMask | SmcDieProcMask
8086 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
8087 &smcallbacks,
8088 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00008089 &xsmp.clientid,
Bram Moolenaar4841a7c2018-09-22 14:08:49 +02008090 sizeof(errorstring) - 1,
Bram Moolenaar071d4272004-06-13 20:20:40 +00008091 errorstring);
8092 if (xsmp.smcconn == NULL)
8093 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00008094 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008095 {
Bram Moolenaare1be1182020-10-24 13:30:51 +02008096 char errorreport[132];
8097
8098 // If the message is too long it might not be NUL terminated. Add
8099 // a NUL at the end to make sure we don't go over the end.
8100 errorstring[sizeof(errorstring) - 1] = NUL;
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008101 vim_snprintf(errorreport, sizeof(errorreport),
8102 _("XSMP SmcOpenConnection failed: %s"), errorstring);
Bram Moolenaar32526b32019-01-19 17:43:09 +01008103 verb_msg(errorreport);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00008104 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00008105 return;
8106 }
8107 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
8108
8109#if 0
Bram Moolenaar0f873732019-12-05 20:28:46 +01008110 // ID ourselves
Bram Moolenaar071d4272004-06-13 20:20:40 +00008111 smname.value = "vim";
8112 smname.length = 3;
8113 smnameprop.name = "SmProgram";
8114 smnameprop.type = "SmARRAY8";
8115 smnameprop.num_vals = 1;
8116 smnameprop.vals = &smname;
8117
8118 smprops[0] = &smnameprop;
8119 SmcSetProperties(xsmp.smcconn, 1, smprops);
8120#endif
8121}
8122
8123
Bram Moolenaar0f873732019-12-05 20:28:46 +01008124// Shut down XSMP comms.
Bram Moolenaar071d4272004-06-13 20:20:40 +00008125 void
Bram Moolenaar05540972016-01-30 20:31:25 +01008126xsmp_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00008127{
8128 if (xsmp_icefd != -1)
8129 {
8130 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00008131 if (xsmp.clientid != NULL)
8132 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00008133 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00008134 xsmp_icefd = -1;
8135 }
8136}
Bram Moolenaar0f873732019-12-05 20:28:46 +01008137#endif // USE_XSMP
Bram Moolenaar071d4272004-06-13 20:20:40 +00008138
8139
8140#ifdef EBCDIC
Bram Moolenaar0f873732019-12-05 20:28:46 +01008141// Translate character to its CTRL- value
Bram Moolenaar071d4272004-06-13 20:20:40 +00008142char CtrlTable[] =
8143{
8144/* 00 - 5E */
8145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8146 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8147 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8148 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8151/* ^ */ 0x1E,
8152/* - */ 0x1F,
8153/* 61 - 6C */
8154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8155/* _ */ 0x1F,
8156/* 6E - 80 */
8157 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8158/* a */ 0x01,
8159/* b */ 0x02,
8160/* c */ 0x03,
8161/* d */ 0x37,
8162/* e */ 0x2D,
8163/* f */ 0x2E,
8164/* g */ 0x2F,
8165/* h */ 0x16,
8166/* i */ 0x05,
8167/* 8A - 90 */
8168 0, 0, 0, 0, 0, 0, 0,
8169/* j */ 0x15,
8170/* k */ 0x0B,
8171/* l */ 0x0C,
8172/* m */ 0x0D,
8173/* n */ 0x0E,
8174/* o */ 0x0F,
8175/* p */ 0x10,
8176/* q */ 0x11,
8177/* r */ 0x12,
8178/* 9A - A1 */
8179 0, 0, 0, 0, 0, 0, 0, 0,
8180/* s */ 0x13,
8181/* t */ 0x3C,
8182/* u */ 0x3D,
8183/* v */ 0x32,
8184/* w */ 0x26,
8185/* x */ 0x18,
8186/* y */ 0x19,
8187/* z */ 0x3F,
8188/* AA - AC */
8189 0, 0, 0,
8190/* [ */ 0x27,
8191/* AE - BC */
8192 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8193/* ] */ 0x1D,
8194/* BE - C0 */ 0, 0, 0,
8195/* A */ 0x01,
8196/* B */ 0x02,
8197/* C */ 0x03,
8198/* D */ 0x37,
8199/* E */ 0x2D,
8200/* F */ 0x2E,
8201/* G */ 0x2F,
8202/* H */ 0x16,
8203/* I */ 0x05,
8204/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
8205/* J */ 0x15,
8206/* K */ 0x0B,
8207/* L */ 0x0C,
8208/* M */ 0x0D,
8209/* N */ 0x0E,
8210/* O */ 0x0F,
8211/* P */ 0x10,
8212/* Q */ 0x11,
8213/* R */ 0x12,
8214/* DA - DF */ 0, 0, 0, 0, 0, 0,
8215/* \ */ 0x1C,
8216/* E1 */ 0,
8217/* S */ 0x13,
8218/* T */ 0x3C,
8219/* U */ 0x3D,
8220/* V */ 0x32,
8221/* W */ 0x26,
8222/* X */ 0x18,
8223/* Y */ 0x19,
8224/* Z */ 0x3F,
8225/* EA - FF*/ 0, 0, 0, 0, 0, 0,
8226 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8227};
8228
8229char MetaCharTable[]=
Bram Moolenaar0f873732019-12-05 20:28:46 +01008230{// 0 1 2 3 4 5 6 7 8 9 A B C D E F
Bram Moolenaar071d4272004-06-13 20:20:40 +00008231 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
8232 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
8233 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
8234 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
8235};
8236
8237
Bram Moolenaar0f873732019-12-05 20:28:46 +01008238// TODO: Use characters NOT numbers!!!
Bram Moolenaar071d4272004-06-13 20:20:40 +00008239char CtrlCharTable[]=
Bram Moolenaar0f873732019-12-05 20:28:46 +01008240{// 0 1 2 3 4 5 6 7 8 9 A B C D E F
Bram Moolenaar071d4272004-06-13 20:20:40 +00008241 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
8242 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
8243 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
8244 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
8245};
8246
8247
8248#endif