blob: a63eb6e89196e8b22798c8d4a0958abc8e8c8e99 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * OS/2 port by Paul Slootman
5 * VMS merge by Zoltan Arpadffy
6 *
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 * See README.txt for an overview of the Vim source code.
10 */
11
12/*
13 * os_unix.c -- code for all flavors of Unix (BSD, SYSV, SVR4, POSIX, ...)
14 * Also for OS/2, using the excellent EMX package!!!
15 * Also for BeOS and Atari MiNT.
16 *
17 * A lot of this file was originally written by Juergen Weigert and later
18 * changed beyond recognition.
19 */
20
21/*
22 * Some systems have a prototype for select() that has (int *) instead of
23 * (fd_set *), which is wrong. This define removes that prototype. We define
24 * our own prototype below.
25 * Don't use it for the Mac, it causes a warning for precompiled headers.
26 * TODO: use a configure check for precompiled headers?
27 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000028#if !defined(__APPLE__) && !defined(__TANDEM)
Bram Moolenaar071d4272004-06-13 20:20:40 +000029# define select select_declared_wrong
30#endif
31
32#include "vim.h"
33
Bram Moolenaar325b7a22004-07-05 15:58:32 +000034#ifdef FEAT_MZSCHEME
35# include "if_mzsch.h"
36#endif
37
Bram Moolenaar071d4272004-06-13 20:20:40 +000038#include "os_unixx.h" /* unix includes for os_unix.c only */
39
40#ifdef USE_XSMP
41# include <X11/SM/SMlib.h>
42#endif
43
Bram Moolenaar588ebeb2008-05-07 17:09:24 +000044#ifdef HAVE_SELINUX
45# include <selinux/selinux.h>
46static int selinux_enabled = -1;
47#endif
48
Bram Moolenaar5bd32f42014-04-02 14:05:38 +020049#ifdef HAVE_SMACK
50# include <attr/xattr.h>
51# include <linux/xattr.h>
52# ifndef SMACK_LABEL_LEN
53# define SMACK_LABEL_LEN 1024
54# endif
55#endif
56
Bram Moolenaar071d4272004-06-13 20:20:40 +000057/*
58 * Use this prototype for select, some include files have a wrong prototype
59 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000060#ifndef __TANDEM
61# undef select
62# ifdef __BEOS__
63# define select beos_select
64# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000065#endif
66
Bram Moolenaara2442432007-04-26 14:26:37 +000067#ifdef __CYGWIN__
68# ifndef WIN32
Bram Moolenaar0d1498e2008-06-29 12:00:49 +000069# include <cygwin/version.h>
70# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() and/or
71 * for cygwin_conv_path() */
Bram Moolenaar693e40c2013-02-26 14:56:42 +010072# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
73# define WIN32_LEAN_AND_MEAN
74# include <windows.h>
75# include "winclip.pro"
76# endif
Bram Moolenaara2442432007-04-26 14:26:37 +000077# endif
78#endif
79
Bram Moolenaar071d4272004-06-13 20:20:40 +000080#if defined(HAVE_SELECT)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010081extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
Bram Moolenaar071d4272004-06-13 20:20:40 +000082#endif
83
84#ifdef FEAT_MOUSE_GPM
85# include <gpm.h>
86/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
87 * I just copied relevant defines here. A cleaner solution would be to put gpm
88 * code into separate file and include there linux/keyboard.h
89 */
90/* #include <linux/keyboard.h> */
91# define KG_SHIFT 0
92# define KG_CTRL 2
93# define KG_ALT 3
94# define KG_ALTGR 1
95# define KG_SHIFTL 4
96# define KG_SHIFTR 5
97# define KG_CTRLL 6
98# define KG_CTRLR 7
99# define KG_CAPSSHIFT 8
100
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100101static void gpm_close(void);
102static int gpm_open(void);
103static int mch_gpm_process(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000104#endif
105
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000106#ifdef FEAT_SYSMOUSE
107# include <sys/consio.h>
108# include <sys/fbio.h>
109
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100110static int sysmouse_open(void);
111static void sysmouse_close(void);
Bram Moolenaard99df422016-01-29 23:20:40 +0100112static RETSIGTYPE sig_sysmouse SIGPROTOARG;
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000113#endif
114
Bram Moolenaar071d4272004-06-13 20:20:40 +0000115/*
116 * end of autoconf section. To be extended...
117 */
118
119/* Are the following #ifdefs still required? And why? Is that for X11? */
120
121#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
122# ifdef SIGWINCH
123# undef SIGWINCH
124# endif
125# ifdef TIOCGWINSZ
126# undef TIOCGWINSZ
127# endif
128#endif
129
130#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
131# define SIGWINCH SIGWINDOW
132#endif
133
134#ifdef FEAT_X11
135# include <X11/Xlib.h>
136# include <X11/Xutil.h>
137# include <X11/Xatom.h>
138# ifdef FEAT_XCLIPBOARD
139# include <X11/Intrinsic.h>
140# include <X11/Shell.h>
141# include <X11/StringDefs.h>
142static Widget xterm_Shell = (Widget)0;
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100143static void clip_update(void);
144static void xterm_update(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145# endif
146
147# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
148Window x11_window = 0;
149# endif
150Display *x11_display = NULL;
151
152# ifdef FEAT_TITLE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100153static int get_x11_windis(void);
154static void set_x11_title(char_u *);
155static void set_x11_icon(char_u *);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000156# endif
157#endif
158
159#ifdef FEAT_TITLE
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100160static int get_x11_title(int);
161static int get_x11_icon(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162
163static char_u *oldtitle = NULL;
164static int did_set_title = FALSE;
165static char_u *oldicon = NULL;
166static int did_set_icon = FALSE;
167#endif
168
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100169static void may_core_dump(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170
Bram Moolenaar205b8862011-09-07 15:04:31 +0200171#ifdef HAVE_UNION_WAIT
172typedef union wait waitstatus;
173#else
174typedef int waitstatus;
175#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100176static pid_t wait4pid(pid_t, waitstatus *);
Bram Moolenaar205b8862011-09-07 15:04:31 +0200177
Bram Moolenaarcda77642016-06-04 13:32:35 +0200178static int WaitForChar(long msec, int *interrupted);
179static int WaitForCharOrMouse(long msec, int *interrupted);
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100180#if defined(__BEOS__) || defined(VMS)
Bram Moolenaarcda77642016-06-04 13:32:35 +0200181int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000182#else
Bram Moolenaarcda77642016-06-04 13:32:35 +0200183static int RealWaitForChar(int, long, int *, int *interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184#endif
185
186#ifdef FEAT_XCLIPBOARD
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100187static int do_xterm_trace(void);
Bram Moolenaarcf851ce2005-06-16 21:52:47 +0000188# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000189#endif
190
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100191static void handle_resize(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000192
193#if defined(SIGWINCH)
Bram Moolenaard99df422016-01-29 23:20:40 +0100194static RETSIGTYPE sig_winch SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000195#endif
196#if defined(SIGINT)
Bram Moolenaard99df422016-01-29 23:20:40 +0100197static RETSIGTYPE catch_sigint SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198#endif
199#if defined(SIGPWR)
Bram Moolenaard99df422016-01-29 23:20:40 +0100200static RETSIGTYPE catch_sigpwr SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201#endif
202#if defined(SIGALRM) && defined(FEAT_X11) \
203 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
204# define SET_SIG_ALARM
Bram Moolenaard99df422016-01-29 23:20:40 +0100205static RETSIGTYPE sig_alarm SIGPROTOARG;
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000206/* volatile because it is used in signal handler sig_alarm(). */
207static volatile int sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000208#endif
Bram Moolenaard99df422016-01-29 23:20:40 +0100209static RETSIGTYPE deathtrap SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100211static void catch_int_signal(void);
212static void set_signals(void);
213static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)());
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +0200214#ifdef HAVE_SIGPROCMASK
215# define SIGSET_DECL(set) sigset_t set;
216# define BLOCK_SIGNALS(set) block_signals(set)
217# define UNBLOCK_SIGNALS(set) unblock_signals(set)
218#else
219# define SIGSET_DECL(set)
220# define BLOCK_SIGNALS(set) do { /**/ } while (0)
221# define UNBLOCK_SIGNALS(set) do { /**/ } while (0)
222#endif
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100223static int have_wildcard(int, char_u **);
224static int have_dollars(int, char_u **);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000225
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100226static int save_patterns(int num_pat, char_u **pat, int *num_file, char_u ***file);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227
228#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000229# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000230#endif
231
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000232/* volatile because it is used in signal handler sig_winch(). */
233static volatile int do_resize = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000234static char_u *extra_shell_arg = NULL;
235static int show_shell_mess = TRUE;
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000236/* volatile because it is used in signal handler deathtrap(). */
237static volatile int deadly_signal = 0; /* The signal we caught */
238/* volatile because it is used in signal handler deathtrap(). */
239static volatile int in_mch_delay = FALSE; /* sleeping in mch_delay() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000240
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +0100241#if defined(FEAT_JOB_CHANNEL) && !defined(USE_SYSTEM)
242static int dont_check_job_ended = 0;
243#endif
244
Bram Moolenaar071d4272004-06-13 20:20:40 +0000245static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
246
247#ifdef USE_XSMP
248typedef struct
249{
250 SmcConn smcconn; /* The SM connection ID */
251 IceConn iceconn; /* The ICE connection ID */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200252 char *clientid; /* The client ID for the current smc session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000253 Bool save_yourself; /* If we're in the middle of a save_yourself */
254 Bool shutdown; /* If we're in shutdown mode */
255} xsmp_config_T;
256
257static xsmp_config_T xsmp;
258#endif
259
260#ifdef SYS_SIGLIST_DECLARED
261/*
262 * I have seen
263 * extern char *_sys_siglist[NSIG];
264 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
265 * that describe the signals. That is nearly what we want here. But
266 * autoconf does only check for sys_siglist (without the underscore), I
267 * do not want to change everything today.... jw.
Bram Moolenaar3f7d0902016-11-12 21:13:42 +0100268 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.ac.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000269 */
270#endif
271
272static struct signalinfo
273{
274 int sig; /* Signal number, eg. SIGSEGV etc */
275 char *name; /* Signal name (not char_u!). */
276 char deadly; /* Catch as a deadly signal? */
277} signal_info[] =
278{
279#ifdef SIGHUP
280 {SIGHUP, "HUP", TRUE},
281#endif
282#ifdef SIGQUIT
283 {SIGQUIT, "QUIT", TRUE},
284#endif
285#ifdef SIGILL
286 {SIGILL, "ILL", TRUE},
287#endif
288#ifdef SIGTRAP
289 {SIGTRAP, "TRAP", TRUE},
290#endif
291#ifdef SIGABRT
292 {SIGABRT, "ABRT", TRUE},
293#endif
294#ifdef SIGEMT
295 {SIGEMT, "EMT", TRUE},
296#endif
297#ifdef SIGFPE
298 {SIGFPE, "FPE", TRUE},
299#endif
300#ifdef SIGBUS
301 {SIGBUS, "BUS", TRUE},
302#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100303#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
304 /* MzScheme uses SEGV in its garbage collector */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 {SIGSEGV, "SEGV", TRUE},
306#endif
307#ifdef SIGSYS
308 {SIGSYS, "SYS", TRUE},
309#endif
310#ifdef SIGALRM
311 {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
312#endif
313#ifdef SIGTERM
314 {SIGTERM, "TERM", TRUE},
315#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100316#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000317 {SIGVTALRM, "VTALRM", TRUE},
318#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000319#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
320 /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
321 * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322 {SIGPROF, "PROF", TRUE},
323#endif
324#ifdef SIGXCPU
325 {SIGXCPU, "XCPU", TRUE},
326#endif
327#ifdef SIGXFSZ
328 {SIGXFSZ, "XFSZ", TRUE},
329#endif
330#ifdef SIGUSR1
331 {SIGUSR1, "USR1", TRUE},
332#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000333#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
334 /* Used for sysmouse handling */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000335 {SIGUSR2, "USR2", TRUE},
336#endif
337#ifdef SIGINT
338 {SIGINT, "INT", FALSE},
339#endif
340#ifdef SIGWINCH
341 {SIGWINCH, "WINCH", FALSE},
342#endif
343#ifdef SIGTSTP
344 {SIGTSTP, "TSTP", FALSE},
345#endif
346#ifdef SIGPIPE
347 {SIGPIPE, "PIPE", FALSE},
348#endif
349 {-1, "Unknown!", FALSE}
350};
351
Bram Moolenaar25724922009-07-14 15:38:41 +0000352 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100353mch_chdir(char *path)
Bram Moolenaar25724922009-07-14 15:38:41 +0000354{
355 if (p_verbose >= 5)
356 {
357 verbose_enter();
358 smsg((char_u *)"chdir(%s)", path);
359 verbose_leave();
360 }
361# ifdef VMS
362 return chdir(vms_fixfilename(path));
363# else
364 return chdir(path);
365# endif
366}
367
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000368/*
369 * Write s[len] to the screen.
370 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000371 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100372mch_write(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000373{
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000374 ignored = (int)write(1, (char *)s, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375 if (p_wd) /* Unix is too fast, slow down a bit more */
Bram Moolenaar8fdd7212016-03-26 19:41:48 +0100376 RealWaitForChar(read_cmd_fd, p_wd, NULL, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377}
378
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200379#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
380/*
381 * Return time in msec since "start_tv".
382 */
383 static long
384elapsed(struct timeval *start_tv)
385{
386 struct timeval now_tv;
387
388 gettimeofday(&now_tv, NULL);
389 return (now_tv.tv_sec - start_tv->tv_sec) * 1000L
390 + (now_tv.tv_usec - start_tv->tv_usec) / 1000L;
391}
392#endif
393
Bram Moolenaar071d4272004-06-13 20:20:40 +0000394/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000395 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000396 * Get a characters from the keyboard.
397 * Return the number of characters that are available.
398 * If wtime == 0 do not wait for characters.
399 * If wtime == n wait a short time for characters.
400 * If wtime == -1 wait forever for characters.
401 */
402 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100403mch_inchar(
404 char_u *buf,
405 int maxlen,
406 long wtime, /* don't use "time", MIPS cannot handle it */
407 int tb_change_cnt)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408{
409 int len;
Bram Moolenaarcda77642016-06-04 13:32:35 +0200410 int interrupted = FALSE;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200411 int did_start_blocking = FALSE;
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200412 long wait_time;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200413 long elapsed_time = 0;
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200414#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
415 struct timeval start_tv;
416
417 gettimeofday(&start_tv, NULL);
418#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000419
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200420 /* repeat until we got a character or waited long enough */
Bram Moolenaare30a3d02016-06-04 14:11:20 +0200421 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422 {
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200423 /* Check if window changed size while we were busy, perhaps the ":set
424 * columns=99" command was used. */
425 while (do_resize)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000426 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200427
Bram Moolenaar93c88e02015-09-15 14:12:05 +0200428#ifdef MESSAGE_QUEUE
429 parse_queued_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200430#endif
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200431 if (wtime < 0 && did_start_blocking)
432 /* blocking and already waited for p_ut */
433 wait_time = -1;
434 else
435 {
436 if (wtime >= 0)
437 wait_time = wtime;
438 else
439 /* going to block after p_ut */
440 wait_time = p_ut;
441#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
442 elapsed_time = elapsed(&start_tv);
443#endif
444 wait_time -= elapsed_time;
445 if (wait_time < 0)
446 {
447 if (wtime >= 0)
448 /* no character available within "wtime" */
449 return 0;
450
451 if (wtime < 0)
452 {
453 /* no character available within 'updatetime' */
454 did_start_blocking = TRUE;
455#ifdef FEAT_AUTOCMD
456 if (trigger_cursorhold() && maxlen >= 3
457 && !typebuf_changed(tb_change_cnt))
458 {
459 buf[0] = K_SPECIAL;
460 buf[1] = KS_EXTRA;
461 buf[2] = (int)KE_CURSORHOLD;
462 return 3;
463 }
464#endif
465 /*
466 * If there is no character available within 'updatetime'
467 * seconds flush all the swap files to disk.
468 * Also done when interrupted by SIGWINCH.
469 */
470 before_blocking();
471 continue;
472 }
473 }
474 }
475
476#ifdef FEAT_JOB_CHANNEL
477 /* Checking if a job ended requires polling. Do this every 100 msec. */
478 if (has_pending_job() && (wait_time < 0 || wait_time > 100L))
479 wait_time = 100L;
480#endif
481
Bram Moolenaar071d4272004-06-13 20:20:40 +0000482 /*
Bram Moolenaar48bae372010-07-29 23:12:15 +0200483 * We want to be interrupted by the winch signal
484 * or by an event on the monitored file descriptors.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000485 */
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200486 if (WaitForChar(wait_time, &interrupted))
Bram Moolenaar67c53842010-05-22 18:28:27 +0200487 {
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200488 /* If input was put directly in typeahead buffer bail out here. */
489 if (typebuf_changed(tb_change_cnt))
490 return 0;
491
492 /*
493 * For some terminals we only get one character at a time.
494 * We want the get all available characters, so we could keep on
495 * trying until none is available
496 * For some other terminals this is quite slow, that's why we don't
497 * do it.
498 */
499 len = read_from_input_buf(buf, (long)maxlen);
500 if (len > 0)
501 return len;
502 continue;
Bram Moolenaar67c53842010-05-22 18:28:27 +0200503 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200505 /* no character available */
506#if !(defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H))
507 /* estimate the elapsed time */
Bram Moolenaarde5e2c22016-11-04 20:35:31 +0100508 elapsed_time += wait_time;
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200509#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200511 if (do_resize /* interrupted by SIGWINCH signal */
512#ifdef FEAT_CLIENTSERVER
513 || server_waiting()
514#endif
515#ifdef MESSAGE_QUEUE
516 || interrupted
517#endif
518 || wait_time > 0
519 || !did_start_blocking)
520 continue;
521
522 /* no character available or interrupted */
523 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000524 }
Bram Moolenaar01688ad2016-10-27 20:00:07 +0200525 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526}
527
528 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100529handle_resize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530{
531 do_resize = FALSE;
532 shell_resized();
533}
534
535/*
Bram Moolenaar40b1b542016-04-20 20:18:23 +0200536 * Return non-zero if a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000537 */
538 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100539mch_char_avail(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540{
Bram Moolenaarcda77642016-06-04 13:32:35 +0200541 return WaitForChar(0L, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542}
543
544#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
545# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000546# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547# endif
548# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
549# include <sys/sysctl.h>
550# endif
551# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
552# include <sys/sysinfo.h>
553# endif
554
555/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000556 * Return total amount of memory available in Kbyte.
557 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000559 long_u
Bram Moolenaar05540972016-01-30 20:31:25 +0100560mch_total_mem(int special UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561{
Bram Moolenaar071d4272004-06-13 20:20:40 +0000562 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000563 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000564
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200565# ifdef HAVE_SYSCTL
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 int mib[2], physmem;
567 size_t len;
568
569 /* BSD way of getting the amount of RAM available. */
570 mib[0] = CTL_HW;
571 mib[1] = HW_USERMEM;
572 len = sizeof(physmem);
573 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
574 mem = (long_u)physmem;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200575# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000576
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200577# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578 if (mem == 0)
579 {
580 struct sysinfo sinfo;
581
582 /* Linux way of getting amount of RAM available */
583 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000584 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200585# ifdef HAVE_SYSINFO_MEM_UNIT
Bram Moolenaar914572a2007-05-01 11:37:47 +0000586 /* avoid overflow as much as possible */
587 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
588 {
589 sinfo.mem_unit = sinfo.mem_unit >> 1;
590 --shiftright;
591 }
592 mem = sinfo.totalram * sinfo.mem_unit;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200593# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 mem = sinfo.totalram;
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200595# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000596 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200598# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000599
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200600# ifdef HAVE_SYSCONF
Bram Moolenaar071d4272004-06-13 20:20:40 +0000601 if (mem == 0)
602 {
603 long pagesize, pagecount;
604
605 /* Solaris way of getting amount of RAM available */
606 pagesize = sysconf(_SC_PAGESIZE);
607 pagecount = sysconf(_SC_PHYS_PAGES);
608 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000609 {
610 /* avoid overflow as much as possible */
611 while (shiftright > 0 && (pagesize & 1) == 0)
612 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000613 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000614 --shiftright;
615 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000616 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000617 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200619# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620
621 /* Return the minimum of the physical memory and the user limit, because
622 * using more than the user limit may cause Vim to be terminated. */
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200623# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624 {
625 struct rlimit rlp;
626
627 if (getrlimit(RLIMIT_DATA, &rlp) == 0
628 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200629# ifdef RLIM_INFINITY
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 && rlp.rlim_cur != RLIM_INFINITY
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200631# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000632 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000634 {
635 mem = (long_u)rlp.rlim_cur;
636 shiftright = 10;
637 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200639# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640
641 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000642 return mem >> shiftright;
643 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644}
645#endif
646
647 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100648mch_delay(long msec, int ignoreinput)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649{
650 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000651#ifdef FEAT_MZSCHEME
652 long total = msec; /* remember original value */
653#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654
655 if (ignoreinput)
656 {
657 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000658 * here. But we don't want QUIT to kill us (CTRL-\ used in a
659 * shell may produce SIGQUIT). */
660 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661 old_tmode = curr_tmode;
662 if (curr_tmode == TMODE_RAW)
663 settmode(TMODE_SLEEP);
664
665 /*
666 * Everybody sleeps in a different way...
667 * Prefer nanosleep(), some versions of usleep() can only sleep up to
668 * one second.
669 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000670#ifdef FEAT_MZSCHEME
671 do
672 {
673 /* if total is large enough, wait by portions in p_mzq */
674 if (total > p_mzq)
675 msec = p_mzq;
676 else
677 msec = total;
678 total -= msec;
679#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680#ifdef HAVE_NANOSLEEP
681 {
682 struct timespec ts;
683
684 ts.tv_sec = msec / 1000;
685 ts.tv_nsec = (msec % 1000) * 1000000;
686 (void)nanosleep(&ts, NULL);
687 }
688#else
689# ifdef HAVE_USLEEP
690 while (msec >= 1000)
691 {
692 usleep((unsigned int)(999 * 1000));
693 msec -= 999;
694 }
695 usleep((unsigned int)(msec * 1000));
696# else
697# ifndef HAVE_SELECT
698 poll(NULL, 0, (int)msec);
699# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700 {
701 struct timeval tv;
702
703 tv.tv_sec = msec / 1000;
704 tv.tv_usec = (msec % 1000) * 1000;
705 /*
706 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
707 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
708 */
709 select(0, NULL, NULL, NULL, &tv);
710 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711# endif /* HAVE_SELECT */
712# endif /* HAVE_NANOSLEEP */
713#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000714#ifdef FEAT_MZSCHEME
715 }
716 while (total > 0);
717#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718
719 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000720 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000721 }
722 else
Bram Moolenaarcda77642016-06-04 13:32:35 +0200723 WaitForChar(msec, NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000724}
725
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000726#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
728# define HAVE_CHECK_STACK_GROWTH
729/*
730 * Support for checking for an almost-out-of-stack-space situation.
731 */
732
733/*
734 * Return a pointer to an item on the stack. Used to find out if the stack
735 * grows up or down.
736 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100737static void check_stack_growth(char *p);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738static int stack_grows_downwards;
739
740/*
741 * Find out if the stack grows upwards or downwards.
742 * "p" points to a variable on the stack of the caller.
743 */
744 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100745check_stack_growth(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746{
747 int i;
748
749 stack_grows_downwards = (p > (char *)&i);
750}
751#endif
752
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000753#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000754static char *stack_limit = NULL;
755
756#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
757# include <pthread.h>
758# include <pthread_np.h>
759#endif
760
761/*
762 * Find out until how var the stack can grow without getting into trouble.
763 * Called when starting up and when switching to the signal stack in
764 * deathtrap().
765 */
766 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100767get_stack_limit(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768{
769 struct rlimit rlp;
770 int i;
771 long lim;
772
773 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
774 * limit doesn't fit in a long (rlim_cur might be "long long"). */
775 if (getrlimit(RLIMIT_STACK, &rlp) == 0
776 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
777# ifdef RLIM_INFINITY
778 && rlp.rlim_cur != RLIM_INFINITY
779# endif
780 )
781 {
782 lim = (long)rlp.rlim_cur;
783#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
784 {
785 pthread_attr_t attr;
786 size_t size;
787
788 /* On FreeBSD the initial thread always has a fixed stack size, no
789 * matter what the limits are set to. Normally it's 1 Mbyte. */
790 pthread_attr_init(&attr);
791 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
792 {
793 pthread_attr_getstacksize(&attr, &size);
794 if (lim > (long)size)
795 lim = (long)size;
796 }
797 pthread_attr_destroy(&attr);
798 }
799#endif
800 if (stack_grows_downwards)
801 {
802 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
803 if (stack_limit >= (char *)&i)
804 /* overflow, set to 1/16 of current stack position */
805 stack_limit = (char *)((long)&i / 16L);
806 }
807 else
808 {
809 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
810 if (stack_limit <= (char *)&i)
811 stack_limit = NULL; /* overflow */
812 }
813 }
814}
815
816/*
817 * Return FAIL when running out of stack space.
818 * "p" must point to any variable local to the caller that's on the stack.
819 */
820 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100821mch_stackcheck(char *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822{
823 if (stack_limit != NULL)
824 {
825 if (stack_grows_downwards)
826 {
827 if (p < stack_limit)
828 return FAIL;
829 }
830 else if (p > stack_limit)
831 return FAIL;
832 }
833 return OK;
834}
835#endif
836
837#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
838/*
839 * Support for using the signal stack.
840 * This helps when we run out of stack space, which causes a SIGSEGV. The
841 * signal handler then must run on another stack, since the normal stack is
842 * completely full.
843 */
844
Bram Moolenaar39766a72013-11-03 00:41:00 +0100845#if defined(HAVE_AVAILABILITYMACROS_H)
Bram Moolenaar4cc95d12013-11-02 21:49:32 +0100846# include <AvailabilityMacros.h>
847#endif
848
Bram Moolenaar071d4272004-06-13 20:20:40 +0000849#ifndef SIGSTKSZ
850# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
851#endif
852
853# ifdef HAVE_SIGALTSTACK
854static stack_t sigstk; /* for sigaltstack() */
855# else
856static struct sigstack sigstk; /* for sigstack() */
857# endif
858
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100859static void init_signal_stack(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860static char *signal_stack;
861
862 static void
Bram Moolenaar05540972016-01-30 20:31:25 +0100863init_signal_stack(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000864{
865 if (signal_stack != NULL)
866 {
867# ifdef HAVE_SIGALTSTACK
Bram Moolenaar1a3d0862007-08-30 09:47:38 +0000868# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
869 || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
871 * "struct sigaltstack" needs to be declared. */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +0100872 extern int sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000873# endif
874
875# ifdef HAVE_SS_BASE
876 sigstk.ss_base = signal_stack;
877# else
878 sigstk.ss_sp = signal_stack;
879# endif
880 sigstk.ss_size = SIGSTKSZ;
881 sigstk.ss_flags = 0;
882 (void)sigaltstack(&sigstk, NULL);
883# else
884 sigstk.ss_sp = signal_stack;
885 if (stack_grows_downwards)
886 sigstk.ss_sp += SIGSTKSZ - 1;
887 sigstk.ss_onstack = 0;
888 (void)sigstack(&sigstk, NULL);
889# endif
890 }
891}
892#endif
893
894/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000895 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 * will barf when the second argument to signal() is ``wrong''.
897 * Let me try it with a few tricky defines from my own osdef.h (jw).
898 */
899#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000900 static RETSIGTYPE
901sig_winch SIGDEFARG(sigarg)
902{
903 /* this is not required on all systems, but it doesn't hurt anybody */
904 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
905 do_resize = TRUE;
906 SIGRETURN;
907}
908#endif
909
910#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000911 static RETSIGTYPE
912catch_sigint SIGDEFARG(sigarg)
913{
914 /* this is not required on all systems, but it doesn't hurt anybody */
915 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
916 got_int = TRUE;
917 SIGRETURN;
918}
919#endif
920
921#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000922 static RETSIGTYPE
923catch_sigpwr SIGDEFARG(sigarg)
924{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000925 /* this is not required on all systems, but it doesn't hurt anybody */
926 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000927 /*
928 * I'm not sure we get the SIGPWR signal when the system is really going
929 * down or when the batteries are almost empty. Just preserve the swap
930 * files and don't exit, that can't do any harm.
931 */
932 ml_sync_all(FALSE, FALSE);
933 SIGRETURN;
934}
935#endif
936
937#ifdef SET_SIG_ALARM
938/*
939 * signal function for alarm().
940 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000941 static RETSIGTYPE
942sig_alarm SIGDEFARG(sigarg)
943{
944 /* doesn't do anything, just to break a system call */
945 sig_alarm_called = TRUE;
946 SIGRETURN;
947}
948#endif
949
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000950#if (defined(HAVE_SETJMP_H) \
951 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
952 || defined(FEAT_LIBCALL))) \
953 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000954/*
955 * A simplistic version of setjmp() that only allows one level of using.
956 * Don't call twice before calling mch_endjmp()!.
957 * Usage:
958 * mch_startjmp();
959 * if (SETJMP(lc_jump_env) != 0)
960 * {
961 * mch_didjmp();
962 * EMSG("crash!");
963 * }
964 * else
965 * {
966 * do_the_work;
967 * mch_endjmp();
968 * }
969 * Note: Can't move SETJMP() here, because a function calling setjmp() must
970 * not return before the saved environment is used.
971 * Returns OK for normal return, FAIL when the protected code caused a
972 * problem and LONGJMP() was used.
973 */
974 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100975mch_startjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000976{
977#ifdef SIGHASARG
978 lc_signal = 0;
979#endif
980 lc_active = TRUE;
981}
982
983 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100984mch_endjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000985{
986 lc_active = FALSE;
987}
988
989 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100990mch_didjmp(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000991{
992# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
993 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
994 * otherwise catching the signal only works once. */
995 init_signal_stack();
996# endif
997}
998#endif
999
1000/*
1001 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001002 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001003 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001004 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
1005 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001006 */
1007 static RETSIGTYPE
1008deathtrap SIGDEFARG(sigarg)
1009{
1010 static int entered = 0; /* count the number of times we got here.
1011 Note: when memory has been corrupted
1012 this may get an arbitrary value! */
1013#ifdef SIGHASARG
1014 int i;
1015#endif
1016
1017#if defined(HAVE_SETJMP_H)
1018 /*
1019 * Catch a crash in protected code.
1020 * Restores the environment saved in lc_jump_env, which looks like
1021 * SETJMP() returns 1.
1022 */
1023 if (lc_active)
1024 {
1025# if defined(SIGHASARG)
1026 lc_signal = sigarg;
1027# endif
1028 lc_active = FALSE; /* don't jump again */
1029 LONGJMP(lc_jump_env, 1);
1030 /* NOTREACHED */
1031 }
1032#endif
1033
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001034#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +00001035# ifdef SIGQUIT
1036 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
1037 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
1038 * pressing CTRL-\, but we don't want Vim to exit then. */
1039 if (in_mch_delay && sigarg == SIGQUIT)
1040 SIGRETURN;
1041# endif
1042
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001043 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
1044 * here. This avoids that a non-reentrant function is interrupted, e.g.,
1045 * free(). Calling free() again may then cause a crash. */
1046 if (entered == 0
1047 && (0
1048# ifdef SIGHUP
1049 || sigarg == SIGHUP
1050# endif
1051# ifdef SIGQUIT
1052 || sigarg == SIGQUIT
1053# endif
1054# ifdef SIGTERM
1055 || sigarg == SIGTERM
1056# endif
1057# ifdef SIGPWR
1058 || sigarg == SIGPWR
1059# endif
1060# ifdef SIGUSR1
1061 || sigarg == SIGUSR1
1062# endif
1063# ifdef SIGUSR2
1064 || sigarg == SIGUSR2
1065# endif
1066 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001067 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001068 SIGRETURN;
1069#endif
1070
Bram Moolenaar071d4272004-06-13 20:20:40 +00001071 /* Remember how often we have been called. */
1072 ++entered;
1073
Bram Moolenaare429e702016-06-10 19:49:14 +02001074#ifdef FEAT_AUTOCMD
1075 /* Executing autocommands is likely to use more stack space than we have
1076 * available in the signal stack. */
1077 block_autocmds();
1078#endif
1079
Bram Moolenaar071d4272004-06-13 20:20:40 +00001080#ifdef FEAT_EVAL
1081 /* Set the v:dying variable. */
1082 set_vim_var_nr(VV_DYING, (long)entered);
1083#endif
1084
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001085#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001086 /* Since we are now using the signal stack, need to reset the stack
1087 * limit. Otherwise using a regexp will fail. */
1088 get_stack_limit();
1089#endif
1090
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001091#if 0
1092 /* This is for opening gdb the moment Vim crashes.
1093 * You need to manually adjust the file name and Vim executable name.
1094 * Suggested by SungHyun Nam. */
1095 {
1096# define VI_GDB_FILE "/tmp/vimgdb"
1097# define VIM_NAME "/usr/bin/vim"
1098 FILE *fp = fopen(VI_GDB_FILE, "w");
1099 if (fp)
1100 {
1101 fprintf(fp,
1102 "file %s\n"
1103 "attach %d\n"
1104 "set height 1000\n"
1105 "bt full\n"
1106 , VIM_NAME, getpid());
1107 fclose(fp);
1108 system("xterm -e gdb -x "VI_GDB_FILE);
1109 unlink(VI_GDB_FILE);
1110 }
1111 }
1112#endif
1113
Bram Moolenaar071d4272004-06-13 20:20:40 +00001114#ifdef SIGHASARG
1115 /* try to find the name of this signal */
1116 for (i = 0; signal_info[i].sig != -1; i++)
1117 if (sigarg == signal_info[i].sig)
1118 break;
1119 deadly_signal = sigarg;
1120#endif
1121
1122 full_screen = FALSE; /* don't write message to the GUI, it might be
1123 * part of the problem... */
1124 /*
1125 * If something goes wrong after entering here, we may get here again.
1126 * When this happens, give a message and try to exit nicely (resetting the
1127 * terminal mode, etc.)
1128 * When this happens twice, just exit, don't even try to give a message,
1129 * stack may be corrupt or something weird.
1130 * When this still happens again (or memory was corrupted in such a way
1131 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1132 */
1133 if (entered >= 3)
1134 {
1135 reset_signals(); /* don't catch any signals anymore */
1136 may_core_dump();
1137 if (entered >= 4)
1138 _exit(8);
1139 exit(7);
1140 }
1141 if (entered == 2)
1142 {
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001143 /* No translation, it may call malloc(). */
1144 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001145 out_flush();
1146 getout(1);
1147 }
1148
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001149 /* No translation, it may call malloc(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001150#ifdef SIGHASARG
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001151 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001152 signal_info[i].name);
1153#else
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001154 sprintf((char *)IObuff, "Vim: Caught deadly signal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001156
1157 /* Preserve files and exit. This sets the really_exiting flag to prevent
1158 * calling free(). */
1159 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160
Bram Moolenaare429e702016-06-10 19:49:14 +02001161 /* NOTREACHED */
1162
Bram Moolenaar009b2592004-10-24 19:18:58 +00001163#ifdef NBDEBUG
1164 reset_signals();
1165 may_core_dump();
1166 abort();
1167#endif
1168
Bram Moolenaar071d4272004-06-13 20:20:40 +00001169 SIGRETURN;
1170}
1171
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001172#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001173/*
1174 * On Solaris with multi-threading, suspending might not work immediately.
1175 * Catch the SIGCONT signal, which will be used as an indication whether the
1176 * suspending has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001177 *
1178 * On Linux, signal is not always handled immediately either.
1179 * See https://bugs.launchpad.net/bugs/291373
1180 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001181 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001182 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001183static volatile int sigcont_received;
Bram Moolenaard99df422016-01-29 23:20:40 +01001184static RETSIGTYPE sigcont_handler SIGPROTOARG;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001185
1186/*
1187 * signal handler for SIGCONT
1188 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001189 static RETSIGTYPE
1190sigcont_handler SIGDEFARG(sigarg)
1191{
1192 sigcont_received = TRUE;
1193 SIGRETURN;
1194}
1195#endif
1196
Bram Moolenaar62b42182010-09-21 22:09:37 +02001197# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001198static void loose_clipboard(void);
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001199# ifdef USE_SYSTEM
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001200static void save_clipboard(void);
1201static void restore_clipboard(void);
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001202
1203static void *clip_star_save = NULL;
1204static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001205# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001206
1207/*
1208 * Called when Vim is going to sleep or execute a shell command.
1209 * We can't respond to requests for the X selections. Lose them, otherwise
1210 * other applications will hang. But first copy the text to cut buffer 0.
1211 */
1212 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001213loose_clipboard(void)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001214{
1215 if (clip_star.owned || clip_plus.owned)
1216 {
1217 x11_export_final_selection();
1218 if (clip_star.owned)
1219 clip_lose_selection(&clip_star);
1220 if (clip_plus.owned)
1221 clip_lose_selection(&clip_plus);
1222 if (x11_display != NULL)
1223 XFlush(x11_display);
1224 }
1225}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001226
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001227# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001228/*
1229 * Save clipboard text to restore later.
1230 */
1231 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001232save_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001233{
1234 if (clip_star.owned)
1235 clip_star_save = get_register('*', TRUE);
1236 if (clip_plus.owned)
1237 clip_plus_save = get_register('+', TRUE);
1238}
1239
1240/*
1241 * Restore clipboard text if no one own the X selection.
1242 */
1243 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001244restore_clipboard(void)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001245{
1246 if (clip_star_save != NULL)
1247 {
1248 if (!clip_gen_owner_exists(&clip_star))
1249 put_register('*', clip_star_save);
1250 else
1251 free_register(clip_star_save);
1252 clip_star_save = NULL;
1253 }
1254 if (clip_plus_save != NULL)
1255 {
1256 if (!clip_gen_owner_exists(&clip_plus))
1257 put_register('+', clip_plus_save);
1258 else
1259 free_register(clip_plus_save);
1260 clip_plus_save = NULL;
1261 }
1262}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001263# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001264#endif
1265
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266/*
1267 * If the machine has job control, use it to suspend the program,
1268 * otherwise fake it by starting a new shell.
1269 */
1270 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001271mch_suspend(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001272{
1273 /* BeOS does have SIGTSTP, but it doesn't work. */
1274#if defined(SIGTSTP) && !defined(__BEOS__)
1275 out_flush(); /* needed to make cursor visible on some systems */
1276 settmode(TMODE_COOK);
1277 out_flush(); /* needed to disable mouse on some systems */
1278
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
1282
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001283# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284 sigcont_received = FALSE;
1285# endif
1286 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001287# if defined(_REENTRANT) && defined(SIGCONT)
1288 /*
1289 * Wait for the SIGCONT signal to be handled. It generally happens
1290 * immediately, but somehow not all the time. Do not call pause()
1291 * because there would be race condition which would hang Vim if
1292 * signal happened in between the test of sigcont_received and the
1293 * call to pause(). If signal is not yet received, call sleep(0)
1294 * to just yield CPU. Signal should then be received. If somehow
1295 * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
1296 * further if signal is not received after 1+2+3+4 ms (not expected
1297 * to happen).
1298 */
1299 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001300 long wait_time;
1301 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001302 /* Loop is not entered most of the time */
Bram Moolenaar262735e2009-07-14 10:20:22 +00001303 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001304 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305# endif
1306
1307# ifdef FEAT_TITLE
1308 /*
1309 * Set oldtitle to NULL, so the current title is obtained again.
1310 */
1311 vim_free(oldtitle);
1312 oldtitle = NULL;
1313# endif
1314 settmode(TMODE_RAW);
1315 need_check_timestamps = TRUE;
1316 did_check_timestamps = FALSE;
1317#else
1318 suspend_shell();
1319#endif
1320}
1321
1322 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001323mch_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001324{
1325 Columns = 80;
1326 Rows = 24;
1327
1328 out_flush();
1329 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001330
Bram Moolenaar56718732006-03-15 22:53:57 +00001331#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001332 mac_conv_init();
1333#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001334#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1335 win_clip_init();
1336#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001337}
1338
1339 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001340set_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001341{
1342#if defined(SIGWINCH)
1343 /*
1344 * WINDOW CHANGE signal is handled with sig_winch().
1345 */
1346 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1347#endif
1348
1349 /*
1350 * We want the STOP signal to work, to make mch_suspend() work.
1351 * For "rvim" the STOP signal is ignored.
1352 */
1353#ifdef SIGTSTP
1354 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1355#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001356#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001357 signal(SIGCONT, sigcont_handler);
1358#endif
1359
1360 /*
1361 * We want to ignore breaking of PIPEs.
1362 */
1363#ifdef SIGPIPE
1364 signal(SIGPIPE, SIG_IGN);
1365#endif
1366
Bram Moolenaar071d4272004-06-13 20:20:40 +00001367#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001368 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001369#endif
1370
1371 /*
1372 * Ignore alarm signals (Perl's alarm() generates it).
1373 */
1374#ifdef SIGALRM
1375 signal(SIGALRM, SIG_IGN);
1376#endif
1377
1378 /*
1379 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1380 * work will be lost.
1381 */
1382#ifdef SIGPWR
1383 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1384#endif
1385
1386 /*
1387 * Arrange for other signals to gracefully shutdown Vim.
1388 */
1389 catch_signals(deathtrap, SIG_ERR);
1390
1391#if defined(FEAT_GUI) && defined(SIGHUP)
1392 /*
1393 * When the GUI is running, ignore the hangup signal.
1394 */
1395 if (gui.in_use)
1396 signal(SIGHUP, SIG_IGN);
1397#endif
1398}
1399
Bram Moolenaardf177f62005-02-22 08:39:57 +00001400#if defined(SIGINT) || defined(PROTO)
1401/*
1402 * Catch CTRL-C (only works while in Cooked mode).
1403 */
1404 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001405catch_int_signal(void)
Bram Moolenaardf177f62005-02-22 08:39:57 +00001406{
1407 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1408}
1409#endif
1410
Bram Moolenaar071d4272004-06-13 20:20:40 +00001411 void
Bram Moolenaar05540972016-01-30 20:31:25 +01001412reset_signals(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001413{
1414 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001415#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001416 /* SIGCONT isn't in the list, because its default action is ignore */
1417 signal(SIGCONT, SIG_DFL);
1418#endif
1419}
1420
1421 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001422catch_signals(
1423 RETSIGTYPE (*func_deadly)(),
1424 RETSIGTYPE (*func_other)())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001425{
1426 int i;
1427
1428 for (i = 0; signal_info[i].sig != -1; i++)
1429 if (signal_info[i].deadly)
1430 {
1431#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1432 struct sigaction sa;
1433
1434 /* Setup to use the alternate stack for the signal function. */
1435 sa.sa_handler = func_deadly;
1436 sigemptyset(&sa.sa_mask);
1437# if defined(__linux__) && defined(_REENTRANT)
1438 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1439 * thread handling in combination with using the alternate stack:
1440 * pthread library functions try to use the stack pointer to
1441 * identify the current thread, causing a SEGV signal, which
1442 * recursively calls deathtrap() and hangs. */
1443 sa.sa_flags = 0;
1444# else
1445 sa.sa_flags = SA_ONSTACK;
1446# endif
1447 sigaction(signal_info[i].sig, &sa, NULL);
1448#else
1449# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1450 struct sigvec sv;
1451
1452 /* Setup to use the alternate stack for the signal function. */
1453 sv.sv_handler = func_deadly;
1454 sv.sv_mask = 0;
1455 sv.sv_flags = SV_ONSTACK;
1456 sigvec(signal_info[i].sig, &sv, NULL);
1457# else
1458 signal(signal_info[i].sig, func_deadly);
1459# endif
1460#endif
1461 }
1462 else if (func_other != SIG_ERR)
1463 signal(signal_info[i].sig, func_other);
1464}
1465
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02001466#ifdef HAVE_SIGPROCMASK
1467 static void
1468block_signals(sigset_t *set)
1469{
1470 sigset_t newset;
1471 int i;
1472
1473 sigemptyset(&newset);
1474
1475 for (i = 0; signal_info[i].sig != -1; i++)
1476 sigaddset(&newset, signal_info[i].sig);
1477
1478# if defined(_REENTRANT) && defined(SIGCONT)
1479 /* SIGCONT isn't in the list, because its default action is ignore */
1480 sigaddset(&newset, SIGCONT);
1481# endif
1482
1483 sigprocmask(SIG_BLOCK, &newset, set);
1484}
1485
1486 static void
1487unblock_signals(sigset_t *set)
1488{
1489 sigprocmask(SIG_SETMASK, set, NULL);
1490}
1491#endif
1492
Bram Moolenaar071d4272004-06-13 20:20:40 +00001493/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001494 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001495 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1496 * return TRUE
1497 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1498 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001499 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001500 * Returns TRUE when Vim should exit.
1501 */
1502 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001503vim_handle_signal(int sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001504{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001505 static int got_signal = 0;
1506 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001507
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001508 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001509 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001510 case SIGNAL_BLOCK: blocked = TRUE;
1511 break;
1512
1513 case SIGNAL_UNBLOCK: blocked = FALSE;
1514 if (got_signal != 0)
1515 {
1516 kill(getpid(), got_signal);
1517 got_signal = 0;
1518 }
1519 break;
1520
1521 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001522 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001523 got_signal = sig;
1524#ifdef SIGPWR
1525 if (sig != SIGPWR)
1526#endif
1527 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001528 break;
1529 }
1530 return FALSE;
1531}
1532
1533/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001534 * Check_win checks whether we have an interactive stdout.
1535 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001536 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001537mch_check_win(int argc UNUSED, char **argv UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001538{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001539 if (isatty(1))
1540 return OK;
1541 return FAIL;
1542}
1543
1544/*
1545 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1546 */
1547 int
Bram Moolenaar05540972016-01-30 20:31:25 +01001548mch_input_isatty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001549{
1550 if (isatty(read_cmd_fd))
1551 return TRUE;
1552 return FALSE;
1553}
1554
1555#ifdef FEAT_X11
1556
1557# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1558 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1559
Bram Moolenaare30a3d02016-06-04 14:11:20 +02001560static void xopen_message(struct timeval *start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001561
1562/*
1563 * Give a message about the elapsed time for opening the X window.
1564 */
1565 static void
Bram Moolenaare30a3d02016-06-04 14:11:20 +02001566xopen_message(struct timeval *start_tv)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001567{
Bram Moolenaare30a3d02016-06-04 14:11:20 +02001568 smsg((char_u *)_("Opening the X display took %ld msec"), elapsed(start_tv));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001569}
1570# endif
1571#endif
1572
1573#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1574/*
1575 * A few functions shared by X11 title and clipboard code.
1576 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001577static int x_error_handler(Display *dpy, XErrorEvent *error_event);
1578static int x_error_check(Display *dpy, XErrorEvent *error_event);
1579static int x_connect_to_server(void);
1580static int test_x11_window(Display *dpy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001581
1582static int got_x_error = FALSE;
1583
1584/*
1585 * X Error handler, otherwise X just exits! (very rude) -- webb
1586 */
1587 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001588x_error_handler(Display *dpy, XErrorEvent *error_event)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001589{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001590 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001591 STRCAT(IObuff, _("\nVim: Got X error\n"));
1592
1593 /* We cannot print a message and continue, because no X calls are allowed
1594 * here (causes my system to hang). Silently continuing might be an
1595 * alternative... */
1596 preserve_exit(); /* preserve files and exit */
1597
1598 return 0; /* NOTREACHED */
1599}
1600
1601/*
1602 * Another X Error handler, just used to check for errors.
1603 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001604 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001605x_error_check(Display *dpy UNUSED, XErrorEvent *error_event UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606{
1607 got_x_error = TRUE;
1608 return 0;
1609}
1610
1611#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1612# if defined(HAVE_SETJMP_H)
1613/*
1614 * An X IO Error handler, used to catch error while opening the display.
1615 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001616static int x_IOerror_check(Display *dpy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001617
Bram Moolenaar071d4272004-06-13 20:20:40 +00001618 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001619x_IOerror_check(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001620{
1621 /* This function should not return, it causes exit(). Longjump instead. */
1622 LONGJMP(lc_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001623# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001624 return 0; /* avoid the compiler complains about missing return value */
1625# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001626}
1627# endif
1628
1629/*
1630 * An X IO Error handler, used to catch terminal errors.
1631 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001632static int x_IOerror_handler(Display *dpy);
1633static void may_restore_clipboard(void);
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001634static int xterm_dpy_was_reset = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001635
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001637x_IOerror_handler(Display *dpy UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001638{
1639 xterm_dpy = NULL;
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001640 xterm_dpy_was_reset = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001641 x11_window = 0;
1642 x11_display = NULL;
1643 xterm_Shell = (Widget)0;
1644
1645 /* This function should not return, it causes exit(). Longjump instead. */
1646 LONGJMP(x_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001647# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001648 return 0; /* avoid the compiler complains about missing return value */
1649# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001650}
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001651
1652/*
1653 * If the X11 connection was lost try to restore it.
1654 * Helps when the X11 server was stopped and restarted while Vim was inactive
Bram Moolenaarcaad4f02014-12-17 14:36:14 +01001655 * (e.g. through tmux).
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001656 */
1657 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01001658may_restore_clipboard(void)
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001659{
1660 if (xterm_dpy_was_reset)
1661 {
1662 xterm_dpy_was_reset = FALSE;
Bram Moolenaar527a6782014-12-17 17:59:31 +01001663
1664# ifndef LESSTIF_VERSION
1665 /* This has been reported to avoid Vim getting stuck. */
1666 if (app_context != (XtAppContext)NULL)
1667 {
1668 XtDestroyApplicationContext(app_context);
1669 app_context = (XtAppContext)NULL;
1670 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
1671 }
1672# endif
1673
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001674 setup_term_clip();
1675 get_x11_title(FALSE);
1676 }
1677}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678#endif
1679
1680/*
1681 * Return TRUE when connection to the X server is desired.
1682 */
1683 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001684x_connect_to_server(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001685{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686#if defined(FEAT_CLIENTSERVER)
1687 if (x_force_connect)
1688 return TRUE;
1689#endif
1690 if (x_no_connect)
1691 return FALSE;
1692
1693 /* Check for a match with "exclude:" from 'clipboard'. */
1694 if (clip_exclude_prog != NULL)
1695 {
Bram Moolenaardffa5b82014-11-19 16:38:07 +01001696 if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001697 return FALSE;
1698 }
1699 return TRUE;
1700}
1701
1702/*
1703 * Test if "dpy" and x11_window are valid by getting the window title.
1704 * I don't actually want it yet, so there may be a simpler call to use, but
1705 * this will cause the error handler x_error_check() to be called if anything
1706 * is wrong, such as the window pointer being invalid (as can happen when the
1707 * user changes his DISPLAY, but not his WINDOWID) -- webb
1708 */
1709 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001710test_x11_window(Display *dpy)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001711{
1712 int (*old_handler)();
1713 XTextProperty text_prop;
1714
1715 old_handler = XSetErrorHandler(x_error_check);
1716 got_x_error = FALSE;
1717 if (XGetWMName(dpy, x11_window, &text_prop))
1718 XFree((void *)text_prop.value);
1719 XSync(dpy, False);
1720 (void)XSetErrorHandler(old_handler);
1721
1722 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001723 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001724
1725 return (got_x_error ? FAIL : OK);
1726}
1727#endif
1728
1729#ifdef FEAT_TITLE
1730
1731#ifdef FEAT_X11
1732
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01001733static int get_x11_thing(int get_title, int test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001734
1735/*
1736 * try to get x11 window and display
1737 *
1738 * return FAIL for failure, OK otherwise
1739 */
1740 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001741get_x11_windis(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001742{
1743 char *winid;
1744 static int result = -1;
1745#define XD_NONE 0 /* x11_display not set here */
1746#define XD_HERE 1 /* x11_display opened here */
1747#define XD_GUI 2 /* x11_display used from gui.dpy */
1748#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1749 static int x11_display_from = XD_NONE;
1750 static int did_set_error_handler = FALSE;
1751
1752 if (!did_set_error_handler)
1753 {
1754 /* X just exits if it finds an error otherwise! */
1755 (void)XSetErrorHandler(x_error_handler);
1756 did_set_error_handler = TRUE;
1757 }
1758
Bram Moolenaar9372a112005-12-06 19:59:18 +00001759#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001760 if (gui.in_use)
1761 {
1762 /*
1763 * If the X11 display was opened here before, for the window where Vim
1764 * was started, close that one now to avoid a memory leak.
1765 */
1766 if (x11_display_from == XD_HERE && x11_display != NULL)
1767 {
1768 XCloseDisplay(x11_display);
1769 x11_display_from = XD_NONE;
1770 }
1771 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1772 {
1773 x11_display_from = XD_GUI;
1774 return OK;
1775 }
1776 x11_display = NULL;
1777 return FAIL;
1778 }
1779 else if (x11_display_from == XD_GUI)
1780 {
1781 /* GUI must have stopped somehow, clear x11_display */
1782 x11_window = 0;
1783 x11_display = NULL;
1784 x11_display_from = XD_NONE;
1785 }
1786#endif
1787
1788 /* When started with the "-X" argument, don't try connecting. */
1789 if (!x_connect_to_server())
1790 return FAIL;
1791
1792 /*
1793 * If WINDOWID not set, should try another method to find out
1794 * what the current window number is. The only code I know for
1795 * this is very complicated.
1796 * We assume that zero is invalid for WINDOWID.
1797 */
1798 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1799 x11_window = (Window)atol(winid);
1800
1801#ifdef FEAT_XCLIPBOARD
1802 if (xterm_dpy != NULL && x11_window != 0)
1803 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001804 /* We may have checked it already, but Gnome terminal can move us to
1805 * another window, so we need to check every time. */
1806 if (x11_display_from != XD_XTERM)
1807 {
1808 /*
1809 * If the X11 display was opened here before, for the window where
1810 * Vim was started, close that one now to avoid a memory leak.
1811 */
1812 if (x11_display_from == XD_HERE && x11_display != NULL)
1813 XCloseDisplay(x11_display);
1814 x11_display = xterm_dpy;
1815 x11_display_from = XD_XTERM;
1816 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 if (test_x11_window(x11_display) == FAIL)
1818 {
1819 /* probably bad $WINDOWID */
1820 x11_window = 0;
1821 x11_display = NULL;
1822 x11_display_from = XD_NONE;
1823 return FAIL;
1824 }
1825 return OK;
1826 }
1827#endif
1828
1829 if (x11_window == 0 || x11_display == NULL)
1830 result = -1;
1831
1832 if (result != -1) /* Have already been here and set this */
1833 return result; /* Don't do all these X calls again */
1834
1835 if (x11_window != 0 && x11_display == NULL)
1836 {
1837#ifdef SET_SIG_ALARM
1838 RETSIGTYPE (*sig_save)();
1839#endif
1840#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1841 struct timeval start_tv;
1842
1843 if (p_verbose > 0)
1844 gettimeofday(&start_tv, NULL);
1845#endif
1846
1847#ifdef SET_SIG_ALARM
1848 /*
1849 * Opening the Display may hang if the DISPLAY setting is wrong, or
1850 * the network connection is bad. Set an alarm timer to get out.
1851 */
1852 sig_alarm_called = FALSE;
1853 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1854 (RETSIGTYPE (*)())sig_alarm);
1855 alarm(2);
1856#endif
1857 x11_display = XOpenDisplay(NULL);
1858
1859#ifdef SET_SIG_ALARM
1860 alarm(0);
1861 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1862 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001863 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001864#endif
1865 if (x11_display != NULL)
1866 {
1867# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1868 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001869 {
1870 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001871 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001872 verbose_leave();
1873 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874# endif
1875 if (test_x11_window(x11_display) == FAIL)
1876 {
1877 /* Maybe window id is bad */
1878 x11_window = 0;
1879 XCloseDisplay(x11_display);
1880 x11_display = NULL;
1881 }
1882 else
1883 x11_display_from = XD_HERE;
1884 }
1885 }
1886 if (x11_window == 0 || x11_display == NULL)
1887 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001888
1889# ifdef FEAT_EVAL
1890 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1891# endif
1892
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 return (result = OK);
1894}
1895
1896/*
1897 * Determine original x11 Window Title
1898 */
1899 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001900get_x11_title(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001901{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001902 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001903}
1904
1905/*
1906 * Determine original x11 Window icon
1907 */
1908 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001909get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001910{
1911 int retval = FALSE;
1912
1913 retval = get_x11_thing(FALSE, test_only);
1914
1915 /* could not get old icon, use terminal name */
1916 if (oldicon == NULL && !test_only)
1917 {
1918 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001919 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001920 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001921 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001922 }
1923
1924 return retval;
1925}
1926
1927 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01001928get_x11_thing(
1929 int get_title, /* get title string */
1930 int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001931{
1932 XTextProperty text_prop;
1933 int retval = FALSE;
1934 Status status;
1935
1936 if (get_x11_windis() == OK)
1937 {
1938 /* Get window/icon name if any */
1939 if (get_title)
1940 status = XGetWMName(x11_display, x11_window, &text_prop);
1941 else
1942 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1943
1944 /*
1945 * If terminal is xterm, then x11_window may be a child window of the
1946 * outer xterm window that actually contains the window/icon name, so
1947 * keep traversing up the tree until a window with a title/icon is
1948 * found.
1949 */
1950 /* Previously this was only done for xterm and alikes. I don't see a
1951 * reason why it would fail for other terminal emulators.
1952 * if (term_is_xterm) */
1953 {
1954 Window root;
1955 Window parent;
1956 Window win = x11_window;
1957 Window *children;
1958 unsigned int num_children;
1959
1960 while (!status || text_prop.value == NULL)
1961 {
1962 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1963 &num_children))
1964 break;
1965 if (children)
1966 XFree((void *)children);
1967 if (parent == root || parent == 0)
1968 break;
1969
1970 win = parent;
1971 if (get_title)
1972 status = XGetWMName(x11_display, win, &text_prop);
1973 else
1974 status = XGetWMIconName(x11_display, win, &text_prop);
1975 }
1976 }
1977 if (status && text_prop.value != NULL)
1978 {
1979 retval = TRUE;
1980 if (!test_only)
1981 {
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001982#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
1983 if (text_prop.encoding == XA_STRING
1984# ifdef FEAT_MBYTE
1985 && !has_mbyte
1986# endif
1987 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001988 {
1989#endif
1990 if (get_title)
1991 oldtitle = vim_strsave((char_u *)text_prop.value);
1992 else
1993 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001994#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001995 }
1996 else
1997 {
1998 char **cl;
1999 Status transform_status;
2000 int n = 0;
2001
2002 transform_status = XmbTextPropertyToTextList(x11_display,
2003 &text_prop,
2004 &cl, &n);
2005 if (transform_status >= Success && n > 0 && cl[0])
2006 {
2007 if (get_title)
2008 oldtitle = vim_strsave((char_u *) cl[0]);
2009 else
2010 oldicon = vim_strsave((char_u *) cl[0]);
2011 XFreeStringList(cl);
2012 }
2013 else
2014 {
2015 if (get_title)
2016 oldtitle = vim_strsave((char_u *)text_prop.value);
2017 else
2018 oldicon = vim_strsave((char_u *)text_prop.value);
2019 }
2020 }
2021#endif
2022 }
2023 XFree((void *)text_prop.value);
2024 }
2025 }
2026 return retval;
2027}
2028
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002029/* Xutf8 functions are not avaialble on older systems. Note that on some
2030 * systems X_HAVE_UTF8_STRING may be defined in a header file but
2031 * Xutf8SetWMProperties() is not in the X11 library. Configure checks for
2032 * that and defines HAVE_XUTF8SETWMPROPERTIES. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002033#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02002034# if X_HAVE_UTF8_STRING && HAVE_XUTF8SETWMPROPERTIES
Bram Moolenaar071d4272004-06-13 20:20:40 +00002035# define USE_UTF8_STRING
2036# endif
2037#endif
2038
2039/*
2040 * Set x11 Window Title
2041 *
2042 * get_x11_windis() must be called before this and have returned OK
2043 */
2044 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002045set_x11_title(char_u *title)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002046{
2047 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
2048 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
2049 * supported everywhere and STRING doesn't work for multi-byte titles.
2050 */
2051#ifdef USE_UTF8_STRING
2052 if (enc_utf8)
2053 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
2054 NULL, NULL, 0, NULL, NULL, NULL);
2055 else
2056#endif
2057 {
2058#if XtSpecificationRelease >= 4
2059# ifdef FEAT_XFONTSET
2060 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
2061 NULL, NULL, 0, NULL, NULL, NULL);
2062# else
2063 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002064 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002065
2066 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002067 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068 XSetWMProperties(x11_display, x11_window, &text_prop,
2069 NULL, NULL, 0, NULL, NULL, NULL);
2070# endif
2071#else
2072 XStoreName(x11_display, x11_window, (char *)title);
2073#endif
2074 }
2075 XFlush(x11_display);
2076}
2077
2078/*
2079 * Set x11 Window icon
2080 *
2081 * get_x11_windis() must be called before this and have returned OK
2082 */
2083 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01002084set_x11_icon(char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002085{
2086 /* See above for comments about using X*SetWMProperties(). */
2087#ifdef USE_UTF8_STRING
2088 if (enc_utf8)
2089 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2090 NULL, 0, NULL, NULL, NULL);
2091 else
2092#endif
2093 {
2094#if XtSpecificationRelease >= 4
2095# ifdef FEAT_XFONTSET
2096 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2097 NULL, 0, NULL, NULL, NULL);
2098# else
2099 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002100 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002101
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002102 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2104 NULL, 0, NULL, NULL, NULL);
2105# endif
2106#else
2107 XSetIconName(x11_display, x11_window, (char *)icon);
2108#endif
2109 }
2110 XFlush(x11_display);
2111}
2112
2113#else /* FEAT_X11 */
2114
Bram Moolenaar071d4272004-06-13 20:20:40 +00002115 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002116get_x11_title(int test_only UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002117{
2118 return FALSE;
2119}
2120
2121 static int
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002122get_x11_icon(int test_only)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002123{
2124 if (!test_only)
2125 {
2126 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002127 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002128 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002129 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002130 }
2131 return FALSE;
2132}
2133
2134#endif /* FEAT_X11 */
2135
2136 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002137mch_can_restore_title(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002138{
2139 return get_x11_title(TRUE);
2140}
2141
2142 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002143mch_can_restore_icon(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002144{
2145 return get_x11_icon(TRUE);
2146}
2147
2148/*
2149 * Set the window title and icon.
2150 */
2151 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002152mch_settitle(char_u *title, char_u *icon)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002153{
2154 int type = 0;
2155 static int recursive = 0;
2156
2157 if (T_NAME == NULL) /* no terminal name (yet) */
2158 return;
2159 if (title == NULL && icon == NULL) /* nothing to do */
2160 return;
2161
2162 /* When one of the X11 functions causes a deadly signal, we get here again
2163 * recursively. Avoid hanging then (something is probably locked). */
2164 if (recursive)
2165 return;
2166 ++recursive;
2167
2168 /*
2169 * if the window ID and the display is known, we may use X11 calls
2170 */
2171#ifdef FEAT_X11
2172 if (get_x11_windis() == OK)
2173 type = 1;
2174#else
2175# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2176 if (gui.in_use)
2177 type = 1;
2178# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002179#endif
2180
2181 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002182 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002183 * than x11 calls, because the x11 calls don't always work
2184 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002185 if ((type || *T_TS != NUL) && title != NULL)
2186 {
2187 if (oldtitle == NULL
2188#ifdef FEAT_GUI
2189 && !gui.in_use
2190#endif
2191 ) /* first call but not in GUI, save title */
2192 (void)get_x11_title(FALSE);
2193
2194 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2195 term_settitle(title);
2196#ifdef FEAT_X11
2197 else
2198# ifdef FEAT_GUI_GTK
2199 if (!gui.in_use) /* don't do this if GTK+ is running */
2200# endif
2201 set_x11_title(title); /* x11 */
2202#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002203#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002204 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2205 else
2206 gui_mch_settitle(title, icon);
2207#endif
2208 did_set_title = TRUE;
2209 }
2210
2211 if ((type || *T_CIS != NUL) && icon != NULL)
2212 {
2213 if (oldicon == NULL
2214#ifdef FEAT_GUI
2215 && !gui.in_use
2216#endif
2217 ) /* first call, save icon */
2218 get_x11_icon(FALSE);
2219
2220 if (*T_CIS != NUL)
2221 {
2222 out_str(T_CIS); /* set icon start */
2223 out_str_nf(icon);
2224 out_str(T_CIE); /* set icon end */
2225 out_flush();
2226 }
2227#ifdef FEAT_X11
2228 else
2229# ifdef FEAT_GUI_GTK
2230 if (!gui.in_use) /* don't do this if GTK+ is running */
2231# endif
2232 set_x11_icon(icon); /* x11 */
2233#endif
2234 did_set_icon = TRUE;
2235 }
2236 --recursive;
2237}
2238
2239/*
2240 * Restore the window/icon title.
2241 * "which" is one of:
2242 * 1 only restore title
2243 * 2 only restore icon
2244 * 3 restore title and icon
2245 */
2246 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002247mch_restore_title(int which)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248{
2249 /* only restore the title or icon when it has been set */
2250 mch_settitle(((which & 1) && did_set_title) ?
2251 (oldtitle ? oldtitle : p_titleold) : NULL,
2252 ((which & 2) && did_set_icon) ? oldicon : NULL);
2253}
2254
2255#endif /* FEAT_TITLE */
2256
2257/*
2258 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002259 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002260 */
2261 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002262vim_is_xterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002263{
2264 if (name == NULL)
2265 return FALSE;
2266 return (STRNICMP(name, "xterm", 5) == 0
2267 || STRNICMP(name, "nxterm", 6) == 0
2268 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002269 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270 || STRNICMP(name, "rxvt", 4) == 0
2271 || STRCMP(name, "builtin_xterm") == 0);
2272}
2273
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002274#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2275/*
2276 * Return TRUE if "name" appears to be that of a terminal
2277 * known to support the xterm-style mouse protocol.
2278 * Relies on term_is_xterm having been set to its correct value.
2279 */
2280 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002281use_xterm_like_mouse(char_u *name)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002282{
2283 return (name != NULL
Bram Moolenaare56132b2016-08-14 18:23:21 +02002284 && (term_is_xterm
2285 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002286 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaare56132b2016-08-14 18:23:21 +02002287 || STRICMP(name, "st") == 0
2288 || STRNICMP(name, "st-", 3) == 0
2289 || STRNICMP(name, "stterm", 6) == 0));
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002290}
2291#endif
2292
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2294/*
2295 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2296 * Return 1 for "xterm".
2297 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002298 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002299 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002300 */
2301 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002302use_xterm_mouse(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002304 if (ttym_flags == TTYM_SGR)
2305 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002306 if (ttym_flags == TTYM_URXVT)
2307 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308 if (ttym_flags == TTYM_XTERM2)
2309 return 2;
2310 if (ttym_flags == TTYM_XTERM)
2311 return 1;
2312 return 0;
2313}
2314#endif
2315
2316 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002317vim_is_iris(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002318{
2319 if (name == NULL)
2320 return FALSE;
2321 return (STRNICMP(name, "iris-ansi", 9) == 0
2322 || STRCMP(name, "builtin_iris-ansi") == 0);
2323}
2324
2325 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002326vim_is_vt300(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327{
2328 if (name == NULL)
2329 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002330 /* catch VT100 - VT5xx */
2331 return ((STRNICMP(name, "vt", 2) == 0
2332 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333 || STRCMP(name, "builtin_vt320") == 0);
2334}
2335
2336/*
2337 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2338 * This should include all windowed terminal emulators.
2339 */
2340 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002341vim_is_fastterm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342{
2343 if (name == NULL)
2344 return FALSE;
2345 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2346 return TRUE;
2347 return ( STRNICMP(name, "hpterm", 6) == 0
2348 || STRNICMP(name, "sun-cmd", 7) == 0
2349 || STRNICMP(name, "screen", 6) == 0
Bram Moolenaar0ba40702016-10-12 14:50:54 +02002350 || STRNICMP(name, "tmux", 4) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002351 || STRNICMP(name, "dtterm", 6) == 0);
2352}
2353
2354/*
2355 * Insert user name in s[len].
2356 * Return OK if a name found.
2357 */
2358 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002359mch_get_user_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360{
2361#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002362 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 return OK;
2364#else
2365 return mch_get_uname(getuid(), s, len);
2366#endif
2367}
2368
2369/*
2370 * Insert user name for "uid" in s[len].
2371 * Return OK if a name found.
2372 */
2373 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002374mch_get_uname(uid_t uid, char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002375{
2376#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2377 struct passwd *pw;
2378
2379 if ((pw = getpwuid(uid)) != NULL
2380 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2381 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002382 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383 return OK;
2384 }
2385#endif
2386 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2387 return FAIL; /* a number is not a name */
2388}
2389
2390/*
2391 * Insert host name is s[len].
2392 */
2393
2394#ifdef HAVE_SYS_UTSNAME_H
2395 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002396mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002397{
2398 struct utsname vutsname;
2399
2400 if (uname(&vutsname) < 0)
2401 *s = NUL;
2402 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002403 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002404}
2405#else /* HAVE_SYS_UTSNAME_H */
2406
2407# ifdef HAVE_SYS_SYSTEMINFO_H
2408# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2409# endif
2410
2411 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002412mch_get_host_name(char_u *s, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002413{
2414# ifdef VAXC
2415 vaxc$gethostname((char *)s, len);
2416# else
2417 gethostname((char *)s, len);
2418# endif
2419 s[len - 1] = NUL; /* make sure it's terminated */
2420}
2421#endif /* HAVE_SYS_UTSNAME_H */
2422
2423/*
2424 * return process ID
2425 */
2426 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002427mch_get_pid(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002428{
2429 return (long)getpid();
2430}
2431
2432#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01002433static char *strerror(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434
2435 static char *
Bram Moolenaar05540972016-01-30 20:31:25 +01002436strerror(int err)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437{
2438 extern int sys_nerr;
2439 extern char *sys_errlist[];
2440 static char er[20];
2441
2442 if (err > 0 && err < sys_nerr)
2443 return (sys_errlist[err]);
2444 sprintf(er, "Error %d", err);
2445 return er;
2446}
2447#endif
2448
2449/*
2450 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2451 * Return OK for success, FAIL for failure.
2452 */
2453 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002454mch_dirname(char_u *buf, int len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002455{
2456#if defined(USE_GETCWD)
2457 if (getcwd((char *)buf, len) == NULL)
2458 {
2459 STRCPY(buf, strerror(errno));
2460 return FAIL;
2461 }
2462 return OK;
2463#else
2464 return (getwd((char *)buf) != NULL ? OK : FAIL);
2465#endif
2466}
2467
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002469 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 *
2471 * return FAIL for failure, OK for success
2472 */
2473 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002474mch_FullName(
2475 char_u *fname,
2476 char_u *buf,
2477 int len,
2478 int force) /* also expand when already absolute path */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479{
2480 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002481#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 int fd = -1;
2483 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002484#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002485 char_u olddir[MAXPATHL];
2486 char_u *p;
2487 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002488#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002489 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2490 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002491#endif
2492
Bram Moolenaar38323e42007-03-06 19:22:53 +00002493#ifdef VMS
2494 fname = vms_fixfilename(fname);
2495#endif
2496
Bram Moolenaara2442432007-04-26 14:26:37 +00002497#ifdef __CYGWIN__
2498 /*
2499 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2500 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002501# if CYGWIN_VERSION_DLL_MAJOR >= 1007
Bram Moolenaar06b07342015-12-31 22:26:28 +01002502 /* Use CCP_RELATIVE to avoid that it sometimes returns a path that ends in
2503 * a forward slash. */
2504 cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_RELATIVE,
2505 fname, posix_fname, MAXPATHL);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002506# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002507 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002508# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002509 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002510#endif
2511
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002512 /* Expand it if forced or not an absolute path.
2513 * Do not do it for "/file", the result is always "/". */
2514 if ((force || !mch_isFullName(fname))
2515 && ((p = vim_strrchr(fname, '/')) == NULL || p != fname))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002516 {
2517 /*
2518 * If the file name has a path, change to that directory for a moment,
2519 * and then do the getwd() (and get back to where we were).
2520 * This will get the correct path name with "../" things.
2521 */
Bram Moolenaare3303cb2015-12-31 18:29:46 +01002522 if (p != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002523 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002524#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002525 /*
2526 * Use fchdir() if possible, it's said to be faster and more
2527 * reliable. But on SunOS 4 it might not work. Check this by
2528 * doing a fchdir() right now.
2529 */
2530 if (!dont_fchdir)
2531 {
2532 fd = open(".", O_RDONLY | O_EXTRA, 0);
2533 if (fd >= 0 && fchdir(fd) < 0)
2534 {
2535 close(fd);
2536 fd = -1;
2537 dont_fchdir = TRUE; /* don't try again */
2538 }
2539 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002540#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541
2542 /* Only change directory when we are sure we can return to where
2543 * we are now. After doing "su" chdir(".") might not work. */
2544 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002545#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002546 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002547#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548 (mch_dirname(olddir, MAXPATHL) == FAIL
2549 || mch_chdir((char *)olddir) != 0))
2550 {
2551 p = NULL; /* can't get current dir: don't chdir */
2552 retval = FAIL;
2553 }
2554 else
2555 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556 /* The directory is copied into buf[], to be able to remove
2557 * the file name without changing it (could be a string in
2558 * read-only memory) */
2559 if (p - fname >= len)
2560 retval = FAIL;
2561 else
2562 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002563 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564 if (mch_chdir((char *)buf))
2565 retval = FAIL;
2566 else
2567 fname = p + 1;
2568 *buf = NUL;
2569 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570 }
2571 }
2572 if (mch_dirname(buf, len) == FAIL)
2573 {
2574 retval = FAIL;
2575 *buf = NUL;
2576 }
2577 if (p != NULL)
2578 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002579#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002580 if (fd >= 0)
2581 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002582 if (p_verbose >= 5)
2583 {
2584 verbose_enter();
2585 MSG("fchdir() to previous dir");
2586 verbose_leave();
2587 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588 l = fchdir(fd);
2589 close(fd);
2590 }
2591 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002592#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002593 l = mch_chdir((char *)olddir);
2594 if (l != 0)
2595 EMSG(_(e_prev_dir));
2596 }
2597
2598 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002599 if (l >= len - 1)
2600 retval = FAIL; /* no space for trailing "/" */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002601#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002602 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002603 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002604 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002605#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002607
Bram Moolenaar071d4272004-06-13 20:20:40 +00002608 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002609 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002610 return FAIL;
2611
2612 /* Do not append ".", "/dir/." is equal to "/dir". */
2613 if (STRCMP(fname, ".") != 0)
2614 STRCAT(buf, fname);
2615
2616 return OK;
2617}
2618
2619/*
2620 * Return TRUE if "fname" does not depend on the current directory.
2621 */
2622 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002623mch_isFullName(char_u *fname)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624{
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002625#ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 return ( fname[0] == '/' || fname[0] == '.' ||
2627 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2628 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2629 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
Bram Moolenaara06ecab2016-07-16 14:47:36 +02002630#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002631 return (*fname == '/' || *fname == '~');
Bram Moolenaar071d4272004-06-13 20:20:40 +00002632#endif
2633}
2634
Bram Moolenaar24552be2005-12-10 20:17:30 +00002635#if defined(USE_FNAME_CASE) || defined(PROTO)
2636/*
2637 * Set the case of the file name, if it already exists. This will cause the
2638 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002639 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002640 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002641 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002642fname_case(
2643 char_u *name,
2644 int len UNUSED) /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002645{
2646 struct stat st;
2647 char_u *slash, *tail;
2648 DIR *dirp;
2649 struct dirent *dp;
2650
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002651 if (mch_lstat((char *)name, &st) >= 0)
Bram Moolenaar24552be2005-12-10 20:17:30 +00002652 {
2653 /* Open the directory where the file is located. */
2654 slash = vim_strrchr(name, '/');
2655 if (slash == NULL)
2656 {
2657 dirp = opendir(".");
2658 tail = name;
2659 }
2660 else
2661 {
2662 *slash = NUL;
2663 dirp = opendir((char *)name);
2664 *slash = '/';
2665 tail = slash + 1;
2666 }
2667
2668 if (dirp != NULL)
2669 {
2670 while ((dp = readdir(dirp)) != NULL)
2671 {
2672 /* Only accept names that differ in case and are the same byte
2673 * length. TODO: accept different length name. */
2674 if (STRICMP(tail, dp->d_name) == 0
2675 && STRLEN(tail) == STRLEN(dp->d_name))
2676 {
2677 char_u newname[MAXPATHL + 1];
2678 struct stat st2;
2679
2680 /* Verify the inode is equal. */
2681 vim_strncpy(newname, name, MAXPATHL);
2682 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2683 MAXPATHL - (tail - name));
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01002684 if (mch_lstat((char *)newname, &st2) >= 0
Bram Moolenaar24552be2005-12-10 20:17:30 +00002685 && st.st_ino == st2.st_ino
2686 && st.st_dev == st2.st_dev)
2687 {
2688 STRCPY(tail, dp->d_name);
2689 break;
2690 }
2691 }
2692 }
2693
2694 closedir(dirp);
2695 }
2696 }
2697}
2698#endif
2699
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700/*
2701 * Get file permissions for 'name'.
2702 * Returns -1 when it doesn't exist.
2703 */
2704 long
Bram Moolenaar05540972016-01-30 20:31:25 +01002705mch_getperm(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002706{
2707 struct stat statb;
2708
2709 /* Keep the #ifdef outside of stat(), it may be a macro. */
2710#ifdef VMS
2711 if (stat((char *)vms_fixfilename(name), &statb))
2712#else
2713 if (stat((char *)name, &statb))
2714#endif
2715 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002716#ifdef __INTERIX
2717 /* The top bit makes the value negative, which means the file doesn't
2718 * exist. Remove the bit, we don't use it. */
2719 return statb.st_mode & ~S_ADDACE;
2720#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002721 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002722#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002723}
2724
2725/*
2726 * set file permission for 'name' to 'perm'
2727 *
2728 * return FAIL for failure, OK otherwise
2729 */
2730 int
Bram Moolenaar05540972016-01-30 20:31:25 +01002731mch_setperm(char_u *name, long perm)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002732{
2733 return (chmod((char *)
2734#ifdef VMS
2735 vms_fixfilename(name),
2736#else
2737 name,
2738#endif
2739 (mode_t)perm) == 0 ? OK : FAIL);
2740}
2741
2742#if defined(HAVE_ACL) || defined(PROTO)
2743# ifdef HAVE_SYS_ACL_H
2744# include <sys/acl.h>
2745# endif
2746# ifdef HAVE_SYS_ACCESS_H
2747# include <sys/access.h>
2748# endif
2749
2750# ifdef HAVE_SOLARIS_ACL
2751typedef struct vim_acl_solaris_T {
2752 int acl_cnt;
2753 aclent_t *acl_entry;
2754} vim_acl_solaris_T;
2755# endif
2756
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002757#if defined(HAVE_SELINUX) || defined(PROTO)
2758/*
2759 * Copy security info from "from_file" to "to_file".
2760 */
2761 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002762mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002763{
2764 if (from_file == NULL)
2765 return;
2766
2767 if (selinux_enabled == -1)
2768 selinux_enabled = is_selinux_enabled();
2769
2770 if (selinux_enabled > 0)
2771 {
2772 security_context_t from_context = NULL;
2773 security_context_t to_context = NULL;
2774
2775 if (getfilecon((char *)from_file, &from_context) < 0)
2776 {
2777 /* If the filesystem doesn't support extended attributes,
2778 the original had no special security context and the
2779 target cannot have one either. */
2780 if (errno == EOPNOTSUPP)
2781 return;
2782
2783 MSG_PUTS(_("\nCould not get security context for "));
2784 msg_outtrans(from_file);
2785 msg_putchar('\n');
2786 return;
2787 }
2788 if (getfilecon((char *)to_file, &to_context) < 0)
2789 {
2790 MSG_PUTS(_("\nCould not get security context for "));
2791 msg_outtrans(to_file);
2792 msg_putchar('\n');
2793 freecon (from_context);
2794 return ;
2795 }
2796 if (strcmp(from_context, to_context) != 0)
2797 {
2798 if (setfilecon((char *)to_file, from_context) < 0)
2799 {
2800 MSG_PUTS(_("\nCould not set security context for "));
2801 msg_outtrans(to_file);
2802 msg_putchar('\n');
2803 }
2804 }
2805 freecon(to_context);
2806 freecon(from_context);
2807 }
2808}
2809#endif /* HAVE_SELINUX */
2810
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002811#if defined(HAVE_SMACK) && !defined(PROTO)
2812/*
2813 * Copy security info from "from_file" to "to_file".
2814 */
2815 void
Bram Moolenaard14e00e2016-01-31 17:30:51 +01002816mch_copy_sec(char_u *from_file, char_u *to_file)
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002817{
Bram Moolenaar62f167f2014-04-23 12:52:40 +02002818 static const char * const smack_copied_attributes[] =
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002819 {
2820 XATTR_NAME_SMACK,
2821 XATTR_NAME_SMACKEXEC,
2822 XATTR_NAME_SMACKMMAP
2823 };
2824
2825 char buffer[SMACK_LABEL_LEN];
2826 const char *name;
2827 int index;
2828 int ret;
2829 ssize_t size;
2830
2831 if (from_file == NULL)
2832 return;
2833
2834 for (index = 0 ; index < (int)(sizeof(smack_copied_attributes)
2835 / sizeof(smack_copied_attributes)[0]) ; index++)
2836 {
2837 /* get the name of the attribute to copy */
2838 name = smack_copied_attributes[index];
2839
2840 /* get the value of the attribute in buffer */
2841 size = getxattr((char*)from_file, name, buffer, sizeof(buffer));
2842 if (size >= 0)
2843 {
2844 /* copy the attribute value of buffer */
2845 ret = setxattr((char*)to_file, name, buffer, (size_t)size, 0);
2846 if (ret < 0)
2847 {
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002848 vim_snprintf((char *)IObuff, IOSIZE,
2849 _("Could not set security context %s for %s"),
2850 name, to_file);
2851 msg_outtrans(IObuff);
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002852 msg_putchar('\n');
2853 }
2854 }
2855 else
2856 {
2857 /* what reason of not having the attribute value? */
2858 switch (errno)
2859 {
2860 case ENOTSUP:
2861 /* extended attributes aren't supported or enabled */
2862 /* should a message be echoed? not sure... */
2863 return; /* leave because it isn't usefull to continue */
2864
2865 case ERANGE:
2866 default:
2867 /* no enough size OR unexpected error */
Bram Moolenaar4a1314c2016-01-27 20:47:18 +01002868 vim_snprintf((char *)IObuff, IOSIZE,
2869 _("Could not get security context %s for %s. Removing it!"),
2870 name, from_file);
2871 msg_puts(IObuff);
2872 msg_putchar('\n');
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002873 /* FALLTHROUGH to remove the attribute */
2874
2875 case ENODATA:
2876 /* no attribute of this name */
2877 ret = removexattr((char*)to_file, name);
Bram Moolenaar57a728d2014-04-02 23:09:26 +02002878 /* Silently ignore errors, apparently this happens when
2879 * smack is not actually being used. */
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002880 break;
2881 }
2882 }
2883 }
2884}
2885#endif /* HAVE_SMACK */
2886
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887/*
2888 * Return a pointer to the ACL of file "fname" in allocated memory.
2889 * Return NULL if the ACL is not available for whatever reason.
2890 */
2891 vim_acl_T
Bram Moolenaar05540972016-01-30 20:31:25 +01002892mch_get_acl(char_u *fname UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893{
2894 vim_acl_T ret = NULL;
2895#ifdef HAVE_POSIX_ACL
2896 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2897#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002898#ifdef HAVE_SOLARIS_ZFS_ACL
2899 acl_t *aclent;
2900
2901 if (acl_get((char *)fname, 0, &aclent) < 0)
2902 return NULL;
2903 ret = (vim_acl_T)aclent;
2904#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905#ifdef HAVE_SOLARIS_ACL
2906 vim_acl_solaris_T *aclent;
2907
2908 aclent = malloc(sizeof(vim_acl_solaris_T));
2909 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2910 {
2911 free(aclent);
2912 return NULL;
2913 }
2914 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2915 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2916 {
2917 free(aclent->acl_entry);
2918 free(aclent);
2919 return NULL;
2920 }
2921 ret = (vim_acl_T)aclent;
2922#else
2923#if defined(HAVE_AIX_ACL)
2924 int aclsize;
2925 struct acl *aclent;
2926
2927 aclsize = sizeof(struct acl);
2928 aclent = malloc(aclsize);
2929 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2930 {
2931 if (errno == ENOSPC)
2932 {
2933 aclsize = aclent->acl_len;
2934 aclent = realloc(aclent, aclsize);
2935 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2936 {
2937 free(aclent);
2938 return NULL;
2939 }
2940 }
2941 else
2942 {
2943 free(aclent);
2944 return NULL;
2945 }
2946 }
2947 ret = (vim_acl_T)aclent;
2948#endif /* HAVE_AIX_ACL */
2949#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002950#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951#endif /* HAVE_POSIX_ACL */
2952 return ret;
2953}
2954
2955/*
2956 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2957 */
2958 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002959mch_set_acl(char_u *fname UNUSED, vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002960{
2961 if (aclent == NULL)
2962 return;
2963#ifdef HAVE_POSIX_ACL
2964 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2965#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002966#ifdef HAVE_SOLARIS_ZFS_ACL
2967 acl_set((char *)fname, (acl_t *)aclent);
2968#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002969#ifdef HAVE_SOLARIS_ACL
2970 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2971 ((vim_acl_solaris_T *)aclent)->acl_entry);
2972#else
2973#ifdef HAVE_AIX_ACL
2974 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2975#endif /* HAVE_AIX_ACL */
2976#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002977#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002978#endif /* HAVE_POSIX_ACL */
2979}
2980
2981 void
Bram Moolenaar05540972016-01-30 20:31:25 +01002982mch_free_acl(vim_acl_T aclent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002983{
2984 if (aclent == NULL)
2985 return;
2986#ifdef HAVE_POSIX_ACL
2987 acl_free((acl_t)aclent);
2988#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002989#ifdef HAVE_SOLARIS_ZFS_ACL
2990 acl_free((acl_t *)aclent);
2991#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002992#ifdef HAVE_SOLARIS_ACL
2993 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2994 free(aclent);
2995#else
2996#ifdef HAVE_AIX_ACL
2997 free(aclent);
2998#endif /* HAVE_AIX_ACL */
2999#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003000#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003001#endif /* HAVE_POSIX_ACL */
3002}
3003#endif
3004
3005/*
3006 * Set hidden flag for "name".
3007 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003008 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003009mch_hide(char_u *name UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010{
3011 /* can't hide a file */
3012}
3013
3014/*
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003015 * return TRUE if "name" is a directory or a symlink to a directory
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016 * return FALSE if "name" is not a directory
3017 * return FALSE for error
3018 */
3019 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003020mch_isdir(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003021{
3022 struct stat statb;
3023
3024 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
3025 return FALSE;
3026 if (stat((char *)name, &statb))
3027 return FALSE;
3028#ifdef _POSIX_SOURCE
3029 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
3030#else
3031 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
3032#endif
3033}
3034
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003035/*
3036 * return TRUE if "name" is a directory, NOT a symlink to a directory
3037 * return FALSE if "name" is not a directory
3038 * return FALSE for error
3039 */
3040 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003041mch_isrealdir(char_u *name)
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003042{
3043 struct stat statb;
3044
3045 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
3046 return FALSE;
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01003047 if (mch_lstat((char *)name, &statb))
Bram Moolenaar43a34f92016-01-17 15:56:34 +01003048 return FALSE;
3049#ifdef _POSIX_SOURCE
3050 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
3051#else
3052 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
3053#endif
3054}
3055
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01003056static int executable_file(char_u *name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057
3058/*
3059 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
3060 */
3061 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01003062executable_file(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003063{
3064 struct stat st;
3065
3066 if (stat((char *)name, &st))
3067 return 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003068#ifdef VMS
3069 /* Like on Unix system file can have executable rights but not necessarily
3070 * be an executable, but on Unix is not a default for an ordianry file to
3071 * have an executable flag - on VMS it is in most cases.
3072 * Therefore, this check does not have any sense - let keep us to the
3073 * conventions instead:
3074 * *.COM and *.EXE files are the executables - the rest are not. This is
3075 * not ideal but better then it was.
3076 */
3077 int vms_executable = 0;
3078 if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
3079 {
3080 if (strstr(vms_tolower((char*)name),".exe") != NULL
3081 || strstr(vms_tolower((char*)name),".com")!= NULL)
3082 vms_executable = 1;
3083 }
3084 return vms_executable;
3085#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003086 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003087#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003088}
3089
3090/*
3091 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
Bram Moolenaarb5971142015-03-21 17:32:19 +01003092 * If "use_path" is FALSE only check if "name" is executable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093 * Return -1 if unknown.
3094 */
3095 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003096mch_can_exe(char_u *name, char_u **path, int use_path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003097{
3098 char_u *buf;
3099 char_u *p, *e;
3100 int retval;
3101
Bram Moolenaarb5971142015-03-21 17:32:19 +01003102 /* When "use_path" is false and if it's an absolute or relative path don't
3103 * need to use $PATH. */
3104 if (!use_path || mch_isFullName(name) || (name[0] == '.'
3105 && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))))
Bram Moolenaar206f0112014-03-12 16:51:55 +01003106 {
Bram Moolenaarb5971142015-03-21 17:32:19 +01003107 /* There must be a path separator, files in the current directory
3108 * can't be executed. */
3109 if (gettail(name) != name && executable_file(name))
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003110 {
3111 if (path != NULL)
3112 {
3113 if (name[0] == '.')
3114 *path = FullName_save(name, TRUE);
3115 else
3116 *path = vim_strsave(name);
3117 }
3118 return TRUE;
3119 }
3120 return FALSE;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003121 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003122
3123 p = (char_u *)getenv("PATH");
3124 if (p == NULL || *p == NUL)
3125 return -1;
3126 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
3127 if (buf == NULL)
3128 return -1;
3129
3130 /*
3131 * Walk through all entries in $PATH to check if "name" exists there and
3132 * is an executable file.
3133 */
3134 for (;;)
3135 {
3136 e = (char_u *)strchr((char *)p, ':');
3137 if (e == NULL)
3138 e = p + STRLEN(p);
3139 if (e - p <= 1) /* empty entry means current dir */
3140 STRCPY(buf, "./");
3141 else
3142 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003143 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003144 add_pathsep(buf);
3145 }
3146 STRCAT(buf, name);
3147 retval = executable_file(buf);
3148 if (retval == 1)
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003149 {
3150 if (path != NULL)
3151 {
3152 if (buf[0] == '.')
3153 *path = FullName_save(buf, TRUE);
3154 else
3155 *path = vim_strsave(buf);
3156 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003157 break;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003158 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159
3160 if (*e != ':')
3161 break;
3162 p = e + 1;
3163 }
3164
3165 vim_free(buf);
3166 return retval;
3167}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003168
3169/*
3170 * Check what "name" is:
3171 * NODE_NORMAL: file or directory (or doesn't exist)
3172 * NODE_WRITABLE: writable device, socket, fifo, etc.
3173 * NODE_OTHER: non-writable things
3174 */
3175 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003176mch_nodetype(char_u *name)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003177{
3178 struct stat st;
3179
3180 if (stat((char *)name, &st))
3181 return NODE_NORMAL;
3182 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3183 return NODE_NORMAL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003184 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
3185 return NODE_OTHER;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003186 /* Everything else is writable? */
3187 return NODE_WRITABLE;
3188}
3189
3190 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003191mch_early_init(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192{
3193#ifdef HAVE_CHECK_STACK_GROWTH
3194 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003195
Bram Moolenaar071d4272004-06-13 20:20:40 +00003196 check_stack_growth((char *)&i);
3197
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003198# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003199 get_stack_limit();
3200# endif
3201
3202#endif
3203
3204 /*
3205 * Setup an alternative stack for signals. Helps to catch signals when
3206 * running out of stack space.
3207 * Use of sigaltstack() is preferred, it's more portable.
3208 * Ignore any errors.
3209 */
3210#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00003211 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212 init_signal_stack();
3213#endif
3214}
3215
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003216#if defined(EXITFREE) || defined(PROTO)
3217 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003218mch_free_mem(void)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003219{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003220# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3221 if (clip_star.owned)
3222 clip_lose_selection(&clip_star);
3223 if (clip_plus.owned)
3224 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003225# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003226# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003227 if (xterm_Shell != (Widget)0)
3228 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003229# ifndef LESSTIF_VERSION
3230 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003231 if (xterm_dpy != NULL)
3232 XtCloseDisplay(xterm_dpy);
3233 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003234 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003235 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003236# ifdef FEAT_X11
3237 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
3238# endif
3239 }
3240# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003241# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003242# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003243 if (x11_display != NULL
3244# ifdef FEAT_XCLIPBOARD
3245 && x11_display != xterm_dpy
3246# endif
3247 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003248 XCloseDisplay(x11_display);
3249# endif
3250# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
3251 vim_free(signal_stack);
3252 signal_stack = NULL;
3253# endif
3254# ifdef FEAT_TITLE
3255 vim_free(oldtitle);
3256 vim_free(oldicon);
3257# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003258}
3259#endif
3260
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01003261static void exit_scroll(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262
3263/*
3264 * Output a newline when exiting.
3265 * Make sure the newline goes to the same stream as the text.
3266 */
3267 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003268exit_scroll(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003269{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003270 if (silent_mode)
3271 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003272 if (newline_on_exit || msg_didout)
3273 {
3274 if (msg_use_printf())
3275 {
3276 if (info_message)
3277 mch_msg("\n");
3278 else
3279 mch_errmsg("\r\n");
3280 }
3281 else
3282 out_char('\n');
3283 }
3284 else
3285 {
3286 restore_cterm_colors(); /* get original colors back */
3287 msg_clr_eos_force(); /* clear the rest of the display */
3288 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3289 }
3290}
3291
3292 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003293mch_exit(int r)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003294{
3295 exiting = TRUE;
3296
3297#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3298 x11_export_final_selection();
3299#endif
3300
3301#ifdef FEAT_GUI
3302 if (!gui.in_use)
3303#endif
3304 {
3305 settmode(TMODE_COOK);
3306#ifdef FEAT_TITLE
3307 mch_restore_title(3); /* restore xterm title and icon name */
3308#endif
3309 /*
3310 * When t_ti is not empty but it doesn't cause swapping terminal
3311 * pages, need to output a newline when msg_didout is set. But when
3312 * t_ti does swap pages it should not go to the shell page. Do this
3313 * before stoptermcap().
3314 */
3315 if (swapping_screen() && !newline_on_exit)
3316 exit_scroll();
3317
3318 /* Stop termcap: May need to check for T_CRV response, which
3319 * requires RAW mode. */
3320 stoptermcap();
3321
3322 /*
3323 * A newline is only required after a message in the alternate screen.
3324 * This is set to TRUE by wait_return().
3325 */
3326 if (!swapping_screen() || newline_on_exit)
3327 exit_scroll();
3328
3329 /* Cursor may have been switched off without calling starttermcap()
3330 * when doing "vim -u vimrc" and vimrc contains ":q". */
3331 if (full_screen)
3332 cursor_on();
3333 }
3334 out_flush();
3335 ml_close_all(TRUE); /* remove all memfiles */
3336 may_core_dump();
3337#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003338 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 gui_exit(r);
3340#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003341
Bram Moolenaar56718732006-03-15 22:53:57 +00003342#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003343 mac_conv_cleanup();
3344#endif
3345
Bram Moolenaar071d4272004-06-13 20:20:40 +00003346#ifdef __QNX__
3347 /* A core dump won't be created if the signal handler
3348 * doesn't return, so we can't call exit() */
3349 if (deadly_signal != 0)
3350 return;
3351#endif
3352
Bram Moolenaar009b2592004-10-24 19:18:58 +00003353#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003354 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003355#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003356
3357#ifdef EXITFREE
3358 free_all_mem();
3359#endif
3360
Bram Moolenaar071d4272004-06-13 20:20:40 +00003361 exit(r);
3362}
3363
3364 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01003365may_core_dump(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003366{
3367 if (deadly_signal != 0)
3368 {
3369 signal(deadly_signal, SIG_DFL);
3370 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3371 }
3372}
3373
3374#ifndef VMS
3375
3376 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003377mch_settmode(int tmode)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003378{
3379 static int first = TRUE;
3380
3381 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3382#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3383 /*
3384 * for "new" tty systems
3385 */
3386# ifdef HAVE_TERMIOS_H
3387 static struct termios told;
3388 struct termios tnew;
3389# else
3390 static struct termio told;
3391 struct termio tnew;
3392# endif
3393
3394 if (first)
3395 {
3396 first = FALSE;
3397# if defined(HAVE_TERMIOS_H)
3398 tcgetattr(read_cmd_fd, &told);
3399# else
3400 ioctl(read_cmd_fd, TCGETA, &told);
3401# endif
3402 }
3403
3404 tnew = told;
3405 if (tmode == TMODE_RAW)
3406 {
3407 /*
3408 * ~ICRNL enables typing ^V^M
3409 */
3410 tnew.c_iflag &= ~ICRNL;
3411 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3412# if defined(IEXTEN) && !defined(__MINT__)
3413 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3414 /* but it breaks function keys on MINT */
3415# endif
3416 );
3417# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3418 tnew.c_oflag &= ~ONLCR;
3419# endif
3420 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3421 tnew.c_cc[VTIME] = 0; /* don't wait */
3422 }
3423 else if (tmode == TMODE_SLEEP)
Bram Moolenaar40de4562016-07-01 15:03:46 +02003424 {
3425 /* Also reset ICANON here, otherwise on Solaris select() won't see
3426 * typeahead characters. */
3427 tnew.c_lflag &= ~(ICANON | ECHO);
3428 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3429 tnew.c_cc[VTIME] = 0; /* don't wait */
3430 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003431
3432# if defined(HAVE_TERMIOS_H)
3433 {
3434 int n = 10;
3435
3436 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3437 * few times. */
3438 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3439 && errno == EINTR && n > 0)
3440 --n;
3441 }
3442# else
3443 ioctl(read_cmd_fd, TCSETA, &tnew);
3444# endif
3445
3446#else
3447
3448 /*
3449 * for "old" tty systems
3450 */
3451# ifndef TIOCSETN
3452# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3453# endif
3454 static struct sgttyb ttybold;
3455 struct sgttyb ttybnew;
3456
3457 if (first)
3458 {
3459 first = FALSE;
3460 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3461 }
3462
3463 ttybnew = ttybold;
3464 if (tmode == TMODE_RAW)
3465 {
3466 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3467 ttybnew.sg_flags |= RAW;
3468 }
3469 else if (tmode == TMODE_SLEEP)
3470 ttybnew.sg_flags &= ~(ECHO);
3471 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3472#endif
3473 curr_tmode = tmode;
3474}
3475
3476/*
3477 * Try to get the code for "t_kb" from the stty setting
3478 *
3479 * Even if termcap claims a backspace key, the user's setting *should*
3480 * prevail. stty knows more about reality than termcap does, and if
3481 * somebody's usual erase key is DEL (which, for most BSD users, it will
3482 * be), they're going to get really annoyed if their erase key starts
3483 * doing forward deletes for no reason. (Eric Fischer)
3484 */
3485 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003486get_stty(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003487{
3488 char_u buf[2];
3489 char_u *p;
3490
3491 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3492#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3493 /* for "new" tty systems */
3494# ifdef HAVE_TERMIOS_H
3495 struct termios keys;
3496# else
3497 struct termio keys;
3498# endif
3499
3500# if defined(HAVE_TERMIOS_H)
3501 if (tcgetattr(read_cmd_fd, &keys) != -1)
3502# else
3503 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3504# endif
3505 {
3506 buf[0] = keys.c_cc[VERASE];
3507 intr_char = keys.c_cc[VINTR];
3508#else
3509 /* for "old" tty systems */
3510 struct sgttyb keys;
3511
3512 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3513 {
3514 buf[0] = keys.sg_erase;
3515 intr_char = keys.sg_kill;
3516#endif
3517 buf[1] = NUL;
3518 add_termcode((char_u *)"kb", buf, FALSE);
3519
3520 /*
3521 * If <BS> and <DEL> are now the same, redefine <DEL>.
3522 */
3523 p = find_termcode((char_u *)"kD");
3524 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3525 do_fixdel(NULL);
3526 }
3527#if 0
3528 } /* to keep cindent happy */
3529#endif
3530}
3531
3532#endif /* VMS */
3533
3534#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3535/*
3536 * Set mouse clicks on or off.
3537 */
3538 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003539mch_setmouse(int on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540{
3541 static int ison = FALSE;
3542 int xterm_mouse_vers;
3543
3544 if (on == ison) /* return quickly if nothing to do */
3545 return;
3546
3547 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003548
3549# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003550 if (ttym_flags == TTYM_URXVT)
3551 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003552 out_str_nf((char_u *)
3553 (on
3554 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3555 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
3556 ison = on;
3557 }
3558# endif
3559
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003560# ifdef FEAT_MOUSE_SGR
3561 if (ttym_flags == TTYM_SGR)
3562 {
3563 out_str_nf((char_u *)
3564 (on
3565 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3566 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
3567 ison = on;
3568 }
3569# endif
3570
Bram Moolenaar071d4272004-06-13 20:20:40 +00003571 if (xterm_mouse_vers > 0)
3572 {
3573 if (on) /* enable mouse events, use mouse tracking if available */
3574 out_str_nf((char_u *)
3575 (xterm_mouse_vers > 1
3576 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3577 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3578 else /* disable mouse events, could probably always send the same */
3579 out_str_nf((char_u *)
3580 (xterm_mouse_vers > 1
3581 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3582 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3583 ison = on;
3584 }
3585
3586# ifdef FEAT_MOUSE_DEC
3587 else if (ttym_flags == TTYM_DEC)
3588 {
3589 if (on) /* enable mouse events */
3590 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3591 else /* disable mouse events */
3592 out_str_nf((char_u *)"\033['z");
3593 ison = on;
3594 }
3595# endif
3596
3597# ifdef FEAT_MOUSE_GPM
3598 else
3599 {
3600 if (on)
3601 {
3602 if (gpm_open())
3603 ison = TRUE;
3604 }
3605 else
3606 {
3607 gpm_close();
3608 ison = FALSE;
3609 }
3610 }
3611# endif
3612
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003613# ifdef FEAT_SYSMOUSE
3614 else
3615 {
3616 if (on)
3617 {
3618 if (sysmouse_open() == OK)
3619 ison = TRUE;
3620 }
3621 else
3622 {
3623 sysmouse_close();
3624 ison = FALSE;
3625 }
3626 }
3627# endif
3628
Bram Moolenaar071d4272004-06-13 20:20:40 +00003629# ifdef FEAT_MOUSE_JSB
3630 else
3631 {
3632 if (on)
3633 {
3634 /* D - Enable Mouse up/down messages
3635 * L - Enable Left Button Reporting
3636 * M - Enable Middle Button Reporting
3637 * R - Enable Right Button Reporting
3638 * K - Enable SHIFT and CTRL key Reporting
3639 * + - Enable Advanced messaging of mouse moves and up/down messages
3640 * Q - Quiet No Ack
3641 * # - Numeric value of mouse pointer required
3642 * 0 = Multiview 2000 cursor, used as standard
3643 * 1 = Windows Arrow
3644 * 2 = Windows I Beam
3645 * 3 = Windows Hour Glass
3646 * 4 = Windows Cross Hair
3647 * 5 = Windows UP Arrow
3648 */
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003649# ifdef JSBTERM_MOUSE_NONADVANCED
3650 /* Disables full feedback of pointer movements */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003651 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3652 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003653# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003654 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3655 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003656# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003657 ison = TRUE;
3658 }
3659 else
3660 {
3661 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3662 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3663 ison = FALSE;
3664 }
3665 }
3666# endif
3667# ifdef FEAT_MOUSE_PTERM
3668 else
3669 {
3670 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3671 if (on)
3672 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3673 else
3674 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3675 ison = on;
3676 }
3677# endif
3678}
3679
3680/*
3681 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3682 */
3683 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003684check_mouse_termcode(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685{
3686# ifdef FEAT_MOUSE_XTERM
3687 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003688# ifdef FEAT_MOUSE_URXVT
3689 && use_xterm_mouse() != 3
3690# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003691# ifdef FEAT_GUI
3692 && !gui.in_use
3693# endif
3694 )
3695 {
3696 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003697 ? IF_EB("\233M", CSI_STR "M")
3698 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003699 if (*p_mouse != NUL)
3700 {
3701 /* force mouse off and maybe on to send possibly new mouse
3702 * activation sequence to the xterm, with(out) drag tracing. */
3703 mch_setmouse(FALSE);
3704 setmouse();
3705 }
3706 }
3707 else
3708 del_mouse_termcode(KS_MOUSE);
3709# endif
3710
3711# ifdef FEAT_MOUSE_GPM
3712 if (!use_xterm_mouse()
3713# ifdef FEAT_GUI
3714 && !gui.in_use
3715# endif
3716 )
3717 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3718# endif
3719
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003720# ifdef FEAT_SYSMOUSE
3721 if (!use_xterm_mouse()
3722# ifdef FEAT_GUI
3723 && !gui.in_use
3724# endif
3725 )
3726 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3727# endif
3728
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729# ifdef FEAT_MOUSE_JSB
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003730 /* Conflicts with xterm mouse: "\033[" and "\033[M" ??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003731 if (!use_xterm_mouse()
3732# ifdef FEAT_GUI
3733 && !gui.in_use
3734# endif
3735 )
3736 set_mouse_termcode(KS_JSBTERM_MOUSE,
3737 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3738 else
3739 del_mouse_termcode(KS_JSBTERM_MOUSE);
3740# endif
3741
3742# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003743 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003744 * define it in the GUI or when using an xterm. */
3745 if (!use_xterm_mouse()
3746# ifdef FEAT_GUI
3747 && !gui.in_use
3748# endif
3749 )
3750 set_mouse_termcode(KS_NETTERM_MOUSE,
3751 (char_u *)IF_EB("\033}", ESC_STR "}"));
3752 else
3753 del_mouse_termcode(KS_NETTERM_MOUSE);
3754# endif
3755
3756# ifdef FEAT_MOUSE_DEC
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003757 /* Conflicts with xterm mouse: "\033[" and "\033[M" */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003758 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003759# ifdef FEAT_GUI
3760 && !gui.in_use
3761# endif
3762 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003763 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3764 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765 else
3766 del_mouse_termcode(KS_DEC_MOUSE);
3767# endif
3768# ifdef FEAT_MOUSE_PTERM
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003769 /* same conflict as the dec mouse */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003770 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771# ifdef FEAT_GUI
3772 && !gui.in_use
3773# endif
3774 )
3775 set_mouse_termcode(KS_PTERM_MOUSE,
3776 (char_u *) IF_EB("\033[", ESC_STR "["));
3777 else
3778 del_mouse_termcode(KS_PTERM_MOUSE);
3779# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003780# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003781 /* same conflict as the dec mouse */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003782 if (use_xterm_mouse() == 3
Bram Moolenaarc8427482011-10-20 21:09:35 +02003783# ifdef FEAT_GUI
3784 && !gui.in_use
3785# endif
3786 )
3787 {
3788 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3789 ? IF_EB("\233", CSI_STR)
3790 : IF_EB("\033[", ESC_STR "[")));
3791
3792 if (*p_mouse != NUL)
3793 {
3794 mch_setmouse(FALSE);
3795 setmouse();
3796 }
3797 }
3798 else
3799 del_mouse_termcode(KS_URXVT_MOUSE);
3800# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003801# ifdef FEAT_MOUSE_SGR
Bram Moolenaar24dc2302014-05-13 20:19:58 +02003802 /* There is no conflict with xterm mouse */
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003803 if (use_xterm_mouse() == 4
3804# ifdef FEAT_GUI
3805 && !gui.in_use
3806# endif
3807 )
3808 {
3809 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3810 ? IF_EB("\233<", CSI_STR "<")
3811 : IF_EB("\033[<", ESC_STR "[<")));
3812
3813 if (*p_mouse != NUL)
3814 {
3815 mch_setmouse(FALSE);
3816 setmouse();
3817 }
3818 }
3819 else
3820 del_mouse_termcode(KS_SGR_MOUSE);
3821# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822}
3823#endif
3824
3825/*
3826 * set screen mode, always fails.
3827 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003828 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003829mch_screenmode(char_u *arg UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003830{
3831 EMSG(_(e_screenmode));
3832 return FAIL;
3833}
3834
3835#ifndef VMS
3836
3837/*
3838 * Try to get the current window size:
3839 * 1. with an ioctl(), most accurate method
3840 * 2. from the environment variables LINES and COLUMNS
3841 * 3. from the termcap
3842 * 4. keep using the old values
3843 * Return OK when size could be determined, FAIL otherwise.
3844 */
3845 int
Bram Moolenaar05540972016-01-30 20:31:25 +01003846mch_get_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003847{
3848 long rows = 0;
3849 long columns = 0;
3850 char_u *p;
3851
3852 /*
Bram Moolenaar071d4272004-06-13 20:20:40 +00003853 * 1. try using an ioctl. It is the most accurate method.
3854 *
3855 * Try using TIOCGWINSZ first, some systems that have it also define
3856 * TIOCGSIZE but don't have a struct ttysize.
3857 */
3858# ifdef TIOCGWINSZ
3859 {
3860 struct winsize ws;
3861 int fd = 1;
3862
3863 /* When stdout is not a tty, use stdin for the ioctl(). */
3864 if (!isatty(fd) && isatty(read_cmd_fd))
3865 fd = read_cmd_fd;
3866 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3867 {
3868 columns = ws.ws_col;
3869 rows = ws.ws_row;
3870 }
3871 }
3872# else /* TIOCGWINSZ */
3873# ifdef TIOCGSIZE
3874 {
3875 struct ttysize ts;
3876 int fd = 1;
3877
3878 /* When stdout is not a tty, use stdin for the ioctl(). */
3879 if (!isatty(fd) && isatty(read_cmd_fd))
3880 fd = read_cmd_fd;
3881 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3882 {
3883 columns = ts.ts_cols;
3884 rows = ts.ts_lines;
3885 }
3886 }
3887# endif /* TIOCGSIZE */
3888# endif /* TIOCGWINSZ */
3889
3890 /*
3891 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003892 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3893 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003894 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003895 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896 {
3897 if ((p = (char_u *)getenv("LINES")))
3898 rows = atoi((char *)p);
3899 if ((p = (char_u *)getenv("COLUMNS")))
3900 columns = atoi((char *)p);
3901 }
3902
3903#ifdef HAVE_TGETENT
3904 /*
3905 * 3. try reading "co" and "li" entries from termcap
3906 */
3907 if (columns == 0 || rows == 0)
3908 getlinecol(&columns, &rows);
3909#endif
3910
3911 /*
3912 * 4. If everything fails, use the old values
3913 */
3914 if (columns <= 0 || rows <= 0)
3915 return FAIL;
3916
3917 Rows = rows;
3918 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02003919 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003920 return OK;
3921}
3922
3923/*
3924 * Try to set the window size to Rows and Columns.
3925 */
3926 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003927mch_set_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003928{
3929 if (*T_CWS)
3930 {
3931 /*
3932 * NOTE: if you get an error here that term_set_winsize() is
3933 * undefined, check the output of configure. It could probably not
3934 * find a ncurses, termcap or termlib library.
3935 */
3936 term_set_winsize((int)Rows, (int)Columns);
3937 out_flush();
3938 screen_start(); /* don't know where cursor is now */
3939 }
3940}
3941
3942#endif /* VMS */
3943
3944/*
3945 * Rows and/or Columns has changed.
3946 */
3947 void
Bram Moolenaar05540972016-01-30 20:31:25 +01003948mch_new_shellsize(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003949{
3950 /* Nothing to do. */
3951}
3952
Bram Moolenaar205b8862011-09-07 15:04:31 +02003953/*
3954 * Wait for process "child" to end.
3955 * Return "child" if it exited properly, <= 0 on error.
3956 */
3957 static pid_t
Bram Moolenaar05540972016-01-30 20:31:25 +01003958wait4pid(pid_t child, waitstatus *status)
Bram Moolenaar205b8862011-09-07 15:04:31 +02003959{
3960 pid_t wait_pid = 0;
Bram Moolenaar0abe0522016-08-28 16:53:12 +02003961 long delay_msec = 1;
Bram Moolenaar205b8862011-09-07 15:04:31 +02003962
3963 while (wait_pid != child)
3964 {
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003965 /* When compiled with Python threads are probably used, in which case
3966 * wait() sometimes hangs for no obvious reason. Use waitpid()
3967 * instead and loop (like the GUI). Also needed for other interfaces,
3968 * they might call system(). */
3969# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02003970 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003971# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02003972 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003973# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02003974 if (wait_pid == 0)
3975 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02003976 /* Wait for 1 to 10 msec before trying again. */
3977 mch_delay(delay_msec, TRUE);
3978 if (++delay_msec > 10)
3979 delay_msec = 10;
Bram Moolenaar205b8862011-09-07 15:04:31 +02003980 continue;
3981 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02003982 if (wait_pid <= 0
3983# ifdef ECHILD
3984 && errno == ECHILD
3985# endif
3986 )
3987 break;
3988 }
3989 return wait_pid;
3990}
3991
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01003992#if defined(FEAT_JOB_CHANNEL) || !defined(USE_SYSTEM) || defined(PROTO)
Bram Moolenaar72801402016-02-09 11:37:50 +01003993/*
3994 * Parse "cmd" and put the white-separated parts in "argv".
3995 * "argv" is an allocated array with "argc" entries.
3996 * Returns FAIL when out of memory.
3997 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01003998 int
3999mch_parse_cmd(char_u *cmd, int use_shcf, char ***argv, int *argc)
4000{
4001 int i;
4002 char_u *p;
4003 int inquote;
4004
4005 /*
4006 * Do this loop twice:
4007 * 1: find number of arguments
4008 * 2: separate them and build argv[]
4009 */
4010 for (i = 0; i < 2; ++i)
4011 {
Bram Moolenaar6231cb82016-04-26 19:42:42 +02004012 p = skipwhite(cmd);
Bram Moolenaar835dc632016-02-07 14:27:38 +01004013 inquote = FALSE;
4014 *argc = 0;
4015 for (;;)
4016 {
4017 if (i == 1)
4018 (*argv)[*argc] = (char *)p;
4019 ++*argc;
4020 while (*p != NUL && (inquote || (*p != ' ' && *p != TAB)))
4021 {
4022 if (*p == '"')
4023 inquote = !inquote;
4024 ++p;
4025 }
4026 if (*p == NUL)
4027 break;
4028 if (i == 1)
4029 *p++ = NUL;
4030 p = skipwhite(p);
4031 }
4032 if (*argv == NULL)
4033 {
4034 if (use_shcf)
4035 {
4036 /* Account for possible multiple args in p_shcf. */
4037 p = p_shcf;
4038 for (;;)
4039 {
4040 p = skiptowhite(p);
4041 if (*p == NUL)
4042 break;
4043 ++*argc;
4044 p = skipwhite(p);
4045 }
4046 }
4047
4048 *argv = (char **)alloc((unsigned)((*argc + 4) * sizeof(char *)));
4049 if (*argv == NULL) /* out of memory */
4050 return FAIL;
4051 }
4052 }
4053 return OK;
4054}
4055#endif
4056
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01004057#if !defined(USE_SYSTEM) || defined(FEAT_JOB_CHANNEL)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004058 static void
4059set_child_environment(void)
4060{
4061# ifdef HAVE_SETENV
4062 char envbuf[50];
4063# else
4064 static char envbuf_Rows[20];
4065 static char envbuf_Columns[20];
4066# endif
4067
4068 /* Simulate to have a dumb terminal (for now) */
4069# ifdef HAVE_SETENV
4070 setenv("TERM", "dumb", 1);
4071 sprintf((char *)envbuf, "%ld", Rows);
4072 setenv("ROWS", (char *)envbuf, 1);
4073 sprintf((char *)envbuf, "%ld", Rows);
4074 setenv("LINES", (char *)envbuf, 1);
4075 sprintf((char *)envbuf, "%ld", Columns);
4076 setenv("COLUMNS", (char *)envbuf, 1);
4077# else
4078 /*
4079 * Putenv does not copy the string, it has to remain valid.
4080 * Use a static array to avoid losing allocated memory.
4081 */
4082 putenv("TERM=dumb");
4083 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
4084 putenv(envbuf_Rows);
4085 sprintf(envbuf_Rows, "LINES=%ld", Rows);
4086 putenv(envbuf_Rows);
4087 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
4088 putenv(envbuf_Columns);
4089# endif
4090}
4091#endif
4092
Bram Moolenaar071d4272004-06-13 20:20:40 +00004093 int
Bram Moolenaar05540972016-01-30 20:31:25 +01004094mch_call_shell(
4095 char_u *cmd,
4096 int options) /* SHELL_*, see vim.h */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004097{
4098#ifdef VMS
4099 char *ifn = NULL;
4100 char *ofn = NULL;
4101#endif
4102 int tmode = cur_tmode;
4103#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
Bram Moolenaarb2b050a2016-07-16 21:52:46 +02004104 char_u *newcmd; /* only needed for unix */
Bram Moolenaarde5e2c22016-11-04 20:35:31 +01004105 int x;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106
4107 out_flush();
4108
4109 if (options & SHELL_COOKED)
4110 settmode(TMODE_COOK); /* set to normal mode */
4111
Bram Moolenaar62b42182010-09-21 22:09:37 +02004112# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004113 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02004114 loose_clipboard();
4115# endif
4116
Bram Moolenaar071d4272004-06-13 20:20:40 +00004117 if (cmd == NULL)
4118 x = system((char *)p_sh);
4119 else
4120 {
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004121# ifdef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122 if (ofn = strchr((char *)cmd, '>'))
4123 *ofn++ = '\0';
4124 if (ifn = strchr((char *)cmd, '<'))
4125 {
4126 char *p;
4127
4128 *ifn++ = '\0';
4129 p = strchr(ifn,' '); /* chop off any trailing spaces */
4130 if (p)
4131 *p = '\0';
4132 }
4133 if (ofn)
4134 x = vms_sys((char *)cmd, ofn, ifn);
4135 else
4136 x = system((char *)cmd);
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004137# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138 newcmd = lalloc(STRLEN(p_sh)
4139 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
4140 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
4141 if (newcmd == NULL)
4142 x = 0;
4143 else
4144 {
4145 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
4146 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
4147 (char *)p_shcf,
4148 (char *)cmd);
4149 x = system((char *)newcmd);
4150 vim_free(newcmd);
4151 }
Bram Moolenaara06ecab2016-07-16 14:47:36 +02004152# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004153 }
4154# ifdef VMS
4155 x = vms_sys_status(x);
4156# endif
4157 if (emsg_silent)
4158 ;
4159 else if (x == 127)
4160 MSG_PUTS(_("\nCannot execute shell sh\n"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161 else if (x && !(options & SHELL_SILENT))
4162 {
4163 MSG_PUTS(_("\nshell returned "));
4164 msg_outnum((long)x);
4165 msg_putchar('\n');
4166 }
4167
4168 if (tmode == TMODE_RAW)
4169 settmode(TMODE_RAW); /* set to raw mode */
4170# ifdef FEAT_TITLE
4171 resettitle();
4172# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004173# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4174 restore_clipboard();
4175# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176 return x;
4177
4178#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
4179
Bram Moolenaardf177f62005-02-22 08:39:57 +00004180# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
4181 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004182
Bram Moolenaar835dc632016-02-07 14:27:38 +01004183 char_u *newcmd;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004185 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004186 pid_t wait_pid = 0;
4187# ifdef HAVE_UNION_WAIT
4188 union wait status;
4189# else
4190 int status = -1;
4191# endif
4192 int retval = -1;
4193 char **argv = NULL;
4194 int argc;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004195 char_u *p_shcf_copy = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004196 int i;
4197 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004198 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004199# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004200 int pty_slave_fd = -1;
4201 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004202# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004203 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004204 int fd_fromshell[2];
4205 int pipe_error = FALSE;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004206 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004207
Bram Moolenaar62b42182010-09-21 22:09:37 +02004208 newcmd = vim_strsave(p_sh);
4209 if (newcmd == NULL) /* out of memory */
4210 goto error;
4211
Bram Moolenaar071d4272004-06-13 20:20:40 +00004212 out_flush();
4213 if (options & SHELL_COOKED)
4214 settmode(TMODE_COOK); /* set to normal mode */
4215
Bram Moolenaar835dc632016-02-07 14:27:38 +01004216 if (mch_parse_cmd(newcmd, TRUE, &argv, &argc) == FAIL)
4217 goto error;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004218
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219 if (cmd != NULL)
4220 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004221 char_u *s;
4222
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223 if (extra_shell_arg != NULL)
4224 argv[argc++] = (char *)extra_shell_arg;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004225
4226 /* Break 'shellcmdflag' into white separated parts. This doesn't
4227 * handle quoted strings, they are very unlikely to appear. */
4228 p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
4229 if (p_shcf_copy == NULL) /* out of memory */
4230 goto error;
4231 s = p_shcf_copy;
4232 p = p_shcf;
4233 while (*p != NUL)
4234 {
4235 argv[argc++] = (char *)s;
4236 while (*p && *p != ' ' && *p != TAB)
4237 *s++ = *p++;
4238 *s++ = NUL;
4239 p = skipwhite(p);
4240 }
4241
Bram Moolenaar071d4272004-06-13 20:20:40 +00004242 argv[argc++] = (char *)cmd;
4243 }
4244 argv[argc] = NULL;
4245
Bram Moolenaar071d4272004-06-13 20:20:40 +00004246 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004247 * For the GUI, when writing the output into the buffer and when reading
4248 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4249 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004251 if ((options & (SHELL_READ|SHELL_WRITE))
4252# ifdef FEAT_GUI
4253 || (gui.in_use && show_shell_mess)
4254# endif
4255 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004256 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004257# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004258 /*
4259 * Try to open a master pty.
4260 * If this works, open the slave pty.
4261 * If the slave can't be opened, close the master pty.
4262 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004263 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004264 {
4265 pty_master_fd = OpenPTY(&tty_name); /* open pty */
Bram Moolenaare70172e2011-08-04 19:36:52 +02004266 if (pty_master_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004267 {
Bram Moolenaare70172e2011-08-04 19:36:52 +02004268 /* Leaving out O_NOCTTY may lead to waitpid() always returning
4269 * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4270 * adding O_NOCTTY always works when defined. */
4271#ifdef O_NOCTTY
4272 pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4273#else
4274 pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4275#endif
4276 if (pty_slave_fd < 0)
4277 {
4278 close(pty_master_fd);
4279 pty_master_fd = -1;
4280 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004281 }
4282 }
4283 /*
4284 * If not opening a pty or it didn't work, try using pipes.
4285 */
4286 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004287# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004288 {
4289 pipe_error = (pipe(fd_toshell) < 0);
4290 if (!pipe_error) /* pipe create OK */
4291 {
4292 pipe_error = (pipe(fd_fromshell) < 0);
4293 if (pipe_error) /* pipe create failed */
4294 {
4295 close(fd_toshell[0]);
4296 close(fd_toshell[1]);
4297 }
4298 }
4299 if (pipe_error)
4300 {
4301 MSG_PUTS(_("\nCannot create pipes\n"));
4302 out_flush();
4303 }
4304 }
4305 }
4306
4307 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004308 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004309 SIGSET_DECL(curset)
4310
Bram Moolenaar071d4272004-06-13 20:20:40 +00004311# ifdef __BEOS__
4312 beos_cleanup_read_thread();
4313# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004314
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004315 BLOCK_SIGNALS(&curset);
4316 pid = fork(); /* maybe we should use vfork() */
4317 if (pid == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004318 {
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004319 UNBLOCK_SIGNALS(&curset);
4320
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004322 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004324 || (gui.in_use && show_shell_mess)
4325# endif
4326 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004327 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004328# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004329 if (pty_master_fd >= 0) /* close the pseudo tty */
4330 {
4331 close(pty_master_fd);
4332 close(pty_slave_fd);
4333 }
4334 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004335# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004336 {
4337 close(fd_toshell[0]);
4338 close(fd_toshell[1]);
4339 close(fd_fromshell[0]);
4340 close(fd_fromshell[1]);
4341 }
4342 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004343 }
4344 else if (pid == 0) /* child */
4345 {
4346 reset_signals(); /* handle signals normally */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004347 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348
4349 if (!show_shell_mess || (options & SHELL_EXPAND))
4350 {
4351 int fd;
4352
4353 /*
4354 * Don't want to show any message from the shell. Can't just
4355 * close stdout and stderr though, because some systems will
4356 * break if you try to write to them after that, so we must
4357 * use dup() to replace them with something else -- webb
4358 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4359 * waiting for input.
4360 */
4361 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4362 fclose(stdin);
4363 fclose(stdout);
4364 fclose(stderr);
4365
4366 /*
4367 * If any of these open()'s and dup()'s fail, we just continue
4368 * anyway. It's not fatal, and on most systems it will make
4369 * no difference at all. On a few it will cause the execvp()
4370 * to exit with a non-zero status even when the completion
4371 * could be done, which is nothing too serious. If the open()
4372 * or dup() failed we'd just do the same thing ourselves
4373 * anyway -- webb
4374 */
4375 if (fd >= 0)
4376 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004377 ignored = dup(fd); /* To replace stdin (fd 0) */
4378 ignored = dup(fd); /* To replace stdout (fd 1) */
4379 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004380
4381 /* Don't need this now that we've duplicated it */
4382 close(fd);
4383 }
4384 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004385 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004386# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004387 || gui.in_use
4388# endif
4389 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004390 {
4391
Bram Moolenaardf177f62005-02-22 08:39:57 +00004392# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004393 /* Create our own process group, so that the child and all its
4394 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004395 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004396 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004397 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004398 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004399# if defined(SIGHUP)
4400 /* When doing "!xterm&" and 'shell' is bash: the shell
4401 * will exit and send SIGHUP to all processes in its
4402 * group, killing the just started process. Ignore SIGHUP
4403 * to avoid that. (suggested by Simon Schubert)
4404 */
4405 signal(SIGHUP, SIG_IGN);
4406# endif
4407 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004408# endif
4409# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004410 if (pty_slave_fd >= 0)
4411 {
4412 /* push stream discipline modules */
4413 if (options & SHELL_COOKED)
4414 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004415# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004416 /* Try to become controlling tty (probably doesn't work,
4417 * unless run by root) */
4418 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004419# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004420 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004421# endif
Bram Moolenaar6463ca22016-02-13 17:04:46 +01004422 set_child_environment();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004423
Bram Moolenaara5792f52005-11-23 21:25:05 +00004424 /*
4425 * stderr is only redirected when using the GUI, so that a
4426 * program like gpg can still access the terminal to get a
4427 * passphrase using stderr.
4428 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004429# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004430 if (pty_master_fd >= 0)
4431 {
4432 close(pty_master_fd); /* close master side of pty */
4433
4434 /* set up stdin/stdout/stderr for the child */
4435 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004436 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004438 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004439 if (gui.in_use)
4440 {
4441 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004442 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004443 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004444
4445 close(pty_slave_fd); /* has been dupped, close it now */
4446 }
4447 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004448# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449 {
4450 /* set up stdin for the child */
4451 close(fd_toshell[1]);
4452 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004453 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004454 close(fd_toshell[0]);
4455
4456 /* set up stdout for the child */
4457 close(fd_fromshell[0]);
4458 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004459 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004460 close(fd_fromshell[1]);
4461
Bram Moolenaara5792f52005-11-23 21:25:05 +00004462# ifdef FEAT_GUI
4463 if (gui.in_use)
4464 {
4465 /* set up stderr for the child */
4466 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004467 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004468 }
4469# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004470 }
4471 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004472
Bram Moolenaar071d4272004-06-13 20:20:40 +00004473 /*
4474 * There is no type cast for the argv, because the type may be
4475 * different on different machines. This may cause a warning
4476 * message with strict compilers, don't worry about it.
4477 * Call _exit() instead of exit() to avoid closing the connection
4478 * to the X server (esp. with GTK, which uses atexit()).
4479 */
4480 execvp(argv[0], argv);
4481 _exit(EXEC_FAILED); /* exec failed, return failure code */
4482 }
4483 else /* parent */
4484 {
4485 /*
4486 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004487 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004488 */
4489 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004490 catch_int_signal();
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02004491 UNBLOCK_SIGNALS(&curset);
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01004492# ifdef FEAT_JOB_CHANNEL
4493 ++dont_check_job_ended;
4494# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004495 /*
4496 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004497 * This is also used to pipe stdin/stdout to/from the external
4498 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004499 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004500 if ((options & (SHELL_READ|SHELL_WRITE))
4501# ifdef FEAT_GUI
4502 || (gui.in_use && show_shell_mess)
4503# endif
4504 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004505 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004506# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004508# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004509 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004510# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004511 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4512 int ta_len = 0; /* valid bytes in ta_buf[] */
4513 int len;
4514 int p_more_save;
4515 int old_State;
4516 int c;
4517 int toshell_fd;
4518 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004519 garray_T ga;
4520 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004521# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4522 struct timeval start_tv;
4523# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004524
Bram Moolenaardf177f62005-02-22 08:39:57 +00004525# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004526 if (pty_master_fd >= 0)
4527 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004528 fromshell_fd = pty_master_fd;
4529 toshell_fd = dup(pty_master_fd);
4530 }
4531 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004532# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004533 {
4534 close(fd_toshell[0]);
4535 close(fd_fromshell[1]);
4536 toshell_fd = fd_toshell[1];
4537 fromshell_fd = fd_fromshell[0];
4538 }
4539
4540 /*
4541 * Write to the child if there are typed characters.
4542 * Read from the child if there are characters available.
4543 * Repeat the reading a few times if more characters are
4544 * available. Need to check for typed keys now and then, but
4545 * not too often (delays when no chars are available).
4546 * This loop is quit if no characters can be read from the pty
4547 * (WaitForChar detected special condition), or there are no
4548 * characters available and the child has exited.
4549 * Only check if the child has exited when there is no more
4550 * output. The child may exit before all the output has
4551 * been printed.
4552 *
4553 * Currently this busy loops!
4554 * This can probably dead-lock when the write blocks!
4555 */
4556 p_more_save = p_more;
4557 p_more = FALSE;
4558 old_State = State;
4559 State = EXTERNCMD; /* don't redraw at window resize */
4560
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004561 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004562 {
4563 /* Fork a process that will write the lines to the
4564 * external program. */
4565 if ((wpid = fork()) == -1)
4566 {
4567 MSG_PUTS(_("\nCannot fork\n"));
4568 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004569 else if (wpid == 0) /* child */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004570 {
4571 linenr_T lnum = curbuf->b_op_start.lnum;
4572 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004573 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004574 size_t l;
4575
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004576 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004577 for (;;)
4578 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004579 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004580 if (l == 0)
4581 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004582 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004583 /* NL -> NUL translation */
4584 len = write(toshell_fd, "", (size_t)1);
4585 else
4586 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004587 char_u *s = vim_strchr(lp + written, NL);
4588
Bram Moolenaar89d40322006-08-29 15:30:07 +00004589 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004590 s == NULL ? l
4591 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004592 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004593 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004594 {
4595 /* Finished a line, add a NL, unless this line
4596 * should not have one. */
4597 if (lnum != curbuf->b_op_end.lnum
Bram Moolenaar34d72d42015-07-17 14:18:08 +02004598 || (!curbuf->b_p_bin
4599 && curbuf->b_p_fixeol)
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004600 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004601 && (lnum !=
4602 curbuf->b_ml.ml_line_count
4603 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004604 ignored = write(toshell_fd, "\n",
4605 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004606 ++lnum;
4607 if (lnum > curbuf->b_op_end.lnum)
4608 {
4609 /* finished all the lines, close pipe */
4610 close(toshell_fd);
4611 toshell_fd = -1;
4612 break;
4613 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004614 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004615 written = 0;
4616 }
4617 else if (len > 0)
4618 written += len;
4619 }
4620 _exit(0);
4621 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004622 else /* parent */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004623 {
4624 close(toshell_fd);
4625 toshell_fd = -1;
4626 }
4627 }
4628
4629 if (options & SHELL_READ)
4630 ga_init2(&ga, 1, BUFLEN);
4631
4632 noread_cnt = 0;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004633# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4634 gettimeofday(&start_tv, NULL);
4635# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636 for (;;)
4637 {
4638 /*
4639 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004640 * if there are any.
4641 * Don't do this if we are expanding wild cards (would eat
4642 * typeahead).
4643 * Don't do this when filtering and terminal is in cooked
4644 * mode, the shell command will handle the I/O. Avoids
4645 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004646 * Don't get characters when the child has already
4647 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004648 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004649 * while (noread_cnt > 4), avoids that ":r !ls" eats
4650 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004651 */
4652 len = 0;
4653 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004654 && ((options &
4655 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4656 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004657# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004658 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004659# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004660 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004661 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004662 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004663 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004664 if (ta_len == 0)
4665 {
4666 /* Get extra characters when we don't have any.
4667 * Reset the counter and timer. */
4668 noread_cnt = 0;
4669# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4670 gettimeofday(&start_tv, NULL);
4671# endif
4672 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4673 }
4674 if (ta_len > 0 || len > 0)
4675 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676 /*
4677 * For pipes:
4678 * Check for CTRL-C: send interrupt signal to child.
4679 * Check for CTRL-D: EOF, close pipe to child.
4680 */
4681 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4682 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004683# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004684 /*
4685 * Send SIGINT to the child's group or all
4686 * processes in our group.
4687 */
4688 if (ta_buf[ta_len] == Ctrl_C
4689 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004690 {
4691# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004692 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004693# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004694 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004695# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004696 if (wpid > 0)
4697 kill(wpid, SIGINT);
4698 }
4699# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004700 if (pty_master_fd < 0 && toshell_fd >= 0
4701 && ta_buf[ta_len] == Ctrl_D)
4702 {
4703 close(toshell_fd);
4704 toshell_fd = -1;
4705 }
4706 }
4707
4708 /* replace K_BS by <BS> and K_DEL by <DEL> */
4709 for (i = ta_len; i < ta_len + len; ++i)
4710 {
4711 if (ta_buf[i] == CSI && len - i > 2)
4712 {
4713 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4714 if (c == K_DEL || c == K_KDEL || c == K_BS)
4715 {
4716 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4717 (size_t)(len - i - 2));
4718 if (c == K_DEL || c == K_KDEL)
4719 ta_buf[i] = DEL;
4720 else
4721 ta_buf[i] = Ctrl_H;
4722 len -= 2;
4723 }
4724 }
4725 else if (ta_buf[i] == '\r')
4726 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004727# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004728 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00004729 i += (*mb_ptr2len_len)(ta_buf + i,
4730 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004731# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004732 }
4733
4734 /*
4735 * For pipes: echo the typed characters.
4736 * For a pty this does not seem to work.
4737 */
4738 if (pty_master_fd < 0)
4739 {
4740 for (i = ta_len; i < ta_len + len; ++i)
4741 {
4742 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4743 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004744# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004745 else if (has_mbyte)
4746 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004747 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748
4749 msg_outtrans_len(ta_buf + i, l);
4750 i += l - 1;
4751 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004752# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004753 else
4754 msg_outtrans_len(ta_buf + i, 1);
4755 }
4756 windgoto(msg_row, msg_col);
4757 out_flush();
4758 }
4759
4760 ta_len += len;
4761
4762 /*
4763 * Write the characters to the child, unless EOF has
4764 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004765 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004766 * When writing buffer lines, drop the typed
4767 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004768 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004769 if (options & SHELL_WRITE)
4770 ta_len = 0;
4771 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772 {
4773 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4774 if (len > 0)
4775 {
4776 ta_len -= len;
4777 mch_memmove(ta_buf, ta_buf + len, ta_len);
4778 }
4779 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004780 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004781 }
4782
Bram Moolenaardf177f62005-02-22 08:39:57 +00004783 if (got_int)
4784 {
4785 /* CTRL-C sends a signal to the child, we ignore it
4786 * ourselves */
4787# ifdef HAVE_SETSID
4788 kill(-pid, SIGINT);
4789# else
4790 kill(0, SIGINT);
4791# endif
4792 if (wpid > 0)
4793 kill(wpid, SIGINT);
4794 got_int = FALSE;
4795 }
4796
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797 /*
4798 * Check if the child has any characters to be printed.
4799 * Read them and write them to our window. Repeat this as
4800 * long as there is something to do, avoid the 10ms wait
4801 * for mch_inchar(), or sending typeahead characters to
4802 * the external process.
4803 * TODO: This should handle escape sequences, compatible
4804 * to some terminal (vt52?).
4805 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004806 ++noread_cnt;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01004807 while (RealWaitForChar(fromshell_fd, 10L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004809 len = read_eintr(fromshell_fd, buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004810# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004812# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004813 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004814# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815 );
4816 if (len <= 0) /* end of file or error */
4817 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004818
4819 noread_cnt = 0;
4820 if (options & SHELL_READ)
4821 {
4822 /* Do NUL -> NL translation, append NL separated
4823 * lines to the current buffer. */
4824 for (i = 0; i < len; ++i)
4825 {
4826 if (buffer[i] == NL)
4827 append_ga_line(&ga);
4828 else if (buffer[i] == NUL)
4829 ga_append(&ga, NL);
4830 else
4831 ga_append(&ga, buffer[i]);
4832 }
4833 }
4834# ifdef FEAT_MBYTE
4835 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004836 {
4837 int l;
4838
Bram Moolenaardf177f62005-02-22 08:39:57 +00004839 len += buffer_off;
4840 buffer[len] = NUL;
4841
Bram Moolenaar071d4272004-06-13 20:20:40 +00004842 /* Check if the last character in buffer[] is
4843 * incomplete, keep these bytes for the next
4844 * round. */
4845 for (p = buffer; p < buffer + len; p += l)
4846 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02004847 l = MB_CPTR2LEN(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004848 if (l == 0)
4849 l = 1; /* NUL byte? */
4850 else if (MB_BYTE2LEN(*p) != l)
4851 break;
4852 }
4853 if (p == buffer) /* no complete character */
4854 {
4855 /* avoid getting stuck at an illegal byte */
4856 if (len >= 12)
4857 ++p;
4858 else
4859 {
4860 buffer_off = len;
4861 continue;
4862 }
4863 }
4864 c = *p;
4865 *p = NUL;
4866 msg_puts(buffer);
4867 if (p < buffer + len)
4868 {
4869 *p = c;
4870 buffer_off = (buffer + len) - p;
4871 mch_memmove(buffer, p, buffer_off);
4872 continue;
4873 }
4874 buffer_off = 0;
4875 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004876# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004877 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004878 {
4879 buffer[len] = NUL;
4880 msg_puts(buffer);
4881 }
4882
4883 windgoto(msg_row, msg_col);
4884 cursor_on();
4885 out_flush();
4886 if (got_int)
4887 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004888
4889# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02004890 if (wait_pid == 0)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004891 {
Bram Moolenaare30a3d02016-06-04 14:11:20 +02004892 long msec = elapsed(&start_tv);
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004893
4894 /* Avoid that we keep looping here without
4895 * checking for a CTRL-C for a long time. Don't
4896 * break out too often to avoid losing typeahead. */
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004897 if (msec > 2000)
4898 {
4899 noread_cnt = 5;
4900 break;
4901 }
4902 }
4903# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004904 }
4905
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02004906 /* If we already detected the child has finished, continue
4907 * reading output for a short while. Some text may be
4908 * buffered. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004909 if (wait_pid == pid)
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02004910 {
4911 if (noread_cnt < 5)
4912 continue;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004913 break;
Bram Moolenaar17fe5e12016-04-04 22:03:08 +02004914 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004915
Bram Moolenaar071d4272004-06-13 20:20:40 +00004916 /*
4917 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004918 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004919 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004920# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004921 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004922# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004923 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004924# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004925 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4926 || (wait_pid == pid && WIFEXITED(status)))
4927 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004928 /* Don't break the loop yet, try reading more
4929 * characters from "fromshell_fd" first. When using
4930 * pipes there might still be something to read and
4931 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004932 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004934 else
4935 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004936
Bram Moolenaar95a51352013-03-21 22:53:50 +01004937# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004938 /* Handle any X events, e.g. serving the clipboard. */
4939 clip_update();
4940# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004941 }
4942finished:
4943 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004944 if (options & SHELL_READ)
4945 {
4946 if (ga.ga_len > 0)
4947 {
4948 append_ga_line(&ga);
4949 /* remember that the NL was missing */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004950 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004951 }
4952 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004953 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004954 ga_clear(&ga);
4955 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004956
Bram Moolenaar071d4272004-06-13 20:20:40 +00004957 /*
4958 * Give all typeahead that wasn't used back to ui_inchar().
4959 */
4960 if (ta_len)
4961 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004962 State = old_State;
4963 if (toshell_fd >= 0)
4964 close(toshell_fd);
4965 close(fromshell_fd);
4966 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01004967# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004968 else
4969 {
Bram Moolenaar0abe0522016-08-28 16:53:12 +02004970 long delay_msec = 1;
4971
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004972 /*
4973 * Similar to the loop above, but only handle X events, no
4974 * I/O.
4975 */
4976 for (;;)
4977 {
4978 if (got_int)
4979 {
4980 /* CTRL-C sends a signal to the child, we ignore it
4981 * ourselves */
4982# ifdef HAVE_SETSID
4983 kill(-pid, SIGINT);
4984# else
4985 kill(0, SIGINT);
4986# endif
4987 got_int = FALSE;
4988 }
4989# ifdef __NeXT__
4990 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4991# else
4992 wait_pid = waitpid(pid, &status, WNOHANG);
4993# endif
4994 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4995 || (wait_pid == pid && WIFEXITED(status)))
4996 {
4997 wait_pid = pid;
4998 break;
4999 }
5000
5001 /* Handle any X events, e.g. serving the clipboard. */
5002 clip_update();
5003
Bram Moolenaar0abe0522016-08-28 16:53:12 +02005004 /* Wait for 1 to 10 msec. 1 is faster but gives the child
5005 * less time. */
5006 mch_delay(delay_msec, TRUE);
5007 if (++delay_msec > 10)
5008 delay_msec = 10;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01005009 }
5010 }
5011# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005012
5013 /*
5014 * Wait until our child has exited.
5015 * Ignore wait() returning pids of other children and returning
5016 * because of some signal like SIGWINCH.
5017 * Don't wait if wait_pid was already set above, indicating the
5018 * child already exited.
5019 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02005020 if (wait_pid != pid)
5021 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005022
Bram Moolenaar624891f2010-10-13 16:22:09 +02005023# ifdef FEAT_GUI
5024 /* Close slave side of pty. Only do this after the child has
5025 * exited, otherwise the child may hang when it tries to write on
5026 * the pty. */
5027 if (pty_master_fd >= 0)
5028 close(pty_slave_fd);
5029# endif
5030
Bram Moolenaardf177f62005-02-22 08:39:57 +00005031 /* Make sure the child that writes to the external program is
5032 * dead. */
5033 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02005034 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00005035 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02005036 wait4pid(wpid, NULL);
5037 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005038
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005039# ifdef FEAT_JOB_CHANNEL
5040 --dont_check_job_ended;
5041# endif
5042
Bram Moolenaar071d4272004-06-13 20:20:40 +00005043 /*
5044 * Set to raw mode right now, otherwise a CTRL-C after
5045 * catch_signals() will kill Vim.
5046 */
5047 if (tmode == TMODE_RAW)
5048 settmode(TMODE_RAW);
5049 did_settmode = TRUE;
5050 set_signals();
5051
5052 if (WIFEXITED(status))
5053 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00005054 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005055 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01005056 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005057 {
5058 if (retval == EXEC_FAILED)
5059 {
5060 MSG_PUTS(_("\nCannot execute shell "));
5061 msg_outtrans(p_sh);
5062 msg_putchar('\n');
5063 }
5064 else if (!(options & SHELL_SILENT))
5065 {
5066 MSG_PUTS(_("\nshell returned "));
5067 msg_outnum((long)retval);
5068 msg_putchar('\n');
5069 }
5070 }
5071 }
5072 else
5073 MSG_PUTS(_("\nCommand terminated\n"));
5074 }
5075 }
5076 vim_free(argv);
Bram Moolenaarea35ef62011-08-04 22:59:28 +02005077 vim_free(p_shcf_copy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005078
5079error:
5080 if (!did_settmode)
5081 if (tmode == TMODE_RAW)
5082 settmode(TMODE_RAW); /* set to raw mode */
5083# ifdef FEAT_TITLE
5084 resettitle();
5085# endif
5086 vim_free(newcmd);
5087
5088 return retval;
5089
5090#endif /* USE_SYSTEM */
5091}
5092
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005093#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005094 void
Bram Moolenaar802d5592016-03-05 22:05:27 +01005095mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005096{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005097 pid_t pid;
5098 int fd_in[2]; /* for stdin */
5099 int fd_out[2]; /* for stdout */
5100 int fd_err[2]; /* for stderr */
Bram Moolenaar16eb4f82016-02-14 23:02:34 +01005101 channel_T *channel = NULL;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005102 int use_null_for_in = options->jo_io[PART_IN] == JIO_NULL;
5103 int use_null_for_out = options->jo_io[PART_OUT] == JIO_NULL;
5104 int use_null_for_err = options->jo_io[PART_ERR] == JIO_NULL;
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005105 int use_file_for_in = options->jo_io[PART_IN] == JIO_FILE;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005106 int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE;
5107 int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE;
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005108 int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT;
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005109 SIGSET_DECL(curset)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005110
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005111 if (use_out_for_err && use_null_for_out)
5112 use_null_for_err = TRUE;
5113
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005114 /* default is to fail */
5115 job->jv_status = JOB_FAILED;
5116 fd_in[0] = -1;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005117 fd_in[1] = -1;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005118 fd_out[0] = -1;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005119 fd_out[1] = -1;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005120 fd_err[0] = -1;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005121 fd_err[1] = -1;
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005122
Bram Moolenaar12dcf022016-02-15 23:09:04 +01005123 /* TODO: without the channel feature connect the child to /dev/null? */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005124 /* Open pipes for stdin, stdout, stderr. */
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005125 if (use_file_for_in)
5126 {
5127 char_u *fname = options->jo_io_name[PART_IN];
5128
5129 fd_in[0] = mch_open((char *)fname, O_RDONLY, 0);
5130 if (fd_in[0] < 0)
5131 {
5132 EMSG2(_(e_notopen), fname);
5133 goto failed;
5134 }
5135 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005136 else if (!use_null_for_in && pipe(fd_in) < 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005137 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005138
5139 if (use_file_for_out)
5140 {
5141 char_u *fname = options->jo_io_name[PART_OUT];
5142
5143 fd_out[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
5144 if (fd_out[1] < 0)
5145 {
5146 EMSG2(_(e_notopen), fname);
5147 goto failed;
5148 }
5149 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005150 else if (!use_null_for_out && pipe(fd_out) < 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005151 goto failed;
Bram Moolenaare98d1212016-03-08 15:37:41 +01005152
5153 if (use_file_for_err)
5154 {
5155 char_u *fname = options->jo_io_name[PART_ERR];
5156
5157 fd_err[1] = mch_open((char *)fname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
5158 if (fd_err[1] < 0)
5159 {
5160 EMSG2(_(e_notopen), fname);
5161 goto failed;
5162 }
5163 }
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005164 else if (!use_out_for_err && !use_null_for_err && pipe(fd_err) < 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005165 goto failed;
5166
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005167 if (!use_null_for_in || !use_null_for_out || !use_null_for_err)
5168 {
Bram Moolenaarde279892016-03-11 22:19:44 +01005169 if (options->jo_set & JO_CHANNEL)
5170 {
5171 channel = options->jo_channel;
5172 if (channel != NULL)
5173 ++channel->ch_refcount;
5174 }
5175 else
5176 channel = add_channel();
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005177 if (channel == NULL)
5178 goto failed;
5179 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005180
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005181 BLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005182 pid = fork(); /* maybe we should use vfork() */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005183 if (pid == -1)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005184 {
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005185 /* failed to fork */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005186 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005187 goto failed;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005188 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005189 if (pid == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005190 {
Bram Moolenaar4694a172016-04-21 14:05:23 +02005191 int null_fd = -1;
5192 int stderr_works = TRUE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005193
Bram Moolenaar835dc632016-02-07 14:27:38 +01005194 /* child */
5195 reset_signals(); /* handle signals normally */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005196 UNBLOCK_SIGNALS(&curset);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005197
5198# ifdef HAVE_SETSID
5199 /* Create our own process group, so that the child and all its
5200 * children can be kill()ed. Don't do this when using pipes,
5201 * because stdin is not a tty, we would lose /dev/tty. */
5202 (void)setsid();
5203# endif
5204
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005205 set_child_environment();
5206
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005207 if (use_null_for_in || use_null_for_out || use_null_for_err)
5208 null_fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
5209
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005210 /* set up stdin for the child */
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005211 if (use_null_for_in && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005212 {
5213 close(0);
5214 ignored = dup(null_fd);
5215 }
5216 else
5217 {
5218 if (!use_file_for_in)
5219 close(fd_in[1]);
5220 close(0);
5221 ignored = dup(fd_in[0]);
5222 close(fd_in[0]);
5223 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005224
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005225 /* set up stderr for the child */
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005226 if (use_null_for_err && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005227 {
5228 close(2);
5229 ignored = dup(null_fd);
Bram Moolenaar4694a172016-04-21 14:05:23 +02005230 stderr_works = FALSE;
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005231 }
5232 else if (use_out_for_err)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005233 {
5234 close(2);
5235 ignored = dup(fd_out[1]);
5236 }
5237 else
5238 {
Bram Moolenaare98d1212016-03-08 15:37:41 +01005239 if (!use_file_for_err)
5240 close(fd_err[0]);
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005241 close(2);
5242 ignored = dup(fd_err[1]);
5243 close(fd_err[1]);
5244 }
5245
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005246 /* set up stdout for the child */
Bram Moolenaarc0a1d7f2016-03-19 14:12:50 +01005247 if (use_null_for_out && null_fd >= 0)
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005248 {
Bram Moolenaarea83bf02016-05-08 09:40:51 +02005249 close(1);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005250 ignored = dup(null_fd);
5251 }
5252 else
5253 {
5254 if (!use_file_for_out)
5255 close(fd_out[0]);
5256 close(1);
5257 ignored = dup(fd_out[1]);
5258 close(fd_out[1]);
5259 }
Bram Moolenaarea83bf02016-05-08 09:40:51 +02005260
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005261 if (null_fd >= 0)
5262 close(null_fd);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005263
Bram Moolenaar835dc632016-02-07 14:27:38 +01005264 /* See above for type of argv. */
5265 execvp(argv[0], argv);
5266
Bram Moolenaar4694a172016-04-21 14:05:23 +02005267 if (stderr_works)
5268 perror("executing job failed");
Bram Moolenaarcda77642016-06-04 13:32:35 +02005269#ifdef EXITFREE
5270 /* calling free_all_mem() here causes problems. Ignore valgrind
5271 * reporting possibly leaked memory. */
5272#endif
Bram Moolenaar835dc632016-02-07 14:27:38 +01005273 _exit(EXEC_FAILED); /* exec failed, return failure code */
5274 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005275
5276 /* parent */
Bram Moolenaarbb09ceb2016-10-18 16:27:23 +02005277 UNBLOCK_SIGNALS(&curset);
5278
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005279 job->jv_pid = pid;
5280 job->jv_status = JOB_STARTED;
Bram Moolenaarde279892016-03-11 22:19:44 +01005281 job->jv_channel = channel; /* ch_refcount was set above */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005282
5283 /* child stdin, stdout and stderr */
Bram Moolenaarbe6aa462016-03-20 21:02:00 +01005284 if (!use_file_for_in && fd_in[0] >= 0)
Bram Moolenaarb69fccf2016-03-06 23:06:25 +01005285 close(fd_in[0]);
Bram Moolenaarbe6aa462016-03-20 21:02:00 +01005286 if (!use_file_for_out && fd_out[1] >= 0)
Bram Moolenaare98d1212016-03-08 15:37:41 +01005287 close(fd_out[1]);
Bram Moolenaarbe6aa462016-03-20 21:02:00 +01005288 if (!use_out_for_err && !use_file_for_err && fd_err[1] >= 0)
Bram Moolenaarc25558b2016-03-03 21:02:23 +01005289 close(fd_err[1]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005290 if (channel != NULL)
5291 {
5292 channel_set_pipes(channel,
5293 use_file_for_in || use_null_for_in
5294 ? INVALID_FD : fd_in[1],
5295 use_file_for_out || use_null_for_out
5296 ? INVALID_FD : fd_out[0],
5297 use_out_for_err || use_file_for_err || use_null_for_err
Bram Moolenaare98d1212016-03-08 15:37:41 +01005298 ? INVALID_FD : fd_err[0]);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005299 channel_set_job(channel, job, options);
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005300 }
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005301
Bram Moolenaarf65333c2016-03-08 18:27:21 +01005302 /* success! */
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005303 return;
5304
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005305failed:
Bram Moolenaarde279892016-03-11 22:19:44 +01005306 channel_unref(channel);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005307 if (fd_in[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005308 close(fd_in[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005309 if (fd_in[1] >= 0)
5310 close(fd_in[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005311 if (fd_out[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005312 close(fd_out[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005313 if (fd_out[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005314 close(fd_out[1]);
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005315 if (fd_err[0] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005316 close(fd_err[0]);
Bram Moolenaare98d1212016-03-08 15:37:41 +01005317 if (fd_err[1] >= 0)
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005318 close(fd_err[1]);
Bram Moolenaar835dc632016-02-07 14:27:38 +01005319}
5320
5321 char *
5322mch_job_status(job_T *job)
5323{
5324# ifdef HAVE_UNION_WAIT
5325 union wait status;
5326# else
5327 int status = -1;
5328# endif
5329 pid_t wait_pid = 0;
5330
5331# ifdef __NeXT__
5332 wait_pid = wait4(job->jv_pid, &status, WNOHANG, (struct rusage *)0);
5333# else
5334 wait_pid = waitpid(job->jv_pid, &status, WNOHANG);
5335# endif
5336 if (wait_pid == -1)
5337 {
5338 /* process must have exited */
Bram Moolenaar97792de2016-10-15 18:36:49 +02005339 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005340 }
5341 if (wait_pid == 0)
5342 return "run";
5343 if (WIFEXITED(status))
5344 {
5345 /* LINTED avoid "bitwise operation on signed value" */
5346 job->jv_exitval = WEXITSTATUS(status);
Bram Moolenaar97792de2016-10-15 18:36:49 +02005347 goto return_dead;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005348 }
Bram Moolenaar76467df2016-02-12 19:30:26 +01005349 if (WIFSIGNALED(status))
5350 {
5351 job->jv_exitval = -1;
Bram Moolenaar97792de2016-10-15 18:36:49 +02005352 goto return_dead;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005353 }
Bram Moolenaar835dc632016-02-07 14:27:38 +01005354 return "run";
Bram Moolenaar97792de2016-10-15 18:36:49 +02005355
5356return_dead:
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005357 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005358 {
5359 ch_log(job->jv_channel, "Job ended");
5360 job->jv_status = JOB_ENDED;
5361 }
5362 return "dead";
5363}
5364
5365 job_T *
5366mch_detect_ended_job(job_T *job_list)
5367{
5368# ifdef HAVE_UNION_WAIT
5369 union wait status;
5370# else
5371 int status = -1;
5372# endif
5373 pid_t wait_pid = 0;
5374 job_T *job;
5375
Bram Moolenaarc4d4ac22016-11-07 22:42:57 +01005376# ifndef USE_SYSTEM
5377 /* Do not do this when waiting for a shell command to finish, we would get
5378 * the exit value here (and discard it), the exit value obtained there
5379 * would then be wrong. */
5380 if (dont_check_job_ended > 0)
5381 return NULL;
5382# endif
5383
Bram Moolenaar97792de2016-10-15 18:36:49 +02005384# ifdef __NeXT__
5385 wait_pid = wait4(-1, &status, WNOHANG, (struct rusage *)0);
5386# else
5387 wait_pid = waitpid(-1, &status, WNOHANG);
5388# endif
5389 if (wait_pid <= 0)
5390 /* no process ended */
5391 return NULL;
5392 for (job = job_list; job != NULL; job = job->jv_next)
5393 {
5394 if (job->jv_pid == wait_pid)
5395 {
5396 if (WIFEXITED(status))
5397 /* LINTED avoid "bitwise operation on signed value" */
5398 job->jv_exitval = WEXITSTATUS(status);
5399 else if (WIFSIGNALED(status))
5400 job->jv_exitval = -1;
Bram Moolenaar7df915d2016-11-17 17:25:32 +01005401 if (job->jv_status < JOB_ENDED)
Bram Moolenaar97792de2016-10-15 18:36:49 +02005402 {
5403 ch_log(job->jv_channel, "Job ended");
5404 job->jv_status = JOB_ENDED;
5405 }
5406 return job;
5407 }
5408 }
5409 return NULL;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005410}
5411
Bram Moolenaar3a117e12016-10-30 21:57:52 +01005412/*
5413 * Send a (deadly) signal to "job".
5414 * Return FAIL if "how" is not a valid name.
5415 */
Bram Moolenaar835dc632016-02-07 14:27:38 +01005416 int
5417mch_stop_job(job_T *job, char_u *how)
5418{
Bram Moolenaar6463ca22016-02-13 17:04:46 +01005419 int sig = -1;
5420 pid_t job_pid;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005421
Bram Moolenaar923d9262016-02-25 20:56:01 +01005422 if (*how == NUL || STRCMP(how, "term") == 0)
Bram Moolenaar835dc632016-02-07 14:27:38 +01005423 sig = SIGTERM;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005424 else if (STRCMP(how, "hup") == 0)
5425 sig = SIGHUP;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005426 else if (STRCMP(how, "quit") == 0)
5427 sig = SIGQUIT;
Bram Moolenaar923d9262016-02-25 20:56:01 +01005428 else if (STRCMP(how, "int") == 0)
5429 sig = SIGINT;
Bram Moolenaar835dc632016-02-07 14:27:38 +01005430 else if (STRCMP(how, "kill") == 0)
5431 sig = SIGKILL;
5432 else if (isdigit(*how))
5433 sig = atoi((char *)how);
5434 else
5435 return FAIL;
Bram Moolenaar76467df2016-02-12 19:30:26 +01005436
Bram Moolenaar72801402016-02-09 11:37:50 +01005437 /* TODO: have an option to only kill the process, not the group? */
Bram Moolenaar76467df2016-02-12 19:30:26 +01005438 job_pid = job->jv_pid;
5439 if (job_pid == getpgid(job_pid))
5440 job_pid = -job_pid;
5441
5442 kill(job_pid, sig);
5443
Bram Moolenaar835dc632016-02-07 14:27:38 +01005444 return OK;
5445}
Bram Moolenaar76467df2016-02-12 19:30:26 +01005446
5447/*
5448 * Clear the data related to "job".
5449 */
5450 void
5451mch_clear_job(job_T *job)
5452{
5453 /* call waitpid because child process may become zombie */
5454# ifdef __NeXT__
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005455 (void)wait4(job->jv_pid, NULL, WNOHANG, (struct rusage *)0);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005456# else
Bram Moolenaar4ca812b2016-03-02 21:51:16 +01005457 (void)waitpid(job->jv_pid, NULL, WNOHANG);
Bram Moolenaar76467df2016-02-12 19:30:26 +01005458# endif
5459}
Bram Moolenaar835dc632016-02-07 14:27:38 +01005460#endif
5461
Bram Moolenaar071d4272004-06-13 20:20:40 +00005462/*
5463 * Check for CTRL-C typed by reading all available characters.
5464 * In cooked mode we should get SIGINT, no need to check.
5465 */
5466 void
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005467mch_breakcheck(int force)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005468{
Bram Moolenaarb9c31e72016-09-29 15:18:57 +02005469 if ((curr_tmode == TMODE_RAW || force)
5470 && RealWaitForChar(read_cmd_fd, 0L, NULL, NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005471 fill_input_buf(FALSE);
5472}
5473
5474/*
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005475 * Wait "msec" msec until a character is available from the mouse, keyboard,
5476 * from inbuf[].
5477 * "msec" == -1 will block forever.
5478 * Invokes timer callbacks when needed.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005479 * "interrupted" (if not NULL) is set to TRUE when no character is available
5480 * but something else needs to be done.
Bram Moolenaar40b1b542016-04-20 20:18:23 +02005481 * Returns TRUE when a character is available.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005482 * When a GUI is being used, this will never get called -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00005483 */
5484 static int
Bram Moolenaarcda77642016-06-04 13:32:35 +02005485WaitForChar(long msec, int *interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005486{
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005487#ifdef FEAT_TIMERS
5488 long due_time;
5489 long remaining = msec;
Bram Moolenaar40b1b542016-04-20 20:18:23 +02005490 int tb_change_cnt = typebuf.tb_change_cnt;
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005491
5492 /* When waiting very briefly don't trigger timers. */
5493 if (msec >= 0 && msec < 10L)
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005494 return WaitForCharOrMouse(msec, NULL);
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005495
5496 while (msec < 0 || remaining > 0)
5497 {
5498 /* Trigger timers and then get the time in msec until the next one is
5499 * due. Wait up to that time. */
5500 due_time = check_due_timer();
Bram Moolenaar40b1b542016-04-20 20:18:23 +02005501 if (typebuf.tb_change_cnt != tb_change_cnt)
5502 {
5503 /* timer may have used feedkeys() */
5504 return FALSE;
5505 }
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005506 if (due_time <= 0 || (msec > 0 && due_time > remaining))
5507 due_time = remaining;
Bram Moolenaarcda77642016-06-04 13:32:35 +02005508 if (WaitForCharOrMouse(due_time, interrupted))
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005509 return TRUE;
Bram Moolenaarcda77642016-06-04 13:32:35 +02005510 if (interrupted != NULL && *interrupted)
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005511 /* Nothing available, but need to return so that side effects get
5512 * handled, such as handling a message on a channel. */
5513 return FALSE;
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005514 if (msec > 0)
5515 remaining -= due_time;
5516 }
5517 return FALSE;
5518#else
Bram Moolenaarcda77642016-06-04 13:32:35 +02005519 return WaitForCharOrMouse(msec, interrupted);
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005520#endif
5521}
5522
5523/*
5524 * Wait "msec" msec until a character is available from the mouse or keyboard
5525 * or from inbuf[].
5526 * "msec" == -1 will block forever.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005527 * "interrupted" (if not NULL) is set to TRUE when no character is available
5528 * but something else needs to be done.
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005529 * When a GUI is being used, this will never get called -- webb
5530 */
5531 static int
Bram Moolenaarcda77642016-06-04 13:32:35 +02005532WaitForCharOrMouse(long msec, int *interrupted)
Bram Moolenaar943bb2b2016-03-19 14:11:18 +01005533{
Bram Moolenaar071d4272004-06-13 20:20:40 +00005534#ifdef FEAT_MOUSE_GPM
5535 int gpm_process_wanted;
5536#endif
5537#ifdef FEAT_XCLIPBOARD
5538 int rest;
5539#endif
5540 int avail;
5541
5542 if (input_available()) /* something in inbuf[] */
5543 return 1;
5544
5545#if defined(FEAT_MOUSE_DEC)
5546 /* May need to query the mouse position. */
5547 if (WantQueryMouse)
5548 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00005549 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005550 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
5551 }
5552#endif
5553
5554 /*
5555 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
5556 * events. This is a bit complicated, because they might both be defined.
5557 */
5558#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
5559# ifdef FEAT_XCLIPBOARD
5560 rest = 0;
5561 if (do_xterm_trace())
5562 rest = msec;
5563# endif
5564 do
5565 {
5566# ifdef FEAT_XCLIPBOARD
5567 if (rest != 0)
5568 {
5569 msec = XT_TRACE_DELAY;
5570 if (rest >= 0 && rest < XT_TRACE_DELAY)
5571 msec = rest;
5572 if (rest >= 0)
5573 rest -= msec;
5574 }
5575# endif
5576# ifdef FEAT_MOUSE_GPM
5577 gpm_process_wanted = 0;
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005578 avail = RealWaitForChar(read_cmd_fd, msec,
Bram Moolenaarcda77642016-06-04 13:32:35 +02005579 &gpm_process_wanted, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005580# else
Bram Moolenaarcda77642016-06-04 13:32:35 +02005581 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005582# endif
5583 if (!avail)
5584 {
5585 if (input_available())
5586 return 1;
5587# ifdef FEAT_XCLIPBOARD
5588 if (rest == 0 || !do_xterm_trace())
5589# endif
5590 break;
5591 }
5592 }
5593 while (FALSE
5594# ifdef FEAT_MOUSE_GPM
5595 || (gpm_process_wanted && mch_gpm_process() == 0)
5596# endif
5597# ifdef FEAT_XCLIPBOARD
5598 || (!avail && rest != 0)
5599# endif
Bram Moolenaar8fdd7212016-03-26 19:41:48 +01005600 )
5601 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005602
5603#else
Bram Moolenaarcda77642016-06-04 13:32:35 +02005604 avail = RealWaitForChar(read_cmd_fd, msec, NULL, interrupted);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005605#endif
5606 return avail;
5607}
5608
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01005609#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00005610/*
5611 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005612 * "msec" == 0 will check for characters once.
5613 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005614 * When a GUI is being used, this will not be used for input -- webb
Bram Moolenaar071d4272004-06-13 20:20:40 +00005615 * Or when a Linux GPM mouse event is waiting.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02005616 * Or when a clientserver message is on the queue.
Bram Moolenaarcda77642016-06-04 13:32:35 +02005617 * "interrupted" (if not NULL) is set to TRUE when no character is available
5618 * but something else needs to be done.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005619 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005620#if defined(__BEOS__)
5621 int
5622#else
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01005623 static int
Bram Moolenaar071d4272004-06-13 20:20:40 +00005624#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02005625RealWaitForChar(int fd, long msec, int *check_for_gpm UNUSED, int *interrupted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005626{
5627 int ret;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01005628 int result;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005629#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005630 static int busy = FALSE;
5631
5632 /* May retry getting characters after an event was handled. */
5633# define MAY_LOOP
5634
5635# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5636 /* Remember at what time we started, so that we know how much longer we
5637 * should wait after being interrupted. */
5638# define USE_START_TV
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02005639 long start_msec = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005640 struct timeval start_tv;
5641
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02005642 if (msec > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005643 gettimeofday(&start_tv, NULL);
5644# endif
5645
5646 /* Handle being called recursively. This may happen for the session
5647 * manager stuff, it may save the file, which does a breakcheck. */
5648 if (busy)
5649 return 0;
5650#endif
5651
5652#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00005653 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005654#endif
5655 {
5656#ifdef MAY_LOOP
5657 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005658# ifdef FEAT_MZSCHEME
5659 int mzquantum_used = FALSE;
5660# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005661#endif
5662#ifndef HAVE_SELECT
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02005663 /* each channel may use in, out and err */
5664 struct pollfd fds[6 + 3 * MAX_OPEN_CHANNELS];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005665 int nfd;
5666# ifdef FEAT_XCLIPBOARD
5667 int xterm_idx = -1;
5668# endif
5669# ifdef FEAT_MOUSE_GPM
5670 int gpm_idx = -1;
5671# endif
5672# ifdef USE_XSMP
5673 int xsmp_idx = -1;
5674# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005675 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005676
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005677# ifdef FEAT_MZSCHEME
5678 mzvim_check_threads();
5679 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5680 {
5681 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
5682 mzquantum_used = TRUE;
5683 }
5684# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005685 fds[0].fd = fd;
5686 fds[0].events = POLLIN;
5687 nfd = 1;
5688
Bram Moolenaar071d4272004-06-13 20:20:40 +00005689# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01005690 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005691 if (xterm_Shell != (Widget)0)
5692 {
5693 xterm_idx = nfd;
5694 fds[nfd].fd = ConnectionNumber(xterm_dpy);
5695 fds[nfd].events = POLLIN;
5696 nfd++;
5697 }
5698# endif
5699# ifdef FEAT_MOUSE_GPM
5700 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5701 {
5702 gpm_idx = nfd;
5703 fds[nfd].fd = gpm_fd;
5704 fds[nfd].events = POLLIN;
5705 nfd++;
5706 }
5707# endif
5708# ifdef USE_XSMP
5709 if (xsmp_icefd != -1)
5710 {
5711 xsmp_idx = nfd;
5712 fds[nfd].fd = xsmp_icefd;
5713 fds[nfd].events = POLLIN;
5714 nfd++;
5715 }
5716# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005717#ifdef FEAT_JOB_CHANNEL
Bram Moolenaare0874f82016-01-24 20:36:41 +01005718 nfd = channel_poll_setup(nfd, &fds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02005719#endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02005720 if (interrupted != NULL)
5721 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005722
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005723 ret = poll(fds, nfd, towait);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01005724
5725 result = ret > 0 && (fds[0].revents & POLLIN);
Bram Moolenaarcda77642016-06-04 13:32:35 +02005726 if (result == 0 && interrupted != NULL && ret > 0)
5727 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01005728
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005729# ifdef FEAT_MZSCHEME
5730 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005731 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005732 finished = FALSE;
5733# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005734
Bram Moolenaar071d4272004-06-13 20:20:40 +00005735# ifdef FEAT_XCLIPBOARD
5736 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
5737 {
5738 xterm_update(); /* Maybe we should hand out clipboard */
5739 if (--ret == 0 && !input_available())
5740 /* Try again */
5741 finished = FALSE;
5742 }
5743# endif
5744# ifdef FEAT_MOUSE_GPM
5745 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
5746 {
5747 *check_for_gpm = 1;
5748 }
5749# endif
5750# ifdef USE_XSMP
5751 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
5752 {
5753 if (fds[xsmp_idx].revents & POLLIN)
5754 {
5755 busy = TRUE;
5756 xsmp_handle_requests();
5757 busy = FALSE;
5758 }
5759 else if (fds[xsmp_idx].revents & POLLHUP)
5760 {
5761 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005762 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005763 xsmp_close();
5764 }
5765 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005766 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005767 }
5768# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005769#ifdef FEAT_JOB_CHANNEL
Bram Moolenaare0874f82016-01-24 20:36:41 +01005770 if (ret > 0)
5771 ret = channel_poll_check(ret, &fds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02005772#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005773
Bram Moolenaar071d4272004-06-13 20:20:40 +00005774#else /* HAVE_SELECT */
5775
5776 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005777 struct timeval *tvp;
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02005778 fd_set rfds, wfds, efds;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005779 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005780 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005781
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005782# ifdef FEAT_MZSCHEME
5783 mzvim_check_threads();
5784 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5785 {
5786 towait = p_mzq; /* don't wait longer than 'mzquantum' */
5787 mzquantum_used = TRUE;
5788 }
5789# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005790
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005791 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005792 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005793 tv.tv_sec = towait / 1000;
5794 tv.tv_usec = (towait % 1000) * (1000000/1000);
5795 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005796 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005797 else
5798 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005799
5800 /*
5801 * Select on ready for reading and exceptional condition (end of file).
5802 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005803select_eintr:
5804 FD_ZERO(&rfds);
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02005805 FD_ZERO(&wfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005806 FD_ZERO(&efds);
5807 FD_SET(fd, &rfds);
5808# if !defined(__QNX__) && !defined(__CYGWIN32__)
5809 /* For QNX select() always returns 1 if this is set. Why? */
5810 FD_SET(fd, &efds);
5811# endif
5812 maxfd = fd;
5813
Bram Moolenaar071d4272004-06-13 20:20:40 +00005814# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01005815 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005816 if (xterm_Shell != (Widget)0)
5817 {
5818 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
5819 if (maxfd < ConnectionNumber(xterm_dpy))
5820 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02005821
5822 /* An event may have already been read but not handled. In
5823 * particulary, XFlush may cause this. */
5824 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005825 }
5826# endif
5827# ifdef FEAT_MOUSE_GPM
5828 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5829 {
5830 FD_SET(gpm_fd, &rfds);
5831 FD_SET(gpm_fd, &efds);
5832 if (maxfd < gpm_fd)
5833 maxfd = gpm_fd;
5834 }
5835# endif
5836# ifdef USE_XSMP
5837 if (xsmp_icefd != -1)
5838 {
5839 FD_SET(xsmp_icefd, &rfds);
5840 FD_SET(xsmp_icefd, &efds);
5841 if (maxfd < xsmp_icefd)
5842 maxfd = xsmp_icefd;
5843 }
5844# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005845# ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02005846 maxfd = channel_select_setup(maxfd, &rfds, &wfds);
Bram Moolenaardd82d692012-08-15 17:26:57 +02005847# endif
Bram Moolenaarcda77642016-06-04 13:32:35 +02005848 if (interrupted != NULL)
5849 *interrupted = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005850
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02005851 ret = select(maxfd + 1, &rfds, &wfds, &efds, tvp);
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01005852 result = ret > 0 && FD_ISSET(fd, &rfds);
5853 if (result)
5854 --ret;
Bram Moolenaarcda77642016-06-04 13:32:35 +02005855 else if (interrupted != NULL && ret > 0)
5856 *interrupted = TRUE;
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01005857
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005858# ifdef EINTR
5859 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005860 {
5861 /* Check whether window has been resized, EINTR may be caused by
5862 * SIGWINCH. */
5863 if (do_resize)
5864 handle_resize();
5865
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005866 /* Interrupted by a signal, need to try again. We ignore msec
5867 * here, because we do want to check even after a timeout if
5868 * characters are available. Needed for reading output of an
5869 * external command after the process has finished. */
5870 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005871 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005872# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00005873# ifdef __TANDEM
5874 if (ret == -1 && errno == ENOTSUP)
5875 {
5876 FD_ZERO(&rfds);
5877 FD_ZERO(&efds);
5878 ret = 0;
5879 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005880# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005881# ifdef FEAT_MZSCHEME
5882 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005883 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005884 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005885# endif
5886
Bram Moolenaar071d4272004-06-13 20:20:40 +00005887# ifdef FEAT_XCLIPBOARD
5888 if (ret > 0 && xterm_Shell != (Widget)0
5889 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
5890 {
5891 xterm_update(); /* Maybe we should hand out clipboard */
5892 /* continue looping when we only got the X event and the input
5893 * buffer is empty */
5894 if (--ret == 0 && !input_available())
5895 {
5896 /* Try again */
5897 finished = FALSE;
5898 }
5899 }
5900# endif
5901# ifdef FEAT_MOUSE_GPM
5902 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
5903 {
5904 if (FD_ISSET(gpm_fd, &efds))
5905 gpm_close();
5906 else if (FD_ISSET(gpm_fd, &rfds))
5907 *check_for_gpm = 1;
5908 }
5909# endif
5910# ifdef USE_XSMP
5911 if (ret > 0 && xsmp_icefd != -1)
5912 {
5913 if (FD_ISSET(xsmp_icefd, &efds))
5914 {
5915 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005916 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005917 xsmp_close();
5918 if (--ret == 0)
5919 finished = FALSE; /* keep going if event was only one */
5920 }
5921 else if (FD_ISSET(xsmp_icefd, &rfds))
5922 {
5923 busy = TRUE;
5924 xsmp_handle_requests();
5925 busy = FALSE;
5926 if (--ret == 0)
5927 finished = FALSE; /* keep going if event was only one */
5928 }
5929 }
5930# endif
Bram Moolenaar509ce2a2016-03-11 22:52:15 +01005931#ifdef FEAT_JOB_CHANNEL
Bram Moolenaare0874f82016-01-24 20:36:41 +01005932 if (ret > 0)
Bram Moolenaar8b877ac2016-03-28 19:16:20 +02005933 ret = channel_select_check(ret, &rfds, &wfds);
Bram Moolenaar67c53842010-05-22 18:28:27 +02005934#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005935
5936#endif /* HAVE_SELECT */
5937
5938#ifdef MAY_LOOP
5939 if (finished || msec == 0)
5940 break;
5941
Bram Moolenaar93c88e02015-09-15 14:12:05 +02005942# ifdef FEAT_CLIENTSERVER
5943 if (server_waiting())
5944 break;
5945# endif
5946
Bram Moolenaar071d4272004-06-13 20:20:40 +00005947 /* We're going to loop around again, find out for how long */
5948 if (msec > 0)
5949 {
5950# ifdef USE_START_TV
Bram Moolenaar071d4272004-06-13 20:20:40 +00005951 /* Compute remaining wait time. */
Bram Moolenaar76b6dfe2016-06-04 14:37:22 +02005952 msec = start_msec - elapsed(&start_tv);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005953# else
5954 /* Guess we got interrupted halfway. */
5955 msec = msec / 2;
5956# endif
5957 if (msec <= 0)
5958 break; /* waited long enough */
5959 }
5960#endif
5961 }
5962
Bram Moolenaarec70bdd2016-02-18 22:17:42 +01005963 return result;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005964}
5965
Bram Moolenaar071d4272004-06-13 20:20:40 +00005966#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00005967/*
Bram Moolenaar02743632005-07-25 20:42:36 +00005968 * Expand a path into all matching files and/or directories. Handles "*",
5969 * "?", "[a-z]", "**", etc.
5970 * "path" has backslashes before chars that are not to be expanded.
5971 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005972 */
5973 int
Bram Moolenaar05540972016-01-30 20:31:25 +01005974mch_expandpath(
5975 garray_T *gap,
5976 char_u *path,
5977 int flags) /* EW_* flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005978{
Bram Moolenaar02743632005-07-25 20:42:36 +00005979 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005980}
5981#endif
5982
5983/*
5984 * mch_expand_wildcards() - this code does wild-card pattern matching using
5985 * the shell
5986 *
5987 * return OK for success, FAIL for error (you may lose some memory) and put
5988 * an error message in *file.
5989 *
5990 * num_pat is number of input patterns
5991 * pat is array of pointers to input patterns
5992 * num_file is pointer to number of matched file names
5993 * file is pointer to array of pointers to matched file names
5994 */
5995
5996#ifndef SEEK_SET
5997# define SEEK_SET 0
5998#endif
5999#ifndef SEEK_END
6000# define SEEK_END 2
6001#endif
6002
Bram Moolenaar5555acc2006-04-07 21:33:12 +00006003#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00006004
Bram Moolenaar071d4272004-06-13 20:20:40 +00006005 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006006mch_expand_wildcards(
6007 int num_pat,
6008 char_u **pat,
6009 int *num_file,
6010 char_u ***file,
6011 int flags) /* EW_* flags */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006012{
6013 int i;
6014 size_t len;
6015 char_u *p;
6016 int dir;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006017
Bram Moolenaarc7247912008-01-13 12:54:11 +00006018 /*
6019 * This is the non-OS/2 implementation (really Unix).
6020 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006021 int j;
6022 char_u *tempname;
6023 char_u *command;
6024 FILE *fd;
6025 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006026#define STYLE_ECHO 0 /* use "echo", the default */
6027#define STYLE_GLOB 1 /* use "glob", for csh */
6028#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
6029#define STYLE_PRINT 3 /* use "print -N", for zsh */
6030#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
6031 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006032 int shell_style = STYLE_ECHO;
6033 int check_spaces;
6034 static int did_find_nul = FALSE;
6035 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006036 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006037 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00006038
6039 *num_file = 0; /* default: no files found */
6040 *file = NULL;
6041
6042 /*
6043 * If there are no wildcards, just copy the names to allocated memory.
6044 * Saves a lot of time, because we don't have to start a new shell.
6045 */
6046 if (!have_wildcard(num_pat, pat))
6047 return save_patterns(num_pat, pat, num_file, file);
6048
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006049# ifdef HAVE_SANDBOX
6050 /* Don't allow any shell command in the sandbox. */
6051 if (sandbox != 0 && check_secure())
6052 return FAIL;
6053# endif
6054
Bram Moolenaar071d4272004-06-13 20:20:40 +00006055 /*
6056 * Don't allow the use of backticks in secure and restricted mode.
6057 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00006058 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006059 for (i = 0; i < num_pat; ++i)
6060 if (vim_strchr(pat[i], '`') != NULL
6061 && (check_restricted() || check_secure()))
6062 return FAIL;
6063
6064 /*
6065 * get a name for the temp file
6066 */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02006067 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006068 {
6069 EMSG(_(e_notmp));
6070 return FAIL;
6071 }
6072
6073 /*
6074 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00006075 * file.
6076 * STYLE_BT: NL separated
6077 * If expanding `cmd` execute it directly.
6078 * STYLE_GLOB: NUL separated
6079 * If we use *csh, "glob" will work better than "echo".
6080 * STYLE_PRINT: NL or NUL separated
6081 * If we use *zsh, "print -N" will work better than "glob".
6082 * STYLE_VIMGLOB: NL separated
6083 * If we use *sh*, we define "vimglob()".
6084 * STYLE_ECHO: space separated.
6085 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00006086 */
6087 if (num_pat == 1 && *pat[0] == '`'
6088 && (len = STRLEN(pat[0])) > 2
6089 && *(pat[0] + len - 1) == '`')
6090 shell_style = STYLE_BT;
6091 else if ((len = STRLEN(p_sh)) >= 3)
6092 {
6093 if (STRCMP(p_sh + len - 3, "csh") == 0)
6094 shell_style = STYLE_GLOB;
6095 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
6096 shell_style = STYLE_PRINT;
6097 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006098 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
6099 "sh") != NULL)
6100 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006101
Bram Moolenaarc7247912008-01-13 12:54:11 +00006102 /* Compute the length of the command. We need 2 extra bytes: for the
6103 * optional '&' and for the NUL.
6104 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006105 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00006106 if (shell_style == STYLE_VIMGLOB)
6107 len += STRLEN(sh_vimglob_func);
6108
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006109 for (i = 0; i < num_pat; ++i)
6110 {
6111 /* Count the length of the patterns in the same way as they are put in
6112 * "command" below. */
6113#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00006114 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006115#else
6116 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006117 for (j = 0; pat[i][j] != NUL; ++j)
6118 {
6119 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
6120 ++len; /* may add a backslash */
6121 ++len;
6122 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00006123#endif
6124 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006125 command = alloc(len);
6126 if (command == NULL)
6127 {
6128 /* out of memory */
6129 vim_free(tempname);
6130 return FAIL;
6131 }
6132
6133 /*
6134 * Build the shell command:
6135 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
6136 * recognizes this).
6137 * - Add the shell command to print the expanded names.
6138 * - Add the temp file name.
6139 * - Add the file name patterns.
6140 */
6141 if (shell_style == STYLE_BT)
6142 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00006143 /* change `command; command& ` to (command; command ) */
6144 STRCPY(command, "(");
6145 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006146 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006147 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006148 while (p > command && vim_iswhite(*p))
6149 --p;
6150 if (*p == '&') /* remove trailing '&' */
6151 {
6152 ampersent = TRUE;
6153 *p = ' ';
6154 }
6155 STRCAT(command, ">");
6156 }
6157 else
6158 {
6159 if (flags & EW_NOTFOUND)
6160 STRCPY(command, "set nonomatch; ");
6161 else
6162 STRCPY(command, "unset nonomatch; ");
6163 if (shell_style == STYLE_GLOB)
6164 STRCAT(command, "glob >");
6165 else if (shell_style == STYLE_PRINT)
6166 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00006167 else if (shell_style == STYLE_VIMGLOB)
6168 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006169 else
6170 STRCAT(command, "echo >");
6171 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00006172
Bram Moolenaar071d4272004-06-13 20:20:40 +00006173 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00006174
Bram Moolenaar071d4272004-06-13 20:20:40 +00006175 if (shell_style != STYLE_BT)
6176 for (i = 0; i < num_pat; ++i)
6177 {
6178 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00006179 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006180 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006181#ifdef USE_SYSTEM
6182 STRCAT(command, " \"");
6183 STRCAT(command, pat[i]);
6184 STRCAT(command, "\"");
6185#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00006186 int intick = FALSE;
6187
Bram Moolenaar071d4272004-06-13 20:20:40 +00006188 p = command + STRLEN(command);
6189 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00006190 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00006191 {
6192 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00006193 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006194 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
6195 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006196 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00006197 * backslash inside backticks, before a special character
6198 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006199 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00006200 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
6201 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00006202 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006203 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00006204 }
Bram Moolenaare4df1642014-08-29 12:58:44 +02006205 else if (!intick
6206 && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
6207 && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00006208 /* Put a backslash before a special character, but not
Bram Moolenaare4df1642014-08-29 12:58:44 +02006209 * when inside ``. And not for $var when EW_KEEPDOLLAR is
6210 * set. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00006211 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00006212
6213 /* Copy one character. */
6214 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00006215 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006216 *p = NUL;
6217#endif
6218 }
6219 if (flags & EW_SILENT)
6220 show_shell_mess = FALSE;
6221 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00006222 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006223
6224 /*
6225 * Using zsh -G: If a pattern has no matches, it is just deleted from
6226 * the argument list, otherwise zsh gives an error message and doesn't
6227 * expand any other pattern.
6228 */
6229 if (shell_style == STYLE_PRINT)
6230 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
6231
6232 /*
6233 * If we use -f then shell variables set in .cshrc won't get expanded.
6234 * vi can do it, so we will too, but it is only necessary if there is a "$"
6235 * in one of the patterns, otherwise we can still use the fast option.
6236 */
6237 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
6238 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
6239
6240 /*
6241 * execute the shell command
6242 */
6243 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
6244
6245 /* When running in the background, give it some time to create the temp
6246 * file, but don't wait for it to finish. */
6247 if (ampersent)
6248 mch_delay(10L, TRUE);
6249
6250 extra_shell_arg = NULL; /* cleanup */
6251 show_shell_mess = TRUE;
6252 vim_free(command);
6253
Bram Moolenaarc7247912008-01-13 12:54:11 +00006254 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006255 {
6256 mch_remove(tempname);
6257 vim_free(tempname);
6258 /*
6259 * With interactive completion, the error message is not printed.
6260 * However with USE_SYSTEM, I don't know how to turn off error messages
6261 * from the shell, so screen may still get messed up -- webb.
6262 */
6263#ifndef USE_SYSTEM
6264 if (!(flags & EW_SILENT))
6265#endif
6266 {
6267 redraw_later_clear(); /* probably messed up screen */
6268 msg_putchar('\n'); /* clear bottom line quickly */
6269 cmdline_row = Rows - 1; /* continue on last line */
6270#ifdef USE_SYSTEM
6271 if (!(flags & EW_SILENT))
6272#endif
6273 {
6274 MSG(_(e_wildexpand));
6275 msg_start(); /* don't overwrite this message */
6276 }
6277 }
6278 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
6279 * EW_NOTFOUND is given */
6280 if (shell_style == STYLE_BT)
6281 return FAIL;
6282 goto notfound;
6283 }
6284
6285 /*
6286 * read the names from the file into memory
6287 */
6288 fd = fopen((char *)tempname, READBIN);
6289 if (fd == NULL)
6290 {
6291 /* Something went wrong, perhaps a file name with a special char. */
6292 if (!(flags & EW_SILENT))
6293 {
6294 MSG(_(e_wildexpand));
6295 msg_start(); /* don't overwrite this message */
6296 }
6297 vim_free(tempname);
6298 goto notfound;
6299 }
6300 fseek(fd, 0L, SEEK_END);
6301 len = ftell(fd); /* get size of temp file */
6302 fseek(fd, 0L, SEEK_SET);
6303 buffer = alloc(len + 1);
6304 if (buffer == NULL)
6305 {
6306 /* out of memory */
6307 mch_remove(tempname);
6308 vim_free(tempname);
6309 fclose(fd);
6310 return FAIL;
6311 }
6312 i = fread((char *)buffer, 1, len, fd);
6313 fclose(fd);
6314 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00006315 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006316 {
6317 /* unexpected read error */
6318 EMSG2(_(e_notread), tempname);
6319 vim_free(tempname);
6320 vim_free(buffer);
6321 return FAIL;
6322 }
6323 vim_free(tempname);
6324
Bram Moolenaarc7247912008-01-13 12:54:11 +00006325# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006326 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
6327 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02006328 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006329 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
6330 *p++ = buffer[i];
6331 len = p - buffer;
6332# endif
6333
6334
6335 /* file names are separated with Space */
6336 if (shell_style == STYLE_ECHO)
6337 {
6338 buffer[len] = '\n'; /* make sure the buffer ends in NL */
6339 p = buffer;
6340 for (i = 0; *p != '\n'; ++i) /* count number of entries */
6341 {
6342 while (*p != ' ' && *p != '\n')
6343 ++p;
6344 p = skipwhite(p); /* skip to next entry */
6345 }
6346 }
6347 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006348 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006349 {
6350 buffer[len] = NUL; /* make sure the buffer ends in NUL */
6351 p = buffer;
6352 for (i = 0; *p != NUL; ++i) /* count number of entries */
6353 {
6354 while (*p != '\n' && *p != NUL)
6355 ++p;
6356 if (*p != NUL)
6357 ++p;
6358 p = skipwhite(p); /* skip leading white space */
6359 }
6360 }
6361 /* file names are separated with NUL */
6362 else
6363 {
6364 /*
6365 * Some versions of zsh use spaces instead of NULs to separate
6366 * results. Only do this when there is no NUL before the end of the
6367 * buffer, otherwise we would never be able to use file names with
6368 * embedded spaces when zsh does use NULs.
6369 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6370 * don't check for spaces again.
6371 */
6372 check_spaces = FALSE;
6373 if (shell_style == STYLE_PRINT && !did_find_nul)
6374 {
6375 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006376 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006377 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006378 did_find_nul = TRUE;
6379 else
6380 check_spaces = TRUE;
6381 }
6382
6383 /*
6384 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6385 * already is one, for STYLE_GLOB it needs to be added.
6386 */
6387 if (len && buffer[len - 1] == NUL)
6388 --len;
6389 else
6390 buffer[len] = NUL;
6391 i = 0;
6392 for (p = buffer; p < buffer + len; ++p)
6393 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
6394 {
6395 ++i;
6396 *p = NUL;
6397 }
6398 if (len)
6399 ++i; /* count last entry */
6400 }
6401 if (i == 0)
6402 {
6403 /*
6404 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6405 * /bin/sh will happily expand it to nothing rather than returning an
6406 * error; and hey, it's good to check anyway -- webb.
6407 */
6408 vim_free(buffer);
6409 goto notfound;
6410 }
6411 *num_file = i;
6412 *file = (char_u **)alloc(sizeof(char_u *) * i);
6413 if (*file == NULL)
6414 {
6415 /* out of memory */
6416 vim_free(buffer);
6417 return FAIL;
6418 }
6419
6420 /*
6421 * Isolate the individual file names.
6422 */
6423 p = buffer;
6424 for (i = 0; i < *num_file; ++i)
6425 {
6426 (*file)[i] = p;
6427 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006428 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6429 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006430 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006431 while (!(shell_style == STYLE_ECHO && *p == ' ')
6432 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006433 ++p;
6434 if (p == buffer + len) /* last entry */
6435 *p = NUL;
6436 else
6437 {
6438 *p++ = NUL;
6439 p = skipwhite(p); /* skip to next entry */
6440 }
6441 }
6442 else /* NUL separates */
6443 {
6444 while (*p && p < buffer + len) /* skip entry */
6445 ++p;
6446 ++p; /* skip NUL */
6447 }
6448 }
6449
6450 /*
6451 * Move the file names to allocated memory.
6452 */
6453 for (j = 0, i = 0; i < *num_file; ++i)
6454 {
6455 /* Require the files to exist. Helps when using /bin/sh */
6456 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6457 continue;
6458
6459 /* check if this entry should be included */
6460 dir = (mch_isdir((*file)[i]));
6461 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6462 continue;
6463
Bram Moolenaara2031822006-03-07 22:29:51 +00006464 /* Skip files that are not executable if we check for that. */
Bram Moolenaarb5971142015-03-21 17:32:19 +01006465 if (!dir && (flags & EW_EXEC)
6466 && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00006467 continue;
6468
Bram Moolenaar071d4272004-06-13 20:20:40 +00006469 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
6470 if (p)
6471 {
6472 STRCPY(p, (*file)[i]);
6473 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00006474 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006475 (*file)[j++] = p;
6476 }
6477 }
6478 vim_free(buffer);
6479 *num_file = j;
6480
6481 if (*num_file == 0) /* rejected all entries */
6482 {
6483 vim_free(*file);
6484 *file = NULL;
6485 goto notfound;
6486 }
6487
6488 return OK;
6489
6490notfound:
6491 if (flags & EW_NOTFOUND)
6492 return save_patterns(num_pat, pat, num_file, file);
6493 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006494}
6495
6496#endif /* VMS */
6497
Bram Moolenaar071d4272004-06-13 20:20:40 +00006498 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006499save_patterns(
6500 int num_pat,
6501 char_u **pat,
6502 int *num_file,
6503 char_u ***file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006504{
6505 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006506 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006507
6508 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
6509 if (*file == NULL)
6510 return FAIL;
6511 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006512 {
6513 s = vim_strsave(pat[i]);
6514 if (s != NULL)
6515 /* Be compatible with expand_filename(): halve the number of
6516 * backslashes. */
6517 backslash_halve(s);
6518 (*file)[i] = s;
6519 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006520 *num_file = num_pat;
6521 return OK;
6522}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006523
Bram Moolenaar071d4272004-06-13 20:20:40 +00006524/*
6525 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
6526 * expand.
6527 */
6528 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006529mch_has_exp_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006530{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006531 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006532 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006533 if (*p == '\\' && p[1] != NUL)
6534 ++p;
6535 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006536 if (vim_strchr((char_u *)
6537#ifdef VMS
6538 "*?%"
6539#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006540 "*?[{'"
Bram Moolenaar071d4272004-06-13 20:20:40 +00006541#endif
6542 , *p) != NULL)
6543 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006544 }
6545 return FALSE;
6546}
6547
6548/*
6549 * Return TRUE if the string "p" contains a wildcard.
6550 * Don't recognize '~' at the end as a wildcard.
6551 */
6552 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006553mch_has_wildcard(char_u *p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006554{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006555 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006556 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00006557 if (*p == '\\' && p[1] != NUL)
6558 ++p;
6559 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006560 if (vim_strchr((char_u *)
6561#ifdef VMS
6562 "*?%$"
6563#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006564 "*?[{`'$"
Bram Moolenaar071d4272004-06-13 20:20:40 +00006565#endif
6566 , *p) != NULL
6567 || (*p == '~' && p[1] != NUL))
6568 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006569 }
6570 return FALSE;
6571}
6572
Bram Moolenaar071d4272004-06-13 20:20:40 +00006573 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006574have_wildcard(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006575{
6576 int i;
6577
6578 for (i = 0; i < num; i++)
6579 if (mch_has_wildcard(file[i]))
6580 return 1;
6581 return 0;
6582}
6583
6584 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006585have_dollars(int num, char_u **file)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006586{
6587 int i;
6588
6589 for (i = 0; i < num; i++)
6590 if (vim_strchr(file[i], '$') != NULL)
6591 return TRUE;
6592 return FALSE;
6593}
Bram Moolenaar071d4272004-06-13 20:20:40 +00006594
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01006595#if !defined(HAVE_RENAME) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006596/*
6597 * Scaled-down version of rename(), which is missing in Xenix.
6598 * This version can only move regular files and will fail if the
6599 * destination exists.
6600 */
6601 int
Bram Moolenaarfdcc9af2016-02-29 12:52:39 +01006602mch_rename(const char *src, const char *dest)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006603{
6604 struct stat st;
6605
6606 if (stat(dest, &st) >= 0) /* fail if destination exists */
6607 return -1;
6608 if (link(src, dest) != 0) /* link file to new name */
6609 return -1;
6610 if (mch_remove(src) == 0) /* delete link to old name */
6611 return 0;
6612 return -1;
6613}
6614#endif /* !HAVE_RENAME */
6615
6616#ifdef FEAT_MOUSE_GPM
6617/*
6618 * Initializes connection with gpm (if it isn't already opened)
6619 * Return 1 if succeeded (or connection already opened), 0 if failed
6620 */
6621 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006622gpm_open(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006623{
6624 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
6625
6626 if (!gpm_flag)
6627 {
6628 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
6629 gpm_connect.defaultMask = ~GPM_HARD;
6630 /* Default handling for mouse move*/
6631 gpm_connect.minMod = 0; /* Handle any modifier keys */
6632 gpm_connect.maxMod = 0xffff;
6633 if (Gpm_Open(&gpm_connect, 0) > 0)
6634 {
6635 /* gpm library tries to handling TSTP causes
6636 * problems. Anyways, we close connection to Gpm whenever
6637 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006638 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00006639 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006640# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00006641 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006642# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006643 return 1; /* succeed */
6644 }
6645 if (gpm_fd == -2)
6646 Gpm_Close(); /* We don't want to talk to xterm via gpm */
6647 return 0;
6648 }
6649 return 1; /* already open */
6650}
6651
6652/*
6653 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00006654 */
6655 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01006656gpm_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006657{
6658 if (gpm_flag && gpm_fd >= 0) /* if Open */
6659 Gpm_Close();
6660}
6661
6662/* Reads gpm event and adds special keys to input buf. Returns length of
6663 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02006664 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00006665 */
6666 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006667mch_gpm_process(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006668{
6669 int button;
6670 static Gpm_Event gpm_event;
6671 char_u string[6];
6672 int_u vim_modifiers;
6673 int row,col;
6674 unsigned char buttons_mask;
6675 unsigned char gpm_modifiers;
6676 static unsigned char old_buttons = 0;
6677
6678 Gpm_GetEvent(&gpm_event);
6679
6680#ifdef FEAT_GUI
6681 /* Don't put events in the input queue now. */
6682 if (hold_gui_events)
6683 return 0;
6684#endif
6685
6686 row = gpm_event.y - 1;
6687 col = gpm_event.x - 1;
6688
6689 string[0] = ESC; /* Our termcode */
6690 string[1] = 'M';
6691 string[2] = 'G';
6692 switch (GPM_BARE_EVENTS(gpm_event.type))
6693 {
6694 case GPM_DRAG:
6695 string[3] = MOUSE_DRAG;
6696 break;
6697 case GPM_DOWN:
6698 buttons_mask = gpm_event.buttons & ~old_buttons;
6699 old_buttons = gpm_event.buttons;
6700 switch (buttons_mask)
6701 {
6702 case GPM_B_LEFT:
6703 button = MOUSE_LEFT;
6704 break;
6705 case GPM_B_MIDDLE:
6706 button = MOUSE_MIDDLE;
6707 break;
6708 case GPM_B_RIGHT:
6709 button = MOUSE_RIGHT;
6710 break;
6711 default:
6712 return 0;
6713 /*Don't know what to do. Can more than one button be
6714 * reported in one event? */
6715 }
6716 string[3] = (char_u)(button | 0x20);
6717 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
6718 break;
6719 case GPM_UP:
6720 string[3] = MOUSE_RELEASE;
6721 old_buttons &= ~gpm_event.buttons;
6722 break;
6723 default:
6724 return 0;
6725 }
6726 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
6727 gpm_modifiers = gpm_event.modifiers;
6728 vim_modifiers = 0x0;
6729 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
6730 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
6731 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
6732 */
6733 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
6734 vim_modifiers |= MOUSE_SHIFT;
6735
6736 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
6737 vim_modifiers |= MOUSE_CTRL;
6738 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
6739 vim_modifiers |= MOUSE_ALT;
6740 string[3] |= vim_modifiers;
6741 string[4] = (char_u)(col + ' ' + 1);
6742 string[5] = (char_u)(row + ' ' + 1);
6743 add_to_input_buf(string, 6);
6744 return 6;
6745}
6746#endif /* FEAT_MOUSE_GPM */
6747
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006748#ifdef FEAT_SYSMOUSE
6749/*
6750 * Initialize connection with sysmouse.
6751 * Let virtual console inform us with SIGUSR2 for pending sysmouse
6752 * output, any sysmouse output than will be processed via sig_sysmouse().
6753 * Return OK if succeeded, FAIL if failed.
6754 */
6755 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01006756sysmouse_open(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006757{
6758 struct mouse_info mouse;
6759
6760 mouse.operation = MOUSE_MODE;
6761 mouse.u.mode.mode = 0;
6762 mouse.u.mode.signal = SIGUSR2;
6763 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
6764 {
6765 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
6766 mouse.operation = MOUSE_SHOW;
6767 ioctl(1, CONS_MOUSECTL, &mouse);
6768 return OK;
6769 }
6770 return FAIL;
6771}
6772
6773/*
6774 * Stop processing SIGUSR2 signals, and also make sure that
6775 * virtual console do not send us any sysmouse related signal.
6776 */
6777 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01006778sysmouse_close(void)
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006779{
6780 struct mouse_info mouse;
6781
6782 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
6783 mouse.operation = MOUSE_MODE;
6784 mouse.u.mode.mode = 0;
6785 mouse.u.mode.signal = 0;
6786 ioctl(1, CONS_MOUSECTL, &mouse);
6787}
6788
6789/*
6790 * Gets info from sysmouse and adds special keys to input buf.
6791 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006792 static RETSIGTYPE
6793sig_sysmouse SIGDEFARG(sigarg)
6794{
6795 struct mouse_info mouse;
6796 struct video_info video;
6797 char_u string[6];
6798 int row, col;
6799 int button;
6800 int buttons;
6801 static int oldbuttons = 0;
6802
6803#ifdef FEAT_GUI
6804 /* Don't put events in the input queue now. */
6805 if (hold_gui_events)
6806 return;
6807#endif
6808
6809 mouse.operation = MOUSE_GETINFO;
6810 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
6811 && ioctl(1, FBIO_MODEINFO, &video) != -1
6812 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
6813 && video.vi_cheight > 0 && video.vi_cwidth > 0)
6814 {
6815 row = mouse.u.data.y / video.vi_cheight;
6816 col = mouse.u.data.x / video.vi_cwidth;
6817 buttons = mouse.u.data.buttons;
6818 string[0] = ESC; /* Our termcode */
6819 string[1] = 'M';
6820 string[2] = 'S';
6821 if (oldbuttons == buttons && buttons != 0)
6822 {
6823 button = MOUSE_DRAG;
6824 }
6825 else
6826 {
6827 switch (buttons)
6828 {
6829 case 0:
6830 button = MOUSE_RELEASE;
6831 break;
6832 case 1:
6833 button = MOUSE_LEFT;
6834 break;
6835 case 2:
6836 button = MOUSE_MIDDLE;
6837 break;
6838 case 4:
6839 button = MOUSE_RIGHT;
6840 break;
6841 default:
6842 return;
6843 }
6844 oldbuttons = buttons;
6845 }
6846 string[3] = (char_u)(button);
6847 string[4] = (char_u)(col + ' ' + 1);
6848 string[5] = (char_u)(row + ' ' + 1);
6849 add_to_input_buf(string, 6);
6850 }
6851 return;
6852}
6853#endif /* FEAT_SYSMOUSE */
6854
Bram Moolenaar071d4272004-06-13 20:20:40 +00006855#if defined(FEAT_LIBCALL) || defined(PROTO)
Bram Moolenaard99df422016-01-29 23:20:40 +01006856typedef char_u * (*STRPROCSTR)(char_u *);
6857typedef char_u * (*INTPROCSTR)(int);
6858typedef int (*STRPROCINT)(char_u *);
6859typedef int (*INTPROCINT)(int);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006860
6861/*
6862 * Call a DLL routine which takes either a string or int param
6863 * and returns an allocated string.
6864 */
6865 int
Bram Moolenaar05540972016-01-30 20:31:25 +01006866mch_libcall(
6867 char_u *libname,
6868 char_u *funcname,
6869 char_u *argstring, /* NULL when using a argint */
6870 int argint,
6871 char_u **string_result,/* NULL when using number_result */
6872 int *number_result)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006873{
6874# if defined(USE_DLOPEN)
6875 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006876 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006877# else
6878 shl_t hinstLib;
6879# endif
6880 STRPROCSTR ProcAdd;
6881 INTPROCSTR ProcAddI;
6882 char_u *retval_str = NULL;
6883 int retval_int = 0;
6884 int success = FALSE;
6885
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006886 /*
6887 * Get a handle to the DLL module.
6888 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006889# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006890 /* First clear any error, it's not cleared by the dlopen() call. */
6891 (void)dlerror();
6892
Bram Moolenaar071d4272004-06-13 20:20:40 +00006893 hinstLib = dlopen((char *)libname, RTLD_LAZY
6894# ifdef RTLD_LOCAL
6895 | RTLD_LOCAL
6896# endif
6897 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006898 if (hinstLib == NULL)
6899 {
6900 /* "dlerr" must be used before dlclose() */
6901 dlerr = (char *)dlerror();
6902 if (dlerr != NULL)
6903 EMSG2(_("dlerror = \"%s\""), dlerr);
6904 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006905# else
6906 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
6907# endif
6908
6909 /* If the handle is valid, try to get the function address. */
6910 if (hinstLib != NULL)
6911 {
6912# ifdef HAVE_SETJMP_H
6913 /*
6914 * Catch a crash when calling the library function. For example when
6915 * using a number where a string pointer is expected.
6916 */
6917 mch_startjmp();
6918 if (SETJMP(lc_jump_env) != 0)
6919 {
6920 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006921# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006922 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006923# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006924 mch_didjmp();
6925 }
6926 else
6927# endif
6928 {
6929 retval_str = NULL;
6930 retval_int = 0;
6931
6932 if (argstring != NULL)
6933 {
6934# if defined(USE_DLOPEN)
6935 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006936 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006937# else
6938 if (shl_findsym(&hinstLib, (const char *)funcname,
6939 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
6940 ProcAdd = NULL;
6941# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006942 if ((success = (ProcAdd != NULL
6943# if defined(USE_DLOPEN)
6944 && dlerr == NULL
6945# endif
6946 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006947 {
6948 if (string_result == NULL)
6949 retval_int = ((STRPROCINT)ProcAdd)(argstring);
6950 else
6951 retval_str = (ProcAdd)(argstring);
6952 }
6953 }
6954 else
6955 {
6956# if defined(USE_DLOPEN)
6957 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006958 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006959# else
6960 if (shl_findsym(&hinstLib, (const char *)funcname,
6961 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
6962 ProcAddI = NULL;
6963# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006964 if ((success = (ProcAddI != NULL
6965# if defined(USE_DLOPEN)
6966 && dlerr == NULL
6967# endif
6968 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006969 {
6970 if (string_result == NULL)
6971 retval_int = ((INTPROCINT)ProcAddI)(argint);
6972 else
6973 retval_str = (ProcAddI)(argint);
6974 }
6975 }
6976
6977 /* Save the string before we free the library. */
6978 /* Assume that a "1" or "-1" result is an illegal pointer. */
6979 if (string_result == NULL)
6980 *number_result = retval_int;
6981 else if (retval_str != NULL
6982 && retval_str != (char_u *)1
6983 && retval_str != (char_u *)-1)
6984 *string_result = vim_strsave(retval_str);
6985 }
6986
6987# ifdef HAVE_SETJMP_H
6988 mch_endjmp();
6989# ifdef SIGHASARG
6990 if (lc_signal != 0)
6991 {
6992 int i;
6993
6994 /* try to find the name of this signal */
6995 for (i = 0; signal_info[i].sig != -1; i++)
6996 if (lc_signal == signal_info[i].sig)
6997 break;
6998 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6999 }
7000# endif
7001# endif
7002
Bram Moolenaar071d4272004-06-13 20:20:40 +00007003# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00007004 /* "dlerr" must be used before dlclose() */
7005 if (dlerr != NULL)
7006 EMSG2(_("dlerror = \"%s\""), dlerr);
7007
7008 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007009 (void)dlclose(hinstLib);
7010# else
7011 (void)shl_unload(hinstLib);
7012# endif
7013 }
7014
7015 if (!success)
7016 {
7017 EMSG2(_(e_libcall), funcname);
7018 return FAIL;
7019 }
7020
7021 return OK;
7022}
7023#endif
7024
7025#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
7026static int xterm_trace = -1; /* default: disabled */
7027static int xterm_button;
7028
7029/*
7030 * Setup a dummy window for X selections in a terminal.
7031 */
7032 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007033setup_term_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007034{
7035 int z = 0;
7036 char *strp = "";
7037 Widget AppShell;
7038
7039 if (!x_connect_to_server())
7040 return;
7041
7042 open_app_context();
7043 if (app_context != NULL && xterm_Shell == (Widget)0)
7044 {
7045 int (*oldhandler)();
7046#if defined(HAVE_SETJMP_H)
7047 int (*oldIOhandler)();
7048#endif
7049# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
7050 struct timeval start_tv;
7051
7052 if (p_verbose > 0)
7053 gettimeofday(&start_tv, NULL);
7054# endif
7055
7056 /* Ignore X errors while opening the display */
7057 oldhandler = XSetErrorHandler(x_error_check);
7058
7059#if defined(HAVE_SETJMP_H)
7060 /* Ignore X IO errors while opening the display */
7061 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
7062 mch_startjmp();
7063 if (SETJMP(lc_jump_env) != 0)
7064 {
7065 mch_didjmp();
7066 xterm_dpy = NULL;
7067 }
7068 else
7069#endif
7070 {
7071 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
7072 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
7073#if defined(HAVE_SETJMP_H)
7074 mch_endjmp();
7075#endif
7076 }
7077
7078#if defined(HAVE_SETJMP_H)
7079 /* Now handle X IO errors normally. */
7080 (void)XSetIOErrorHandler(oldIOhandler);
7081#endif
7082 /* Now handle X errors normally. */
7083 (void)XSetErrorHandler(oldhandler);
7084
7085 if (xterm_dpy == NULL)
7086 {
7087 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007088 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007089 return;
7090 }
7091
7092 /* Catch terminating error of the X server connection. */
7093 (void)XSetIOErrorHandler(x_IOerror_handler);
7094
7095# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
7096 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007097 {
7098 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00007099 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007100 verbose_leave();
7101 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007102# endif
7103
7104 /* Create a Shell to make converters work. */
7105 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
7106 applicationShellWidgetClass, xterm_dpy,
7107 NULL);
7108 if (AppShell == (Widget)0)
7109 return;
7110 xterm_Shell = XtVaCreatePopupShell("VIM",
7111 topLevelShellWidgetClass, AppShell,
7112 XtNmappedWhenManaged, 0,
7113 XtNwidth, 1,
7114 XtNheight, 1,
7115 NULL);
7116 if (xterm_Shell == (Widget)0)
7117 return;
7118
7119 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02007120 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007121 if (x11_display == NULL)
7122 x11_display = xterm_dpy;
7123
7124 XtRealizeWidget(xterm_Shell);
7125 XSync(xterm_dpy, False);
7126 xterm_update();
7127 }
7128 if (xterm_Shell != (Widget)0)
7129 {
7130 clip_init(TRUE);
7131 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
7132 x11_window = (Window)atol(strp);
7133 /* Check if $WINDOWID is valid. */
7134 if (test_x11_window(xterm_dpy) == FAIL)
7135 x11_window = 0;
7136 if (x11_window != 0)
7137 xterm_trace = 0;
7138 }
7139}
7140
7141 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007142start_xterm_trace(int button)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007143{
7144 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
7145 return;
7146 xterm_trace = 1;
7147 xterm_button = button;
7148 do_xterm_trace();
7149}
7150
7151
7152 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007153stop_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007154{
7155 if (xterm_trace < 0)
7156 return;
7157 xterm_trace = 0;
7158}
7159
7160/*
7161 * Query the xterm pointer and generate mouse termcodes if necessary
7162 * return TRUE if dragging is active, else FALSE
7163 */
7164 static int
Bram Moolenaar05540972016-01-30 20:31:25 +01007165do_xterm_trace(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007166{
7167 Window root, child;
7168 int root_x, root_y;
7169 int win_x, win_y;
7170 int row, col;
7171 int_u mask_return;
7172 char_u buf[50];
7173 char_u *strp;
7174 long got_hints;
7175 static char_u *mouse_code;
7176 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
7177 static int prev_row = 0, prev_col = 0;
7178 static XSizeHints xterm_hints;
7179
7180 if (xterm_trace <= 0)
7181 return FALSE;
7182
7183 if (xterm_trace == 1)
7184 {
7185 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00007186 * have changed recently. */
7187 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
7188 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007189 || xterm_hints.width_inc <= 1
7190 || xterm_hints.height_inc <= 1)
7191 {
7192 xterm_trace = -1; /* Not enough data -- disable tracing */
7193 return FALSE;
7194 }
7195
7196 /* Rely on the same mouse code for the duration of this */
7197 mouse_code = find_termcode(mouse_name);
7198 prev_row = mouse_row;
Bram Moolenaarcde88542015-08-11 19:14:00 +02007199 prev_col = mouse_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007200 xterm_trace = 2;
7201
7202 /* Find the offset of the chars, there might be a scrollbar on the
7203 * left of the window and/or a menu on the top (eterm etc.) */
7204 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7205 &win_x, &win_y, &mask_return);
7206 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
7207 - (xterm_hints.height_inc / 2);
7208 if (xterm_hints.y <= xterm_hints.height_inc / 2)
7209 xterm_hints.y = 2;
7210 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
7211 - (xterm_hints.width_inc / 2);
7212 if (xterm_hints.x <= xterm_hints.width_inc / 2)
7213 xterm_hints.x = 2;
7214 return TRUE;
7215 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02007216 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007217 {
7218 xterm_trace = 0;
7219 return FALSE;
7220 }
7221
7222 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7223 &win_x, &win_y, &mask_return);
7224
7225 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
7226 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
7227 if (row == prev_row && col == prev_col)
7228 return TRUE;
7229
7230 STRCPY(buf, mouse_code);
7231 strp = buf + STRLEN(buf);
7232 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
7233 *strp++ = (char_u)(col + ' ' + 1);
7234 *strp++ = (char_u)(row + ' ' + 1);
7235 *strp = 0;
7236 add_to_input_buf(buf, STRLEN(buf));
7237
7238 prev_row = row;
7239 prev_col = col;
7240 return TRUE;
7241}
7242
7243# if defined(FEAT_GUI) || defined(PROTO)
7244/*
7245 * Destroy the display, window and app_context. Required for GTK.
7246 */
7247 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007248clear_xterm_clip(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007249{
7250 if (xterm_Shell != (Widget)0)
7251 {
7252 XtDestroyWidget(xterm_Shell);
7253 xterm_Shell = (Widget)0;
7254 }
7255 if (xterm_dpy != NULL)
7256 {
Bram Moolenaare8208012008-06-20 09:59:25 +00007257# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007258 /* Lesstif and Solaris crash here, lose some memory */
7259 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00007260# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007261 if (x11_display == xterm_dpy)
7262 x11_display = NULL;
7263 xterm_dpy = NULL;
7264 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007265# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007266 if (app_context != (XtAppContext)NULL)
7267 {
7268 /* Lesstif and Solaris crash here, lose some memory */
7269 XtDestroyApplicationContext(app_context);
7270 app_context = (XtAppContext)NULL;
7271 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007272# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007273}
7274# endif
7275
7276/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007277 * Catch up with GUI or X events.
7278 */
7279 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007280clip_update(void)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007281{
7282# ifdef FEAT_GUI
7283 if (gui.in_use)
7284 gui_mch_update();
7285 else
7286# endif
7287 if (xterm_Shell != (Widget)0)
7288 xterm_update();
7289}
7290
7291/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007292 * Catch up with any queued X events. This may put keyboard input into the
7293 * input buffer, call resize call-backs, trigger timers etc. If there is
7294 * nothing in the X event queue (& no timers pending), then we return
7295 * immediately.
7296 */
7297 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007298xterm_update(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007299{
7300 XEvent event;
7301
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007302 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007303 {
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007304 XtInputMask mask = XtAppPending(app_context);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007305
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007306 if (mask == 0 || vim_is_input_buf_full())
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007307 break;
7308
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007309 if (mask & XtIMXEvent)
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007310 {
7311 /* There is an event to process. */
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007312 XtAppNextEvent(app_context, &event);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007313#ifdef FEAT_CLIENTSERVER
7314 {
7315 XPropertyEvent *e = (XPropertyEvent *)&event;
7316
7317 if (e->type == PropertyNotify && e->window == commWindow
Bram Moolenaar071d4272004-06-13 20:20:40 +00007318 && e->atom == commProperty && e->state == PropertyNewValue)
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007319 serverEventProc(xterm_dpy, &event, 0);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007320 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007321#endif
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007322 XtDispatchEvent(&event);
7323 }
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007324 else
7325 {
7326 /* There is something else than an event to process. */
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007327 XtAppProcessEvent(app_context, mask);
7328 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007329 }
7330}
7331
7332 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007333clip_xterm_own_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007334{
7335 if (xterm_Shell != (Widget)0)
7336 return clip_x11_own_selection(xterm_Shell, cbd);
7337 return FAIL;
7338}
7339
7340 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007341clip_xterm_lose_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007342{
7343 if (xterm_Shell != (Widget)0)
7344 clip_x11_lose_selection(xterm_Shell, cbd);
7345}
7346
7347 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007348clip_xterm_request_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007349{
7350 if (xterm_Shell != (Widget)0)
7351 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7352}
7353
7354 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007355clip_xterm_set_selection(VimClipboard *cbd)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007356{
7357 clip_x11_set_selection(cbd);
7358}
7359#endif
7360
7361
7362#if defined(USE_XSMP) || defined(PROTO)
7363/*
7364 * Code for X Session Management Protocol.
7365 */
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01007366static void xsmp_handle_save_yourself(SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast);
7367static void xsmp_die(SmcConn smc_conn, SmPointer client_data);
7368static void xsmp_save_complete(SmcConn smc_conn, SmPointer client_data);
7369static void xsmp_shutdown_cancelled(SmcConn smc_conn, SmPointer client_data);
7370static void xsmp_ice_connection(IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007371
7372
7373# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +01007374static void xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007375
7376/*
7377 * This is our chance to ask the user if they want to save,
7378 * or abort the logout
7379 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007380 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007381xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007382{
7383 cmdmod_T save_cmdmod;
7384 int cancel_shutdown = False;
7385
7386 save_cmdmod = cmdmod;
7387 cmdmod.confirm = TRUE;
Bram Moolenaar027387f2016-01-02 22:25:52 +01007388 if (check_changed_any(FALSE, FALSE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00007389 /* Mustn't logout */
7390 cancel_shutdown = True;
7391 cmdmod = save_cmdmod;
7392 setcursor(); /* position cursor */
7393 out_flush();
7394
7395 /* Done interaction */
7396 SmcInteractDone(smc_conn, cancel_shutdown);
7397
7398 /* Finish off
7399 * Only end save-yourself here if we're not cancelling shutdown;
7400 * we'll get a cancelled callback later in which we'll end it.
7401 * Hopefully get around glitchy SMs (like GNOME-1)
7402 */
7403 if (!cancel_shutdown)
7404 {
7405 xsmp.save_yourself = False;
7406 SmcSaveYourselfDone(smc_conn, True);
7407 }
7408}
7409# endif
7410
7411/*
7412 * Callback that starts save-yourself.
7413 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007414 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007415xsmp_handle_save_yourself(
7416 SmcConn smc_conn,
7417 SmPointer client_data UNUSED,
7418 int save_type UNUSED,
7419 Bool shutdown,
7420 int interact_style UNUSED,
7421 Bool fast UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007422{
7423 /* Handle already being in saveyourself */
7424 if (xsmp.save_yourself)
7425 SmcSaveYourselfDone(smc_conn, True);
7426 xsmp.save_yourself = True;
7427 xsmp.shutdown = shutdown;
7428
7429 /* First up, preserve all files */
7430 out_flush();
7431 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
7432
7433 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007434 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007435
7436# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7437 /* Now see if we can ask about unsaved files */
7438 if (shutdown && !fast && gui.in_use)
7439 /* Need to interact with user, but need SM's permission */
7440 SmcInteractRequest(smc_conn, SmDialogError,
7441 xsmp_handle_interaction, client_data);
7442 else
7443# endif
7444 {
7445 /* Can stop the cycle here */
7446 SmcSaveYourselfDone(smc_conn, True);
7447 xsmp.save_yourself = False;
7448 }
7449}
7450
7451
7452/*
7453 * Callback to warn us of imminent death.
7454 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007455 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007456xsmp_die(SmcConn smc_conn UNUSED, SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007457{
7458 xsmp_close();
7459
7460 /* quit quickly leaving swapfiles for modified buffers behind */
7461 getout_preserve_modified(0);
7462}
7463
7464
7465/*
7466 * Callback to tell us that save-yourself has completed.
7467 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007468 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007469xsmp_save_complete(
7470 SmcConn smc_conn UNUSED,
7471 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007472{
7473 xsmp.save_yourself = False;
7474}
7475
7476
7477/*
7478 * Callback to tell us that an instigated shutdown was cancelled
7479 * (maybe even by us)
7480 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007481 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007482xsmp_shutdown_cancelled(
7483 SmcConn smc_conn,
7484 SmPointer client_data UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007485{
7486 if (xsmp.save_yourself)
7487 SmcSaveYourselfDone(smc_conn, True);
7488 xsmp.save_yourself = False;
7489 xsmp.shutdown = False;
7490}
7491
7492
7493/*
7494 * Callback to tell us that a new ICE connection has been established.
7495 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007496 static void
Bram Moolenaar05540972016-01-30 20:31:25 +01007497xsmp_ice_connection(
7498 IceConn iceConn,
7499 IcePointer clientData UNUSED,
7500 Bool opening,
7501 IcePointer *watchData UNUSED)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007502{
7503 /* Intercept creation of ICE connection fd */
7504 if (opening)
7505 {
7506 xsmp_icefd = IceConnectionNumber(iceConn);
7507 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7508 }
7509}
7510
7511
7512/* Handle any ICE processing that's required; return FAIL if SM lost */
7513 int
Bram Moolenaar05540972016-01-30 20:31:25 +01007514xsmp_handle_requests(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007515{
7516 Bool rep;
7517
7518 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7519 == IceProcessMessagesIOError)
7520 {
7521 /* Lost ICE */
7522 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007523 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007524 xsmp_close();
7525 return FAIL;
7526 }
7527 else
7528 return OK;
7529}
7530
7531static int dummy;
7532
7533/* Set up X Session Management Protocol */
7534 void
7535xsmp_init(void)
7536{
7537 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007538 SmcCallbacks smcallbacks;
7539#if 0
7540 SmPropValue smname;
7541 SmProp smnameprop;
7542 SmProp *smprops[1];
7543#endif
7544
7545 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007546 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007547
7548 xsmp.save_yourself = xsmp.shutdown = False;
7549
7550 /* Set up SM callbacks - must have all, even if they're not used */
7551 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
7552 smcallbacks.save_yourself.client_data = NULL;
7553 smcallbacks.die.callback = xsmp_die;
7554 smcallbacks.die.client_data = NULL;
7555 smcallbacks.save_complete.callback = xsmp_save_complete;
7556 smcallbacks.save_complete.client_data = NULL;
7557 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
7558 smcallbacks.shutdown_cancelled.client_data = NULL;
7559
7560 /* Set up a watch on ICE connection creations. The "dummy" argument is
7561 * apparently required for FreeBSD (we get a BUS error when using NULL). */
7562 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
7563 {
7564 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007565 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007566 return;
7567 }
7568
7569 /* Create an SM connection */
7570 xsmp.smcconn = SmcOpenConnection(
7571 NULL,
7572 NULL,
7573 SmProtoMajor,
7574 SmProtoMinor,
7575 SmcSaveYourselfProcMask | SmcDieProcMask
7576 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
7577 &smcallbacks,
7578 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00007579 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007580 sizeof(errorstring),
7581 errorstring);
7582 if (xsmp.smcconn == NULL)
7583 {
7584 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00007585
Bram Moolenaar071d4272004-06-13 20:20:40 +00007586 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007587 {
7588 vim_snprintf(errorreport, sizeof(errorreport),
7589 _("XSMP SmcOpenConnection failed: %s"), errorstring);
7590 verb_msg((char_u *)errorreport);
7591 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007592 return;
7593 }
7594 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
7595
7596#if 0
7597 /* ID ourselves */
7598 smname.value = "vim";
7599 smname.length = 3;
7600 smnameprop.name = "SmProgram";
7601 smnameprop.type = "SmARRAY8";
7602 smnameprop.num_vals = 1;
7603 smnameprop.vals = &smname;
7604
7605 smprops[0] = &smnameprop;
7606 SmcSetProperties(xsmp.smcconn, 1, smprops);
7607#endif
7608}
7609
7610
7611/* Shut down XSMP comms. */
7612 void
Bram Moolenaar05540972016-01-30 20:31:25 +01007613xsmp_close(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007614{
7615 if (xsmp_icefd != -1)
7616 {
7617 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00007618 if (xsmp.clientid != NULL)
7619 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00007620 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007621 xsmp_icefd = -1;
7622 }
7623}
7624#endif /* USE_XSMP */
7625
7626
7627#ifdef EBCDIC
7628/* Translate character to its CTRL- value */
7629char CtrlTable[] =
7630{
7631/* 00 - 5E */
7632 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7633 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7634 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7635 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7636 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7637 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7638/* ^ */ 0x1E,
7639/* - */ 0x1F,
7640/* 61 - 6C */
7641 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7642/* _ */ 0x1F,
7643/* 6E - 80 */
7644 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7645/* a */ 0x01,
7646/* b */ 0x02,
7647/* c */ 0x03,
7648/* d */ 0x37,
7649/* e */ 0x2D,
7650/* f */ 0x2E,
7651/* g */ 0x2F,
7652/* h */ 0x16,
7653/* i */ 0x05,
7654/* 8A - 90 */
7655 0, 0, 0, 0, 0, 0, 0,
7656/* j */ 0x15,
7657/* k */ 0x0B,
7658/* l */ 0x0C,
7659/* m */ 0x0D,
7660/* n */ 0x0E,
7661/* o */ 0x0F,
7662/* p */ 0x10,
7663/* q */ 0x11,
7664/* r */ 0x12,
7665/* 9A - A1 */
7666 0, 0, 0, 0, 0, 0, 0, 0,
7667/* s */ 0x13,
7668/* t */ 0x3C,
7669/* u */ 0x3D,
7670/* v */ 0x32,
7671/* w */ 0x26,
7672/* x */ 0x18,
7673/* y */ 0x19,
7674/* z */ 0x3F,
7675/* AA - AC */
7676 0, 0, 0,
7677/* [ */ 0x27,
7678/* AE - BC */
7679 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7680/* ] */ 0x1D,
7681/* BE - C0 */ 0, 0, 0,
7682/* A */ 0x01,
7683/* B */ 0x02,
7684/* C */ 0x03,
7685/* D */ 0x37,
7686/* E */ 0x2D,
7687/* F */ 0x2E,
7688/* G */ 0x2F,
7689/* H */ 0x16,
7690/* I */ 0x05,
7691/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
7692/* J */ 0x15,
7693/* K */ 0x0B,
7694/* L */ 0x0C,
7695/* M */ 0x0D,
7696/* N */ 0x0E,
7697/* O */ 0x0F,
7698/* P */ 0x10,
7699/* Q */ 0x11,
7700/* R */ 0x12,
7701/* DA - DF */ 0, 0, 0, 0, 0, 0,
7702/* \ */ 0x1C,
7703/* E1 */ 0,
7704/* S */ 0x13,
7705/* T */ 0x3C,
7706/* U */ 0x3D,
7707/* V */ 0x32,
7708/* W */ 0x26,
7709/* X */ 0x18,
7710/* Y */ 0x19,
7711/* Z */ 0x3F,
7712/* EA - FF*/ 0, 0, 0, 0, 0, 0,
7713 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7714};
7715
7716char MetaCharTable[]=
7717{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7718 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
7719 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
7720 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
7721 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
7722};
7723
7724
7725/* TODO: Use characters NOT numbers!!! */
7726char CtrlCharTable[]=
7727{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7728 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
7729 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
7730 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
7731 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
7732};
7733
7734
7735#endif