blob: 63d39493bac75be5964c92ee154d995dac983c50 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
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 Moolenaar071d4272004-06-13 20:20:40 +000049/*
50 * Use this prototype for select, some include files have a wrong prototype
51 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000052#ifndef __TANDEM
53# undef select
54# ifdef __BEOS__
55# define select beos_select
56# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000057#endif
58
Bram Moolenaara2442432007-04-26 14:26:37 +000059#ifdef __CYGWIN__
60# ifndef WIN32
Bram Moolenaar0d1498e2008-06-29 12:00:49 +000061# include <cygwin/version.h>
62# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() and/or
63 * for cygwin_conv_path() */
Bram Moolenaar693e40c2013-02-26 14:56:42 +010064# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
65# define WIN32_LEAN_AND_MEAN
66# include <windows.h>
67# include "winclip.pro"
68# endif
Bram Moolenaara2442432007-04-26 14:26:37 +000069# endif
70#endif
71
Bram Moolenaar071d4272004-06-13 20:20:40 +000072#if defined(HAVE_SELECT)
73extern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
74#endif
75
76#ifdef FEAT_MOUSE_GPM
77# include <gpm.h>
78/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
79 * I just copied relevant defines here. A cleaner solution would be to put gpm
80 * code into separate file and include there linux/keyboard.h
81 */
82/* #include <linux/keyboard.h> */
83# define KG_SHIFT 0
84# define KG_CTRL 2
85# define KG_ALT 3
86# define KG_ALTGR 1
87# define KG_SHIFTL 4
88# define KG_SHIFTR 5
89# define KG_CTRLL 6
90# define KG_CTRLR 7
91# define KG_CAPSSHIFT 8
92
93static void gpm_close __ARGS((void));
94static int gpm_open __ARGS((void));
95static int mch_gpm_process __ARGS((void));
96#endif
97
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000098#ifdef FEAT_SYSMOUSE
99# include <sys/consio.h>
100# include <sys/fbio.h>
101
102static int sysmouse_open __ARGS((void));
103static void sysmouse_close __ARGS((void));
104static RETSIGTYPE sig_sysmouse __ARGS(SIGPROTOARG);
105#endif
106
Bram Moolenaar071d4272004-06-13 20:20:40 +0000107/*
108 * end of autoconf section. To be extended...
109 */
110
111/* Are the following #ifdefs still required? And why? Is that for X11? */
112
113#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
114# ifdef SIGWINCH
115# undef SIGWINCH
116# endif
117# ifdef TIOCGWINSZ
118# undef TIOCGWINSZ
119# endif
120#endif
121
122#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
123# define SIGWINCH SIGWINDOW
124#endif
125
126#ifdef FEAT_X11
127# include <X11/Xlib.h>
128# include <X11/Xutil.h>
129# include <X11/Xatom.h>
130# ifdef FEAT_XCLIPBOARD
131# include <X11/Intrinsic.h>
132# include <X11/Shell.h>
133# include <X11/StringDefs.h>
134static Widget xterm_Shell = (Widget)0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +0100135static void clip_update __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000136static void xterm_update __ARGS((void));
137# endif
138
139# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
140Window x11_window = 0;
141# endif
142Display *x11_display = NULL;
143
144# ifdef FEAT_TITLE
145static int get_x11_windis __ARGS((void));
146static void set_x11_title __ARGS((char_u *));
147static void set_x11_icon __ARGS((char_u *));
148# endif
149#endif
150
151#ifdef FEAT_TITLE
152static int get_x11_title __ARGS((int));
153static int get_x11_icon __ARGS((int));
154
155static char_u *oldtitle = NULL;
156static int did_set_title = FALSE;
157static char_u *oldicon = NULL;
158static int did_set_icon = FALSE;
159#endif
160
161static void may_core_dump __ARGS((void));
162
Bram Moolenaar205b8862011-09-07 15:04:31 +0200163#ifdef HAVE_UNION_WAIT
164typedef union wait waitstatus;
165#else
166typedef int waitstatus;
167#endif
Bram Moolenaar9f118812011-09-08 23:24:14 +0200168static pid_t wait4pid __ARGS((pid_t, waitstatus *));
Bram Moolenaar205b8862011-09-07 15:04:31 +0200169
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170static int WaitForChar __ARGS((long));
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100171#if defined(__BEOS__) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172int RealWaitForChar __ARGS((int, long, int *));
173#else
174static int RealWaitForChar __ARGS((int, long, int *));
175#endif
176
177#ifdef FEAT_XCLIPBOARD
178static int do_xterm_trace __ARGS((void));
Bram Moolenaarcf851ce2005-06-16 21:52:47 +0000179# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180#endif
181
182static void handle_resize __ARGS((void));
183
184#if defined(SIGWINCH)
185static RETSIGTYPE sig_winch __ARGS(SIGPROTOARG);
186#endif
187#if defined(SIGINT)
188static RETSIGTYPE catch_sigint __ARGS(SIGPROTOARG);
189#endif
190#if defined(SIGPWR)
191static RETSIGTYPE catch_sigpwr __ARGS(SIGPROTOARG);
192#endif
193#if defined(SIGALRM) && defined(FEAT_X11) \
194 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
195# define SET_SIG_ALARM
196static RETSIGTYPE sig_alarm __ARGS(SIGPROTOARG);
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000197/* volatile because it is used in signal handler sig_alarm(). */
198static volatile int sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199#endif
200static RETSIGTYPE deathtrap __ARGS(SIGPROTOARG);
201
Bram Moolenaardf177f62005-02-22 08:39:57 +0000202static void catch_int_signal __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000203static void set_signals __ARGS((void));
204static void catch_signals __ARGS((RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)()));
205#ifndef __EMX__
206static int have_wildcard __ARGS((int, char_u **));
207static int have_dollars __ARGS((int, char_u **));
208#endif
209
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210#ifndef __EMX__
211static int save_patterns __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file));
212#endif
213
214#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000215# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000216#endif
217
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000218/* volatile because it is used in signal handler sig_winch(). */
219static volatile int do_resize = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220#ifndef __EMX__
221static char_u *extra_shell_arg = NULL;
222static int show_shell_mess = TRUE;
223#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000224/* volatile because it is used in signal handler deathtrap(). */
225static volatile int deadly_signal = 0; /* The signal we caught */
226/* volatile because it is used in signal handler deathtrap(). */
227static volatile int in_mch_delay = FALSE; /* sleeping in mch_delay() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228
229static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
230
231#ifdef USE_XSMP
232typedef struct
233{
234 SmcConn smcconn; /* The SM connection ID */
235 IceConn iceconn; /* The ICE connection ID */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200236 char *clientid; /* The client ID for the current smc session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000237 Bool save_yourself; /* If we're in the middle of a save_yourself */
238 Bool shutdown; /* If we're in shutdown mode */
239} xsmp_config_T;
240
241static xsmp_config_T xsmp;
242#endif
243
244#ifdef SYS_SIGLIST_DECLARED
245/*
246 * I have seen
247 * extern char *_sys_siglist[NSIG];
248 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
249 * that describe the signals. That is nearly what we want here. But
250 * autoconf does only check for sys_siglist (without the underscore), I
251 * do not want to change everything today.... jw.
252 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.in
253 */
254#endif
255
256static struct signalinfo
257{
258 int sig; /* Signal number, eg. SIGSEGV etc */
259 char *name; /* Signal name (not char_u!). */
260 char deadly; /* Catch as a deadly signal? */
261} signal_info[] =
262{
263#ifdef SIGHUP
264 {SIGHUP, "HUP", TRUE},
265#endif
266#ifdef SIGQUIT
267 {SIGQUIT, "QUIT", TRUE},
268#endif
269#ifdef SIGILL
270 {SIGILL, "ILL", TRUE},
271#endif
272#ifdef SIGTRAP
273 {SIGTRAP, "TRAP", TRUE},
274#endif
275#ifdef SIGABRT
276 {SIGABRT, "ABRT", TRUE},
277#endif
278#ifdef SIGEMT
279 {SIGEMT, "EMT", TRUE},
280#endif
281#ifdef SIGFPE
282 {SIGFPE, "FPE", TRUE},
283#endif
284#ifdef SIGBUS
285 {SIGBUS, "BUS", TRUE},
286#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100287#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
288 /* MzScheme uses SEGV in its garbage collector */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000289 {SIGSEGV, "SEGV", TRUE},
290#endif
291#ifdef SIGSYS
292 {SIGSYS, "SYS", TRUE},
293#endif
294#ifdef SIGALRM
295 {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
296#endif
297#ifdef SIGTERM
298 {SIGTERM, "TERM", TRUE},
299#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100300#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301 {SIGVTALRM, "VTALRM", TRUE},
302#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000303#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
304 /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
305 * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306 {SIGPROF, "PROF", TRUE},
307#endif
308#ifdef SIGXCPU
309 {SIGXCPU, "XCPU", TRUE},
310#endif
311#ifdef SIGXFSZ
312 {SIGXFSZ, "XFSZ", TRUE},
313#endif
314#ifdef SIGUSR1
315 {SIGUSR1, "USR1", TRUE},
316#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000317#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
318 /* Used for sysmouse handling */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000319 {SIGUSR2, "USR2", TRUE},
320#endif
321#ifdef SIGINT
322 {SIGINT, "INT", FALSE},
323#endif
324#ifdef SIGWINCH
325 {SIGWINCH, "WINCH", FALSE},
326#endif
327#ifdef SIGTSTP
328 {SIGTSTP, "TSTP", FALSE},
329#endif
330#ifdef SIGPIPE
331 {SIGPIPE, "PIPE", FALSE},
332#endif
333 {-1, "Unknown!", FALSE}
334};
335
Bram Moolenaar25724922009-07-14 15:38:41 +0000336 int
337mch_chdir(path)
338 char *path;
339{
340 if (p_verbose >= 5)
341 {
342 verbose_enter();
343 smsg((char_u *)"chdir(%s)", path);
344 verbose_leave();
345 }
346# ifdef VMS
347 return chdir(vms_fixfilename(path));
348# else
349 return chdir(path);
350# endif
351}
352
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000353/*
354 * Write s[len] to the screen.
355 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356 void
357mch_write(s, len)
358 char_u *s;
359 int len;
360{
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000361 ignored = (int)write(1, (char *)s, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000362 if (p_wd) /* Unix is too fast, slow down a bit more */
363 RealWaitForChar(read_cmd_fd, p_wd, NULL);
364}
365
366/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000367 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368 * Get a characters from the keyboard.
369 * Return the number of characters that are available.
370 * If wtime == 0 do not wait for characters.
371 * If wtime == n wait a short time for characters.
372 * If wtime == -1 wait forever for characters.
373 */
374 int
375mch_inchar(buf, maxlen, wtime, tb_change_cnt)
376 char_u *buf;
377 int maxlen;
378 long wtime; /* don't use "time", MIPS cannot handle it */
379 int tb_change_cnt;
380{
381 int len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000382
Bram Moolenaar67c53842010-05-22 18:28:27 +0200383#ifdef FEAT_NETBEANS_INTG
384 /* Process the queued netbeans messages. */
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200385 netbeans_parse_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200386#endif
387
Bram Moolenaar071d4272004-06-13 20:20:40 +0000388 /* Check if window changed size while we were busy, perhaps the ":set
389 * columns=99" command was used. */
390 while (do_resize)
391 handle_resize();
392
393 if (wtime >= 0)
394 {
395 while (WaitForChar(wtime) == 0) /* no character available */
396 {
397 if (!do_resize) /* return if not interrupted by resize */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000398 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000399 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200400#ifdef FEAT_NETBEANS_INTG
401 /* Process the queued netbeans messages. */
Bram Moolenaarcc448b32010-07-14 16:52:17 +0200402 netbeans_parse_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200403#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000404 }
405 }
406 else /* wtime == -1 */
407 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408 /*
409 * If there is no character available within 'updatetime' seconds
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000410 * flush all the swap files to disk.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000411 * Also done when interrupted by SIGWINCH.
412 */
413 if (WaitForChar(p_ut) == 0)
414 {
415#ifdef FEAT_AUTOCMD
Bram Moolenaard35f9712005-12-18 22:02:33 +0000416 if (trigger_cursorhold() && maxlen >= 3
417 && !typebuf_changed(tb_change_cnt))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418 {
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000419 buf[0] = K_SPECIAL;
420 buf[1] = KS_EXTRA;
421 buf[2] = (int)KE_CURSORHOLD;
422 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424#endif
Bram Moolenaard4098f52005-06-27 22:37:13 +0000425 before_blocking();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000426 }
427 }
428
429 for (;;) /* repeat until we got a character */
430 {
431 while (do_resize) /* window changed size */
432 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200433
434#ifdef FEAT_NETBEANS_INTG
435 /* Process the queued netbeans messages. */
Bram Moolenaarcc448b32010-07-14 16:52:17 +0200436 netbeans_parse_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200437#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000438 /*
Bram Moolenaar48bae372010-07-29 23:12:15 +0200439 * We want to be interrupted by the winch signal
440 * or by an event on the monitored file descriptors.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200442 if (WaitForChar(-1L) == 0)
443 {
444 if (do_resize) /* interrupted by SIGWINCH signal */
445 handle_resize();
446 return 0;
447 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000448
449 /* If input was put directly in typeahead buffer bail out here. */
450 if (typebuf_changed(tb_change_cnt))
451 return 0;
452
453 /*
454 * For some terminals we only get one character at a time.
455 * We want the get all available characters, so we could keep on
456 * trying until none is available
457 * For some other terminals this is quite slow, that's why we don't do
458 * it.
459 */
460 len = read_from_input_buf(buf, (long)maxlen);
461 if (len > 0)
462 {
463#ifdef OS2
464 int i;
465
466 for (i = 0; i < len; i++)
467 if (buf[i] == 0)
468 buf[i] = K_NUL;
469#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470 return len;
471 }
472 }
473}
474
475 static void
476handle_resize()
477{
478 do_resize = FALSE;
479 shell_resized();
480}
481
482/*
483 * return non-zero if a character is available
484 */
485 int
486mch_char_avail()
487{
488 return WaitForChar(0L);
489}
490
491#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
492# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000493# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000494# endif
495# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
496# include <sys/sysctl.h>
497# endif
498# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
499# include <sys/sysinfo.h>
500# endif
501
502/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000503 * Return total amount of memory available in Kbyte.
504 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000505 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 long_u
507mch_total_mem(special)
Bram Moolenaar78a15312009-05-15 19:33:18 +0000508 int special UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000509{
510# ifdef __EMX__
Bram Moolenaar914572a2007-05-01 11:37:47 +0000511 return ulimit(3, 0L) >> 10; /* always 32MB? */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000512# else
513 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000514 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000515
516# ifdef HAVE_SYSCTL
517 int mib[2], physmem;
518 size_t len;
519
520 /* BSD way of getting the amount of RAM available. */
521 mib[0] = CTL_HW;
522 mib[1] = HW_USERMEM;
523 len = sizeof(physmem);
524 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
525 mem = (long_u)physmem;
526# endif
527
528# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
529 if (mem == 0)
530 {
531 struct sysinfo sinfo;
532
533 /* Linux way of getting amount of RAM available */
534 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000535 {
536# ifdef HAVE_SYSINFO_MEM_UNIT
537 /* avoid overflow as much as possible */
538 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
539 {
540 sinfo.mem_unit = sinfo.mem_unit >> 1;
541 --shiftright;
542 }
543 mem = sinfo.totalram * sinfo.mem_unit;
544# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545 mem = sinfo.totalram;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000546# endif
547 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548 }
549# endif
550
551# ifdef HAVE_SYSCONF
552 if (mem == 0)
553 {
554 long pagesize, pagecount;
555
556 /* Solaris way of getting amount of RAM available */
557 pagesize = sysconf(_SC_PAGESIZE);
558 pagecount = sysconf(_SC_PHYS_PAGES);
559 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000560 {
561 /* avoid overflow as much as possible */
562 while (shiftright > 0 && (pagesize & 1) == 0)
563 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000564 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000565 --shiftright;
566 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000567 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000568 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000569 }
570# endif
571
572 /* Return the minimum of the physical memory and the user limit, because
573 * using more than the user limit may cause Vim to be terminated. */
574# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
575 {
576 struct rlimit rlp;
577
578 if (getrlimit(RLIMIT_DATA, &rlp) == 0
579 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
580# ifdef RLIM_INFINITY
581 && rlp.rlim_cur != RLIM_INFINITY
582# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000583 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000585 {
586 mem = (long_u)rlp.rlim_cur;
587 shiftright = 10;
588 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000589 }
590# endif
591
592 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000593 return mem >> shiftright;
594 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000595# endif
596}
597#endif
598
599 void
600mch_delay(msec, ignoreinput)
601 long msec;
602 int ignoreinput;
603{
604 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000605#ifdef FEAT_MZSCHEME
606 long total = msec; /* remember original value */
607#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000608
609 if (ignoreinput)
610 {
611 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000612 * here. But we don't want QUIT to kill us (CTRL-\ used in a
613 * shell may produce SIGQUIT). */
614 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 old_tmode = curr_tmode;
616 if (curr_tmode == TMODE_RAW)
617 settmode(TMODE_SLEEP);
618
619 /*
620 * Everybody sleeps in a different way...
621 * Prefer nanosleep(), some versions of usleep() can only sleep up to
622 * one second.
623 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000624#ifdef FEAT_MZSCHEME
625 do
626 {
627 /* if total is large enough, wait by portions in p_mzq */
628 if (total > p_mzq)
629 msec = p_mzq;
630 else
631 msec = total;
632 total -= msec;
633#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634#ifdef HAVE_NANOSLEEP
635 {
636 struct timespec ts;
637
638 ts.tv_sec = msec / 1000;
639 ts.tv_nsec = (msec % 1000) * 1000000;
640 (void)nanosleep(&ts, NULL);
641 }
642#else
643# ifdef HAVE_USLEEP
644 while (msec >= 1000)
645 {
646 usleep((unsigned int)(999 * 1000));
647 msec -= 999;
648 }
649 usleep((unsigned int)(msec * 1000));
650# else
651# ifndef HAVE_SELECT
652 poll(NULL, 0, (int)msec);
653# else
654# ifdef __EMX__
655 _sleep2(msec);
656# else
657 {
658 struct timeval tv;
659
660 tv.tv_sec = msec / 1000;
661 tv.tv_usec = (msec % 1000) * 1000;
662 /*
663 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
664 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
665 */
666 select(0, NULL, NULL, NULL, &tv);
667 }
668# endif /* __EMX__ */
669# endif /* HAVE_SELECT */
670# endif /* HAVE_NANOSLEEP */
671#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000672#ifdef FEAT_MZSCHEME
673 }
674 while (total > 0);
675#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000676
677 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000678 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000679 }
680 else
681 WaitForChar(msec);
682}
683
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000684#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000685 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
686# define HAVE_CHECK_STACK_GROWTH
687/*
688 * Support for checking for an almost-out-of-stack-space situation.
689 */
690
691/*
692 * Return a pointer to an item on the stack. Used to find out if the stack
693 * grows up or down.
694 */
695static void check_stack_growth __ARGS((char *p));
696static int stack_grows_downwards;
697
698/*
699 * Find out if the stack grows upwards or downwards.
700 * "p" points to a variable on the stack of the caller.
701 */
702 static void
703check_stack_growth(p)
704 char *p;
705{
706 int i;
707
708 stack_grows_downwards = (p > (char *)&i);
709}
710#endif
711
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000712#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713static char *stack_limit = NULL;
714
715#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
716# include <pthread.h>
717# include <pthread_np.h>
718#endif
719
720/*
721 * Find out until how var the stack can grow without getting into trouble.
722 * Called when starting up and when switching to the signal stack in
723 * deathtrap().
724 */
725 static void
726get_stack_limit()
727{
728 struct rlimit rlp;
729 int i;
730 long lim;
731
732 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
733 * limit doesn't fit in a long (rlim_cur might be "long long"). */
734 if (getrlimit(RLIMIT_STACK, &rlp) == 0
735 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
736# ifdef RLIM_INFINITY
737 && rlp.rlim_cur != RLIM_INFINITY
738# endif
739 )
740 {
741 lim = (long)rlp.rlim_cur;
742#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
743 {
744 pthread_attr_t attr;
745 size_t size;
746
747 /* On FreeBSD the initial thread always has a fixed stack size, no
748 * matter what the limits are set to. Normally it's 1 Mbyte. */
749 pthread_attr_init(&attr);
750 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
751 {
752 pthread_attr_getstacksize(&attr, &size);
753 if (lim > (long)size)
754 lim = (long)size;
755 }
756 pthread_attr_destroy(&attr);
757 }
758#endif
759 if (stack_grows_downwards)
760 {
761 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
762 if (stack_limit >= (char *)&i)
763 /* overflow, set to 1/16 of current stack position */
764 stack_limit = (char *)((long)&i / 16L);
765 }
766 else
767 {
768 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
769 if (stack_limit <= (char *)&i)
770 stack_limit = NULL; /* overflow */
771 }
772 }
773}
774
775/*
776 * Return FAIL when running out of stack space.
777 * "p" must point to any variable local to the caller that's on the stack.
778 */
779 int
780mch_stackcheck(p)
781 char *p;
782{
783 if (stack_limit != NULL)
784 {
785 if (stack_grows_downwards)
786 {
787 if (p < stack_limit)
788 return FAIL;
789 }
790 else if (p > stack_limit)
791 return FAIL;
792 }
793 return OK;
794}
795#endif
796
797#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
798/*
799 * Support for using the signal stack.
800 * This helps when we run out of stack space, which causes a SIGSEGV. The
801 * signal handler then must run on another stack, since the normal stack is
802 * completely full.
803 */
804
Bram Moolenaar39766a72013-11-03 00:41:00 +0100805#if defined(HAVE_AVAILABILITYMACROS_H)
Bram Moolenaar4cc95d12013-11-02 21:49:32 +0100806# include <AvailabilityMacros.h>
807#endif
808
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809#ifndef SIGSTKSZ
810# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
811#endif
812
813# ifdef HAVE_SIGALTSTACK
814static stack_t sigstk; /* for sigaltstack() */
815# else
816static struct sigstack sigstk; /* for sigstack() */
817# endif
818
819static void init_signal_stack __ARGS((void));
820static char *signal_stack;
821
822 static void
823init_signal_stack()
824{
825 if (signal_stack != NULL)
826 {
827# ifdef HAVE_SIGALTSTACK
Bram Moolenaar1a3d0862007-08-30 09:47:38 +0000828# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
829 || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
831 * "struct sigaltstack" needs to be declared. */
832 extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
833# endif
834
835# ifdef HAVE_SS_BASE
836 sigstk.ss_base = signal_stack;
837# else
838 sigstk.ss_sp = signal_stack;
839# endif
840 sigstk.ss_size = SIGSTKSZ;
841 sigstk.ss_flags = 0;
842 (void)sigaltstack(&sigstk, NULL);
843# else
844 sigstk.ss_sp = signal_stack;
845 if (stack_grows_downwards)
846 sigstk.ss_sp += SIGSTKSZ - 1;
847 sigstk.ss_onstack = 0;
848 (void)sigstack(&sigstk, NULL);
849# endif
850 }
851}
852#endif
853
854/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000855 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856 * will barf when the second argument to signal() is ``wrong''.
857 * Let me try it with a few tricky defines from my own osdef.h (jw).
858 */
859#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860 static RETSIGTYPE
861sig_winch SIGDEFARG(sigarg)
862{
863 /* this is not required on all systems, but it doesn't hurt anybody */
864 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
865 do_resize = TRUE;
866 SIGRETURN;
867}
868#endif
869
870#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000871 static RETSIGTYPE
872catch_sigint SIGDEFARG(sigarg)
873{
874 /* this is not required on all systems, but it doesn't hurt anybody */
875 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
876 got_int = TRUE;
877 SIGRETURN;
878}
879#endif
880
881#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000882 static RETSIGTYPE
883catch_sigpwr SIGDEFARG(sigarg)
884{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000885 /* this is not required on all systems, but it doesn't hurt anybody */
886 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 /*
888 * I'm not sure we get the SIGPWR signal when the system is really going
889 * down or when the batteries are almost empty. Just preserve the swap
890 * files and don't exit, that can't do any harm.
891 */
892 ml_sync_all(FALSE, FALSE);
893 SIGRETURN;
894}
895#endif
896
897#ifdef SET_SIG_ALARM
898/*
899 * signal function for alarm().
900 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000901 static RETSIGTYPE
902sig_alarm SIGDEFARG(sigarg)
903{
904 /* doesn't do anything, just to break a system call */
905 sig_alarm_called = TRUE;
906 SIGRETURN;
907}
908#endif
909
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000910#if (defined(HAVE_SETJMP_H) \
911 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
912 || defined(FEAT_LIBCALL))) \
913 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000914/*
915 * A simplistic version of setjmp() that only allows one level of using.
916 * Don't call twice before calling mch_endjmp()!.
917 * Usage:
918 * mch_startjmp();
919 * if (SETJMP(lc_jump_env) != 0)
920 * {
921 * mch_didjmp();
922 * EMSG("crash!");
923 * }
924 * else
925 * {
926 * do_the_work;
927 * mch_endjmp();
928 * }
929 * Note: Can't move SETJMP() here, because a function calling setjmp() must
930 * not return before the saved environment is used.
931 * Returns OK for normal return, FAIL when the protected code caused a
932 * problem and LONGJMP() was used.
933 */
934 void
935mch_startjmp()
936{
937#ifdef SIGHASARG
938 lc_signal = 0;
939#endif
940 lc_active = TRUE;
941}
942
943 void
944mch_endjmp()
945{
946 lc_active = FALSE;
947}
948
949 void
950mch_didjmp()
951{
952# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
953 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
954 * otherwise catching the signal only works once. */
955 init_signal_stack();
956# endif
957}
958#endif
959
960/*
961 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200962 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000963 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200964 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
965 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000966 */
967 static RETSIGTYPE
968deathtrap SIGDEFARG(sigarg)
969{
970 static int entered = 0; /* count the number of times we got here.
971 Note: when memory has been corrupted
972 this may get an arbitrary value! */
973#ifdef SIGHASARG
974 int i;
975#endif
976
977#if defined(HAVE_SETJMP_H)
978 /*
979 * Catch a crash in protected code.
980 * Restores the environment saved in lc_jump_env, which looks like
981 * SETJMP() returns 1.
982 */
983 if (lc_active)
984 {
985# if defined(SIGHASARG)
986 lc_signal = sigarg;
987# endif
988 lc_active = FALSE; /* don't jump again */
989 LONGJMP(lc_jump_env, 1);
990 /* NOTREACHED */
991 }
992#endif
993
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000994#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000995# ifdef SIGQUIT
996 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
997 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
998 * pressing CTRL-\, but we don't want Vim to exit then. */
999 if (in_mch_delay && sigarg == SIGQUIT)
1000 SIGRETURN;
1001# endif
1002
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001003 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
1004 * here. This avoids that a non-reentrant function is interrupted, e.g.,
1005 * free(). Calling free() again may then cause a crash. */
1006 if (entered == 0
1007 && (0
1008# ifdef SIGHUP
1009 || sigarg == SIGHUP
1010# endif
1011# ifdef SIGQUIT
1012 || sigarg == SIGQUIT
1013# endif
1014# ifdef SIGTERM
1015 || sigarg == SIGTERM
1016# endif
1017# ifdef SIGPWR
1018 || sigarg == SIGPWR
1019# endif
1020# ifdef SIGUSR1
1021 || sigarg == SIGUSR1
1022# endif
1023# ifdef SIGUSR2
1024 || sigarg == SIGUSR2
1025# endif
1026 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001027 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001028 SIGRETURN;
1029#endif
1030
Bram Moolenaar071d4272004-06-13 20:20:40 +00001031 /* Remember how often we have been called. */
1032 ++entered;
1033
1034#ifdef FEAT_EVAL
1035 /* Set the v:dying variable. */
1036 set_vim_var_nr(VV_DYING, (long)entered);
1037#endif
1038
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001039#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040 /* Since we are now using the signal stack, need to reset the stack
1041 * limit. Otherwise using a regexp will fail. */
1042 get_stack_limit();
1043#endif
1044
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001045#if 0
1046 /* This is for opening gdb the moment Vim crashes.
1047 * You need to manually adjust the file name and Vim executable name.
1048 * Suggested by SungHyun Nam. */
1049 {
1050# define VI_GDB_FILE "/tmp/vimgdb"
1051# define VIM_NAME "/usr/bin/vim"
1052 FILE *fp = fopen(VI_GDB_FILE, "w");
1053 if (fp)
1054 {
1055 fprintf(fp,
1056 "file %s\n"
1057 "attach %d\n"
1058 "set height 1000\n"
1059 "bt full\n"
1060 , VIM_NAME, getpid());
1061 fclose(fp);
1062 system("xterm -e gdb -x "VI_GDB_FILE);
1063 unlink(VI_GDB_FILE);
1064 }
1065 }
1066#endif
1067
Bram Moolenaar071d4272004-06-13 20:20:40 +00001068#ifdef SIGHASARG
1069 /* try to find the name of this signal */
1070 for (i = 0; signal_info[i].sig != -1; i++)
1071 if (sigarg == signal_info[i].sig)
1072 break;
1073 deadly_signal = sigarg;
1074#endif
1075
1076 full_screen = FALSE; /* don't write message to the GUI, it might be
1077 * part of the problem... */
1078 /*
1079 * If something goes wrong after entering here, we may get here again.
1080 * When this happens, give a message and try to exit nicely (resetting the
1081 * terminal mode, etc.)
1082 * When this happens twice, just exit, don't even try to give a message,
1083 * stack may be corrupt or something weird.
1084 * When this still happens again (or memory was corrupted in such a way
1085 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1086 */
1087 if (entered >= 3)
1088 {
1089 reset_signals(); /* don't catch any signals anymore */
1090 may_core_dump();
1091 if (entered >= 4)
1092 _exit(8);
1093 exit(7);
1094 }
1095 if (entered == 2)
1096 {
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001097 /* No translation, it may call malloc(). */
1098 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001099 out_flush();
1100 getout(1);
1101 }
1102
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001103 /* No translation, it may call malloc(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104#ifdef SIGHASARG
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001105 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001106 signal_info[i].name);
1107#else
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001108 sprintf((char *)IObuff, "Vim: Caught deadly signal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001110
1111 /* Preserve files and exit. This sets the really_exiting flag to prevent
1112 * calling free(). */
1113 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001114
Bram Moolenaar009b2592004-10-24 19:18:58 +00001115#ifdef NBDEBUG
1116 reset_signals();
1117 may_core_dump();
1118 abort();
1119#endif
1120
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121 SIGRETURN;
1122}
1123
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001124#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001125/*
1126 * On Solaris with multi-threading, suspending might not work immediately.
1127 * Catch the SIGCONT signal, which will be used as an indication whether the
1128 * suspending has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001129 *
1130 * On Linux, signal is not always handled immediately either.
1131 * See https://bugs.launchpad.net/bugs/291373
1132 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001133 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001135static volatile int sigcont_received;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001136static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1137
1138/*
1139 * signal handler for SIGCONT
1140 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001141 static RETSIGTYPE
1142sigcont_handler SIGDEFARG(sigarg)
1143{
1144 sigcont_received = TRUE;
1145 SIGRETURN;
1146}
1147#endif
1148
Bram Moolenaar62b42182010-09-21 22:09:37 +02001149# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1150static void loose_clipboard __ARGS((void));
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001151# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001152static void save_clipboard __ARGS((void));
1153static void restore_clipboard __ARGS((void));
1154
1155static void *clip_star_save = NULL;
1156static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001157# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001158
1159/*
1160 * Called when Vim is going to sleep or execute a shell command.
1161 * We can't respond to requests for the X selections. Lose them, otherwise
1162 * other applications will hang. But first copy the text to cut buffer 0.
1163 */
1164 static void
1165loose_clipboard()
1166{
1167 if (clip_star.owned || clip_plus.owned)
1168 {
1169 x11_export_final_selection();
1170 if (clip_star.owned)
1171 clip_lose_selection(&clip_star);
1172 if (clip_plus.owned)
1173 clip_lose_selection(&clip_plus);
1174 if (x11_display != NULL)
1175 XFlush(x11_display);
1176 }
1177}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001178
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001179# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001180/*
1181 * Save clipboard text to restore later.
1182 */
1183 static void
1184save_clipboard()
1185{
1186 if (clip_star.owned)
1187 clip_star_save = get_register('*', TRUE);
1188 if (clip_plus.owned)
1189 clip_plus_save = get_register('+', TRUE);
1190}
1191
1192/*
1193 * Restore clipboard text if no one own the X selection.
1194 */
1195 static void
1196restore_clipboard()
1197{
1198 if (clip_star_save != NULL)
1199 {
1200 if (!clip_gen_owner_exists(&clip_star))
1201 put_register('*', clip_star_save);
1202 else
1203 free_register(clip_star_save);
1204 clip_star_save = NULL;
1205 }
1206 if (clip_plus_save != NULL)
1207 {
1208 if (!clip_gen_owner_exists(&clip_plus))
1209 put_register('+', clip_plus_save);
1210 else
1211 free_register(clip_plus_save);
1212 clip_plus_save = NULL;
1213 }
1214}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001215# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001216#endif
1217
Bram Moolenaar071d4272004-06-13 20:20:40 +00001218/*
1219 * If the machine has job control, use it to suspend the program,
1220 * otherwise fake it by starting a new shell.
1221 */
1222 void
1223mch_suspend()
1224{
1225 /* BeOS does have SIGTSTP, but it doesn't work. */
1226#if defined(SIGTSTP) && !defined(__BEOS__)
1227 out_flush(); /* needed to make cursor visible on some systems */
1228 settmode(TMODE_COOK);
1229 out_flush(); /* needed to disable mouse on some systems */
1230
1231# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001232 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233# endif
1234
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001235# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001236 sigcont_received = FALSE;
1237# endif
1238 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001239# if defined(_REENTRANT) && defined(SIGCONT)
1240 /*
1241 * Wait for the SIGCONT signal to be handled. It generally happens
1242 * immediately, but somehow not all the time. Do not call pause()
1243 * because there would be race condition which would hang Vim if
1244 * signal happened in between the test of sigcont_received and the
1245 * call to pause(). If signal is not yet received, call sleep(0)
1246 * to just yield CPU. Signal should then be received. If somehow
1247 * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
1248 * further if signal is not received after 1+2+3+4 ms (not expected
1249 * to happen).
1250 */
1251 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001252 long wait_time;
1253 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001254 /* Loop is not entered most of the time */
Bram Moolenaar262735e2009-07-14 10:20:22 +00001255 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001256 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001257# endif
1258
1259# ifdef FEAT_TITLE
1260 /*
1261 * Set oldtitle to NULL, so the current title is obtained again.
1262 */
1263 vim_free(oldtitle);
1264 oldtitle = NULL;
1265# endif
1266 settmode(TMODE_RAW);
1267 need_check_timestamps = TRUE;
1268 did_check_timestamps = FALSE;
1269#else
1270 suspend_shell();
1271#endif
1272}
1273
1274 void
1275mch_init()
1276{
1277 Columns = 80;
1278 Rows = 24;
1279
1280 out_flush();
1281 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001282
Bram Moolenaar56718732006-03-15 22:53:57 +00001283#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001284 mac_conv_init();
1285#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001286#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1287 win_clip_init();
1288#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289}
1290
1291 static void
1292set_signals()
1293{
1294#if defined(SIGWINCH)
1295 /*
1296 * WINDOW CHANGE signal is handled with sig_winch().
1297 */
1298 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1299#endif
1300
1301 /*
1302 * We want the STOP signal to work, to make mch_suspend() work.
1303 * For "rvim" the STOP signal is ignored.
1304 */
1305#ifdef SIGTSTP
1306 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1307#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001308#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001309 signal(SIGCONT, sigcont_handler);
1310#endif
1311
1312 /*
1313 * We want to ignore breaking of PIPEs.
1314 */
1315#ifdef SIGPIPE
1316 signal(SIGPIPE, SIG_IGN);
1317#endif
1318
Bram Moolenaar071d4272004-06-13 20:20:40 +00001319#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001320 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001321#endif
1322
1323 /*
1324 * Ignore alarm signals (Perl's alarm() generates it).
1325 */
1326#ifdef SIGALRM
1327 signal(SIGALRM, SIG_IGN);
1328#endif
1329
1330 /*
1331 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1332 * work will be lost.
1333 */
1334#ifdef SIGPWR
1335 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1336#endif
1337
1338 /*
1339 * Arrange for other signals to gracefully shutdown Vim.
1340 */
1341 catch_signals(deathtrap, SIG_ERR);
1342
1343#if defined(FEAT_GUI) && defined(SIGHUP)
1344 /*
1345 * When the GUI is running, ignore the hangup signal.
1346 */
1347 if (gui.in_use)
1348 signal(SIGHUP, SIG_IGN);
1349#endif
1350}
1351
Bram Moolenaardf177f62005-02-22 08:39:57 +00001352#if defined(SIGINT) || defined(PROTO)
1353/*
1354 * Catch CTRL-C (only works while in Cooked mode).
1355 */
1356 static void
1357catch_int_signal()
1358{
1359 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1360}
1361#endif
1362
Bram Moolenaar071d4272004-06-13 20:20:40 +00001363 void
1364reset_signals()
1365{
1366 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001367#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001368 /* SIGCONT isn't in the list, because its default action is ignore */
1369 signal(SIGCONT, SIG_DFL);
1370#endif
1371}
1372
1373 static void
1374catch_signals(func_deadly, func_other)
1375 RETSIGTYPE (*func_deadly)();
1376 RETSIGTYPE (*func_other)();
1377{
1378 int i;
1379
1380 for (i = 0; signal_info[i].sig != -1; i++)
1381 if (signal_info[i].deadly)
1382 {
1383#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1384 struct sigaction sa;
1385
1386 /* Setup to use the alternate stack for the signal function. */
1387 sa.sa_handler = func_deadly;
1388 sigemptyset(&sa.sa_mask);
1389# if defined(__linux__) && defined(_REENTRANT)
1390 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1391 * thread handling in combination with using the alternate stack:
1392 * pthread library functions try to use the stack pointer to
1393 * identify the current thread, causing a SEGV signal, which
1394 * recursively calls deathtrap() and hangs. */
1395 sa.sa_flags = 0;
1396# else
1397 sa.sa_flags = SA_ONSTACK;
1398# endif
1399 sigaction(signal_info[i].sig, &sa, NULL);
1400#else
1401# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1402 struct sigvec sv;
1403
1404 /* Setup to use the alternate stack for the signal function. */
1405 sv.sv_handler = func_deadly;
1406 sv.sv_mask = 0;
1407 sv.sv_flags = SV_ONSTACK;
1408 sigvec(signal_info[i].sig, &sv, NULL);
1409# else
1410 signal(signal_info[i].sig, func_deadly);
1411# endif
1412#endif
1413 }
1414 else if (func_other != SIG_ERR)
1415 signal(signal_info[i].sig, func_other);
1416}
1417
1418/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001419 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001420 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1421 * return TRUE
1422 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1423 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001424 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001425 * Returns TRUE when Vim should exit.
1426 */
1427 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001428vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001429 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001430{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001431 static int got_signal = 0;
1432 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001433
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001434 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001435 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001436 case SIGNAL_BLOCK: blocked = TRUE;
1437 break;
1438
1439 case SIGNAL_UNBLOCK: blocked = FALSE;
1440 if (got_signal != 0)
1441 {
1442 kill(getpid(), got_signal);
1443 got_signal = 0;
1444 }
1445 break;
1446
1447 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001448 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001449 got_signal = sig;
1450#ifdef SIGPWR
1451 if (sig != SIGPWR)
1452#endif
1453 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001454 break;
1455 }
1456 return FALSE;
1457}
1458
1459/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001460 * Check_win checks whether we have an interactive stdout.
1461 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001462 int
1463mch_check_win(argc, argv)
Bram Moolenaar78a15312009-05-15 19:33:18 +00001464 int argc UNUSED;
1465 char **argv UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001466{
1467#ifdef OS2
1468 /*
1469 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1470 * name, mostly it's just "vim" and found in the path, which is unusable.
1471 */
1472 if (mch_isFullName(argv[0]))
1473 exe_name = vim_strsave((char_u *)argv[0]);
1474#endif
1475 if (isatty(1))
1476 return OK;
1477 return FAIL;
1478}
1479
1480/*
1481 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1482 */
1483 int
1484mch_input_isatty()
1485{
1486 if (isatty(read_cmd_fd))
1487 return TRUE;
1488 return FALSE;
1489}
1490
1491#ifdef FEAT_X11
1492
1493# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1494 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1495
1496static void xopen_message __ARGS((struct timeval *tvp));
1497
1498/*
1499 * Give a message about the elapsed time for opening the X window.
1500 */
1501 static void
1502xopen_message(tvp)
1503 struct timeval *tvp; /* must contain start time */
1504{
1505 struct timeval end_tv;
1506
1507 /* Compute elapsed time. */
1508 gettimeofday(&end_tv, NULL);
1509 smsg((char_u *)_("Opening the X display took %ld msec"),
1510 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001511 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001512}
1513# endif
1514#endif
1515
1516#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1517/*
1518 * A few functions shared by X11 title and clipboard code.
1519 */
1520static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1521static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1522static int x_connect_to_server __ARGS((void));
1523static int test_x11_window __ARGS((Display *dpy));
1524
1525static int got_x_error = FALSE;
1526
1527/*
1528 * X Error handler, otherwise X just exits! (very rude) -- webb
1529 */
1530 static int
1531x_error_handler(dpy, error_event)
1532 Display *dpy;
1533 XErrorEvent *error_event;
1534{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001535 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001536 STRCAT(IObuff, _("\nVim: Got X error\n"));
1537
1538 /* We cannot print a message and continue, because no X calls are allowed
1539 * here (causes my system to hang). Silently continuing might be an
1540 * alternative... */
1541 preserve_exit(); /* preserve files and exit */
1542
1543 return 0; /* NOTREACHED */
1544}
1545
1546/*
1547 * Another X Error handler, just used to check for errors.
1548 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001549 static int
1550x_error_check(dpy, error_event)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001551 Display *dpy UNUSED;
1552 XErrorEvent *error_event UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001553{
1554 got_x_error = TRUE;
1555 return 0;
1556}
1557
1558#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1559# if defined(HAVE_SETJMP_H)
1560/*
1561 * An X IO Error handler, used to catch error while opening the display.
1562 */
1563static int x_IOerror_check __ARGS((Display *dpy));
1564
Bram Moolenaar071d4272004-06-13 20:20:40 +00001565 static int
1566x_IOerror_check(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001567 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568{
1569 /* This function should not return, it causes exit(). Longjump instead. */
1570 LONGJMP(lc_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001571# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001572 return 0; /* avoid the compiler complains about missing return value */
1573# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001574}
1575# endif
1576
1577/*
1578 * An X IO Error handler, used to catch terminal errors.
1579 */
1580static int x_IOerror_handler __ARGS((Display *dpy));
1581
Bram Moolenaar071d4272004-06-13 20:20:40 +00001582 static int
1583x_IOerror_handler(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001584 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001585{
1586 xterm_dpy = NULL;
1587 x11_window = 0;
1588 x11_display = NULL;
1589 xterm_Shell = (Widget)0;
1590
1591 /* This function should not return, it causes exit(). Longjump instead. */
1592 LONGJMP(x_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001593# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001594 return 0; /* avoid the compiler complains about missing return value */
1595# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596}
1597#endif
1598
1599/*
1600 * Return TRUE when connection to the X server is desired.
1601 */
1602 static int
1603x_connect_to_server()
1604{
1605 regmatch_T regmatch;
1606
1607#if defined(FEAT_CLIENTSERVER)
1608 if (x_force_connect)
1609 return TRUE;
1610#endif
1611 if (x_no_connect)
1612 return FALSE;
1613
1614 /* Check for a match with "exclude:" from 'clipboard'. */
1615 if (clip_exclude_prog != NULL)
1616 {
1617 regmatch.rm_ic = FALSE; /* Don't ignore case */
1618 regmatch.regprog = clip_exclude_prog;
1619 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1620 return FALSE;
1621 }
1622 return TRUE;
1623}
1624
1625/*
1626 * Test if "dpy" and x11_window are valid by getting the window title.
1627 * I don't actually want it yet, so there may be a simpler call to use, but
1628 * this will cause the error handler x_error_check() to be called if anything
1629 * is wrong, such as the window pointer being invalid (as can happen when the
1630 * user changes his DISPLAY, but not his WINDOWID) -- webb
1631 */
1632 static int
1633test_x11_window(dpy)
1634 Display *dpy;
1635{
1636 int (*old_handler)();
1637 XTextProperty text_prop;
1638
1639 old_handler = XSetErrorHandler(x_error_check);
1640 got_x_error = FALSE;
1641 if (XGetWMName(dpy, x11_window, &text_prop))
1642 XFree((void *)text_prop.value);
1643 XSync(dpy, False);
1644 (void)XSetErrorHandler(old_handler);
1645
1646 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001647 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648
1649 return (got_x_error ? FAIL : OK);
1650}
1651#endif
1652
1653#ifdef FEAT_TITLE
1654
1655#ifdef FEAT_X11
1656
1657static int get_x11_thing __ARGS((int get_title, int test_only));
1658
1659/*
1660 * try to get x11 window and display
1661 *
1662 * return FAIL for failure, OK otherwise
1663 */
1664 static int
1665get_x11_windis()
1666{
1667 char *winid;
1668 static int result = -1;
1669#define XD_NONE 0 /* x11_display not set here */
1670#define XD_HERE 1 /* x11_display opened here */
1671#define XD_GUI 2 /* x11_display used from gui.dpy */
1672#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1673 static int x11_display_from = XD_NONE;
1674 static int did_set_error_handler = FALSE;
1675
1676 if (!did_set_error_handler)
1677 {
1678 /* X just exits if it finds an error otherwise! */
1679 (void)XSetErrorHandler(x_error_handler);
1680 did_set_error_handler = TRUE;
1681 }
1682
Bram Moolenaar9372a112005-12-06 19:59:18 +00001683#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001684 if (gui.in_use)
1685 {
1686 /*
1687 * If the X11 display was opened here before, for the window where Vim
1688 * was started, close that one now to avoid a memory leak.
1689 */
1690 if (x11_display_from == XD_HERE && x11_display != NULL)
1691 {
1692 XCloseDisplay(x11_display);
1693 x11_display_from = XD_NONE;
1694 }
1695 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1696 {
1697 x11_display_from = XD_GUI;
1698 return OK;
1699 }
1700 x11_display = NULL;
1701 return FAIL;
1702 }
1703 else if (x11_display_from == XD_GUI)
1704 {
1705 /* GUI must have stopped somehow, clear x11_display */
1706 x11_window = 0;
1707 x11_display = NULL;
1708 x11_display_from = XD_NONE;
1709 }
1710#endif
1711
1712 /* When started with the "-X" argument, don't try connecting. */
1713 if (!x_connect_to_server())
1714 return FAIL;
1715
1716 /*
1717 * If WINDOWID not set, should try another method to find out
1718 * what the current window number is. The only code I know for
1719 * this is very complicated.
1720 * We assume that zero is invalid for WINDOWID.
1721 */
1722 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1723 x11_window = (Window)atol(winid);
1724
1725#ifdef FEAT_XCLIPBOARD
1726 if (xterm_dpy != NULL && x11_window != 0)
1727 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001728 /* We may have checked it already, but Gnome terminal can move us to
1729 * another window, so we need to check every time. */
1730 if (x11_display_from != XD_XTERM)
1731 {
1732 /*
1733 * If the X11 display was opened here before, for the window where
1734 * Vim was started, close that one now to avoid a memory leak.
1735 */
1736 if (x11_display_from == XD_HERE && x11_display != NULL)
1737 XCloseDisplay(x11_display);
1738 x11_display = xterm_dpy;
1739 x11_display_from = XD_XTERM;
1740 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001741 if (test_x11_window(x11_display) == FAIL)
1742 {
1743 /* probably bad $WINDOWID */
1744 x11_window = 0;
1745 x11_display = NULL;
1746 x11_display_from = XD_NONE;
1747 return FAIL;
1748 }
1749 return OK;
1750 }
1751#endif
1752
1753 if (x11_window == 0 || x11_display == NULL)
1754 result = -1;
1755
1756 if (result != -1) /* Have already been here and set this */
1757 return result; /* Don't do all these X calls again */
1758
1759 if (x11_window != 0 && x11_display == NULL)
1760 {
1761#ifdef SET_SIG_ALARM
1762 RETSIGTYPE (*sig_save)();
1763#endif
1764#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1765 struct timeval start_tv;
1766
1767 if (p_verbose > 0)
1768 gettimeofday(&start_tv, NULL);
1769#endif
1770
1771#ifdef SET_SIG_ALARM
1772 /*
1773 * Opening the Display may hang if the DISPLAY setting is wrong, or
1774 * the network connection is bad. Set an alarm timer to get out.
1775 */
1776 sig_alarm_called = FALSE;
1777 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1778 (RETSIGTYPE (*)())sig_alarm);
1779 alarm(2);
1780#endif
1781 x11_display = XOpenDisplay(NULL);
1782
1783#ifdef SET_SIG_ALARM
1784 alarm(0);
1785 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1786 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001787 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001788#endif
1789 if (x11_display != NULL)
1790 {
1791# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1792 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001793 {
1794 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001795 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001796 verbose_leave();
1797 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798# endif
1799 if (test_x11_window(x11_display) == FAIL)
1800 {
1801 /* Maybe window id is bad */
1802 x11_window = 0;
1803 XCloseDisplay(x11_display);
1804 x11_display = NULL;
1805 }
1806 else
1807 x11_display_from = XD_HERE;
1808 }
1809 }
1810 if (x11_window == 0 || x11_display == NULL)
1811 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001812
1813# ifdef FEAT_EVAL
1814 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1815# endif
1816
Bram Moolenaar071d4272004-06-13 20:20:40 +00001817 return (result = OK);
1818}
1819
1820/*
1821 * Determine original x11 Window Title
1822 */
1823 static int
1824get_x11_title(test_only)
1825 int test_only;
1826{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001827 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001828}
1829
1830/*
1831 * Determine original x11 Window icon
1832 */
1833 static int
1834get_x11_icon(test_only)
1835 int test_only;
1836{
1837 int retval = FALSE;
1838
1839 retval = get_x11_thing(FALSE, test_only);
1840
1841 /* could not get old icon, use terminal name */
1842 if (oldicon == NULL && !test_only)
1843 {
1844 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001845 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001847 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848 }
1849
1850 return retval;
1851}
1852
1853 static int
1854get_x11_thing(get_title, test_only)
1855 int get_title; /* get title string */
1856 int test_only;
1857{
1858 XTextProperty text_prop;
1859 int retval = FALSE;
1860 Status status;
1861
1862 if (get_x11_windis() == OK)
1863 {
1864 /* Get window/icon name if any */
1865 if (get_title)
1866 status = XGetWMName(x11_display, x11_window, &text_prop);
1867 else
1868 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1869
1870 /*
1871 * If terminal is xterm, then x11_window may be a child window of the
1872 * outer xterm window that actually contains the window/icon name, so
1873 * keep traversing up the tree until a window with a title/icon is
1874 * found.
1875 */
1876 /* Previously this was only done for xterm and alikes. I don't see a
1877 * reason why it would fail for other terminal emulators.
1878 * if (term_is_xterm) */
1879 {
1880 Window root;
1881 Window parent;
1882 Window win = x11_window;
1883 Window *children;
1884 unsigned int num_children;
1885
1886 while (!status || text_prop.value == NULL)
1887 {
1888 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1889 &num_children))
1890 break;
1891 if (children)
1892 XFree((void *)children);
1893 if (parent == root || parent == 0)
1894 break;
1895
1896 win = parent;
1897 if (get_title)
1898 status = XGetWMName(x11_display, win, &text_prop);
1899 else
1900 status = XGetWMIconName(x11_display, win, &text_prop);
1901 }
1902 }
1903 if (status && text_prop.value != NULL)
1904 {
1905 retval = TRUE;
1906 if (!test_only)
1907 {
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001908#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
1909 if (text_prop.encoding == XA_STRING
1910# ifdef FEAT_MBYTE
1911 && !has_mbyte
1912# endif
1913 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001914 {
1915#endif
1916 if (get_title)
1917 oldtitle = vim_strsave((char_u *)text_prop.value);
1918 else
1919 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001920#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001921 }
1922 else
1923 {
1924 char **cl;
1925 Status transform_status;
1926 int n = 0;
1927
1928 transform_status = XmbTextPropertyToTextList(x11_display,
1929 &text_prop,
1930 &cl, &n);
1931 if (transform_status >= Success && n > 0 && cl[0])
1932 {
1933 if (get_title)
1934 oldtitle = vim_strsave((char_u *) cl[0]);
1935 else
1936 oldicon = vim_strsave((char_u *) cl[0]);
1937 XFreeStringList(cl);
1938 }
1939 else
1940 {
1941 if (get_title)
1942 oldtitle = vim_strsave((char_u *)text_prop.value);
1943 else
1944 oldicon = vim_strsave((char_u *)text_prop.value);
1945 }
1946 }
1947#endif
1948 }
1949 XFree((void *)text_prop.value);
1950 }
1951 }
1952 return retval;
1953}
1954
1955/* Are Xutf8 functions available? Avoid error from old compilers. */
1956#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1957# if X_HAVE_UTF8_STRING
1958# define USE_UTF8_STRING
1959# endif
1960#endif
1961
1962/*
1963 * Set x11 Window Title
1964 *
1965 * get_x11_windis() must be called before this and have returned OK
1966 */
1967 static void
1968set_x11_title(title)
1969 char_u *title;
1970{
1971 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1972 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1973 * supported everywhere and STRING doesn't work for multi-byte titles.
1974 */
1975#ifdef USE_UTF8_STRING
1976 if (enc_utf8)
1977 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1978 NULL, NULL, 0, NULL, NULL, NULL);
1979 else
1980#endif
1981 {
1982#if XtSpecificationRelease >= 4
1983# ifdef FEAT_XFONTSET
1984 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1985 NULL, NULL, 0, NULL, NULL, NULL);
1986# else
1987 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001988 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001989
1990 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001991 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992 XSetWMProperties(x11_display, x11_window, &text_prop,
1993 NULL, NULL, 0, NULL, NULL, NULL);
1994# endif
1995#else
1996 XStoreName(x11_display, x11_window, (char *)title);
1997#endif
1998 }
1999 XFlush(x11_display);
2000}
2001
2002/*
2003 * Set x11 Window icon
2004 *
2005 * get_x11_windis() must be called before this and have returned OK
2006 */
2007 static void
2008set_x11_icon(icon)
2009 char_u *icon;
2010{
2011 /* See above for comments about using X*SetWMProperties(). */
2012#ifdef USE_UTF8_STRING
2013 if (enc_utf8)
2014 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2015 NULL, 0, NULL, NULL, NULL);
2016 else
2017#endif
2018 {
2019#if XtSpecificationRelease >= 4
2020# ifdef FEAT_XFONTSET
2021 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2022 NULL, 0, NULL, NULL, NULL);
2023# else
2024 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002025 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002026
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002027 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002028 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2029 NULL, 0, NULL, NULL, NULL);
2030# endif
2031#else
2032 XSetIconName(x11_display, x11_window, (char *)icon);
2033#endif
2034 }
2035 XFlush(x11_display);
2036}
2037
2038#else /* FEAT_X11 */
2039
Bram Moolenaar071d4272004-06-13 20:20:40 +00002040 static int
2041get_x11_title(test_only)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002042 int test_only UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043{
2044 return FALSE;
2045}
2046
2047 static int
2048get_x11_icon(test_only)
2049 int test_only;
2050{
2051 if (!test_only)
2052 {
2053 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002054 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002055 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002056 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057 }
2058 return FALSE;
2059}
2060
2061#endif /* FEAT_X11 */
2062
2063 int
2064mch_can_restore_title()
2065{
2066 return get_x11_title(TRUE);
2067}
2068
2069 int
2070mch_can_restore_icon()
2071{
2072 return get_x11_icon(TRUE);
2073}
2074
2075/*
2076 * Set the window title and icon.
2077 */
2078 void
2079mch_settitle(title, icon)
2080 char_u *title;
2081 char_u *icon;
2082{
2083 int type = 0;
2084 static int recursive = 0;
2085
2086 if (T_NAME == NULL) /* no terminal name (yet) */
2087 return;
2088 if (title == NULL && icon == NULL) /* nothing to do */
2089 return;
2090
2091 /* When one of the X11 functions causes a deadly signal, we get here again
2092 * recursively. Avoid hanging then (something is probably locked). */
2093 if (recursive)
2094 return;
2095 ++recursive;
2096
2097 /*
2098 * if the window ID and the display is known, we may use X11 calls
2099 */
2100#ifdef FEAT_X11
2101 if (get_x11_windis() == OK)
2102 type = 1;
2103#else
2104# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2105 if (gui.in_use)
2106 type = 1;
2107# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002108#endif
2109
2110 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002111 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112 * than x11 calls, because the x11 calls don't always work
2113 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002114 if ((type || *T_TS != NUL) && title != NULL)
2115 {
2116 if (oldtitle == NULL
2117#ifdef FEAT_GUI
2118 && !gui.in_use
2119#endif
2120 ) /* first call but not in GUI, save title */
2121 (void)get_x11_title(FALSE);
2122
2123 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2124 term_settitle(title);
2125#ifdef FEAT_X11
2126 else
2127# ifdef FEAT_GUI_GTK
2128 if (!gui.in_use) /* don't do this if GTK+ is running */
2129# endif
2130 set_x11_title(title); /* x11 */
2131#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002132#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002133 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2134 else
2135 gui_mch_settitle(title, icon);
2136#endif
2137 did_set_title = TRUE;
2138 }
2139
2140 if ((type || *T_CIS != NUL) && icon != NULL)
2141 {
2142 if (oldicon == NULL
2143#ifdef FEAT_GUI
2144 && !gui.in_use
2145#endif
2146 ) /* first call, save icon */
2147 get_x11_icon(FALSE);
2148
2149 if (*T_CIS != NUL)
2150 {
2151 out_str(T_CIS); /* set icon start */
2152 out_str_nf(icon);
2153 out_str(T_CIE); /* set icon end */
2154 out_flush();
2155 }
2156#ifdef FEAT_X11
2157 else
2158# ifdef FEAT_GUI_GTK
2159 if (!gui.in_use) /* don't do this if GTK+ is running */
2160# endif
2161 set_x11_icon(icon); /* x11 */
2162#endif
2163 did_set_icon = TRUE;
2164 }
2165 --recursive;
2166}
2167
2168/*
2169 * Restore the window/icon title.
2170 * "which" is one of:
2171 * 1 only restore title
2172 * 2 only restore icon
2173 * 3 restore title and icon
2174 */
2175 void
2176mch_restore_title(which)
2177 int which;
2178{
2179 /* only restore the title or icon when it has been set */
2180 mch_settitle(((which & 1) && did_set_title) ?
2181 (oldtitle ? oldtitle : p_titleold) : NULL,
2182 ((which & 2) && did_set_icon) ? oldicon : NULL);
2183}
2184
2185#endif /* FEAT_TITLE */
2186
2187/*
2188 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002189 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002190 */
2191 int
2192vim_is_xterm(name)
2193 char_u *name;
2194{
2195 if (name == NULL)
2196 return FALSE;
2197 return (STRNICMP(name, "xterm", 5) == 0
2198 || STRNICMP(name, "nxterm", 6) == 0
2199 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002200 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002201 || STRNICMP(name, "rxvt", 4) == 0
2202 || STRCMP(name, "builtin_xterm") == 0);
2203}
2204
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002205#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2206/*
2207 * Return TRUE if "name" appears to be that of a terminal
2208 * known to support the xterm-style mouse protocol.
2209 * Relies on term_is_xterm having been set to its correct value.
2210 */
2211 int
2212use_xterm_like_mouse(name)
2213 char_u *name;
2214{
2215 return (name != NULL
2216 && (term_is_xterm || STRNICMP(name, "screen", 6) == 0));
2217}
2218#endif
2219
Bram Moolenaar071d4272004-06-13 20:20:40 +00002220#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2221/*
2222 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2223 * Return 1 for "xterm".
2224 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002225 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002226 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002227 */
2228 int
2229use_xterm_mouse()
2230{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002231 if (ttym_flags == TTYM_SGR)
2232 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002233 if (ttym_flags == TTYM_URXVT)
2234 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002235 if (ttym_flags == TTYM_XTERM2)
2236 return 2;
2237 if (ttym_flags == TTYM_XTERM)
2238 return 1;
2239 return 0;
2240}
2241#endif
2242
2243 int
2244vim_is_iris(name)
2245 char_u *name;
2246{
2247 if (name == NULL)
2248 return FALSE;
2249 return (STRNICMP(name, "iris-ansi", 9) == 0
2250 || STRCMP(name, "builtin_iris-ansi") == 0);
2251}
2252
2253 int
2254vim_is_vt300(name)
2255 char_u *name;
2256{
2257 if (name == NULL)
2258 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002259 /* catch VT100 - VT5xx */
2260 return ((STRNICMP(name, "vt", 2) == 0
2261 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262 || STRCMP(name, "builtin_vt320") == 0);
2263}
2264
2265/*
2266 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2267 * This should include all windowed terminal emulators.
2268 */
2269 int
2270vim_is_fastterm(name)
2271 char_u *name;
2272{
2273 if (name == NULL)
2274 return FALSE;
2275 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2276 return TRUE;
2277 return ( STRNICMP(name, "hpterm", 6) == 0
2278 || STRNICMP(name, "sun-cmd", 7) == 0
2279 || STRNICMP(name, "screen", 6) == 0
2280 || STRNICMP(name, "dtterm", 6) == 0);
2281}
2282
2283/*
2284 * Insert user name in s[len].
2285 * Return OK if a name found.
2286 */
2287 int
2288mch_get_user_name(s, len)
2289 char_u *s;
2290 int len;
2291{
2292#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002293 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002294 return OK;
2295#else
2296 return mch_get_uname(getuid(), s, len);
2297#endif
2298}
2299
2300/*
2301 * Insert user name for "uid" in s[len].
2302 * Return OK if a name found.
2303 */
2304 int
2305mch_get_uname(uid, s, len)
2306 uid_t uid;
2307 char_u *s;
2308 int len;
2309{
2310#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2311 struct passwd *pw;
2312
2313 if ((pw = getpwuid(uid)) != NULL
2314 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2315 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002316 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 return OK;
2318 }
2319#endif
2320 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2321 return FAIL; /* a number is not a name */
2322}
2323
2324/*
2325 * Insert host name is s[len].
2326 */
2327
2328#ifdef HAVE_SYS_UTSNAME_H
2329 void
2330mch_get_host_name(s, len)
2331 char_u *s;
2332 int len;
2333{
2334 struct utsname vutsname;
2335
2336 if (uname(&vutsname) < 0)
2337 *s = NUL;
2338 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002339 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002340}
2341#else /* HAVE_SYS_UTSNAME_H */
2342
2343# ifdef HAVE_SYS_SYSTEMINFO_H
2344# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2345# endif
2346
2347 void
2348mch_get_host_name(s, len)
2349 char_u *s;
2350 int len;
2351{
2352# ifdef VAXC
2353 vaxc$gethostname((char *)s, len);
2354# else
2355 gethostname((char *)s, len);
2356# endif
2357 s[len - 1] = NUL; /* make sure it's terminated */
2358}
2359#endif /* HAVE_SYS_UTSNAME_H */
2360
2361/*
2362 * return process ID
2363 */
2364 long
2365mch_get_pid()
2366{
2367 return (long)getpid();
2368}
2369
2370#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2371static char *strerror __ARGS((int));
2372
2373 static char *
2374strerror(err)
2375 int err;
2376{
2377 extern int sys_nerr;
2378 extern char *sys_errlist[];
2379 static char er[20];
2380
2381 if (err > 0 && err < sys_nerr)
2382 return (sys_errlist[err]);
2383 sprintf(er, "Error %d", err);
2384 return er;
2385}
2386#endif
2387
2388/*
2389 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2390 * Return OK for success, FAIL for failure.
2391 */
2392 int
2393mch_dirname(buf, len)
2394 char_u *buf;
2395 int len;
2396{
2397#if defined(USE_GETCWD)
2398 if (getcwd((char *)buf, len) == NULL)
2399 {
2400 STRCPY(buf, strerror(errno));
2401 return FAIL;
2402 }
2403 return OK;
2404#else
2405 return (getwd((char *)buf) != NULL ? OK : FAIL);
2406#endif
2407}
2408
2409#if defined(OS2) || defined(PROTO)
2410/*
2411 * Replace all slashes by backslashes.
2412 * When 'shellslash' set do it the other way around.
2413 */
2414 void
2415slash_adjust(p)
2416 char_u *p;
2417{
2418 while (*p)
2419 {
2420 if (*p == psepcN)
2421 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002422 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002423 }
2424}
2425#endif
2426
2427/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002428 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429 *
2430 * return FAIL for failure, OK for success
2431 */
2432 int
2433mch_FullName(fname, buf, len, force)
2434 char_u *fname, *buf;
2435 int len;
2436 int force; /* also expand when already absolute path */
2437{
2438 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002439#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002440 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002441#endif
2442#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002443 int fd = -1;
2444 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002445#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002446 char_u olddir[MAXPATHL];
2447 char_u *p;
2448 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002449#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002450 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2451 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002452#endif
2453
Bram Moolenaar38323e42007-03-06 19:22:53 +00002454#ifdef VMS
2455 fname = vms_fixfilename(fname);
2456#endif
2457
Bram Moolenaara2442432007-04-26 14:26:37 +00002458#ifdef __CYGWIN__
2459 /*
2460 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2461 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002462# if CYGWIN_VERSION_DLL_MAJOR >= 1007
2463 cygwin_conv_path(CCP_WIN_A_TO_POSIX, fname, posix_fname, MAXPATHL);
2464# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002465 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002466# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002467 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002468#endif
2469
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 /* expand it if forced or not an absolute path */
2471 if (force || !mch_isFullName(fname))
2472 {
2473 /*
2474 * If the file name has a path, change to that directory for a moment,
2475 * and then do the getwd() (and get back to where we were).
2476 * This will get the correct path name with "../" things.
2477 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002478#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479 only_drive = 0;
2480 if (((p = vim_strrchr(fname, '/')) != NULL)
2481 || ((p = vim_strrchr(fname, '\\')) != NULL)
2482 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002483#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002484 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002485#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002486 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002487#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488 /*
2489 * Use fchdir() if possible, it's said to be faster and more
2490 * reliable. But on SunOS 4 it might not work. Check this by
2491 * doing a fchdir() right now.
2492 */
2493 if (!dont_fchdir)
2494 {
2495 fd = open(".", O_RDONLY | O_EXTRA, 0);
2496 if (fd >= 0 && fchdir(fd) < 0)
2497 {
2498 close(fd);
2499 fd = -1;
2500 dont_fchdir = TRUE; /* don't try again */
2501 }
2502 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002503#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504
2505 /* Only change directory when we are sure we can return to where
2506 * we are now. After doing "su" chdir(".") might not work. */
2507 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002508#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002510#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002511 (mch_dirname(olddir, MAXPATHL) == FAIL
2512 || mch_chdir((char *)olddir) != 0))
2513 {
2514 p = NULL; /* can't get current dir: don't chdir */
2515 retval = FAIL;
2516 }
2517 else
2518 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002519#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002520 /*
2521 * compensate for case where ':' from "D:" was the only
2522 * path separator detected in the file name; the _next_
2523 * character has to be removed, and then restored later.
2524 */
2525 if (only_drive)
2526 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002527#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002528 /* The directory is copied into buf[], to be able to remove
2529 * the file name without changing it (could be a string in
2530 * read-only memory) */
2531 if (p - fname >= len)
2532 retval = FAIL;
2533 else
2534 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002535 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536 if (mch_chdir((char *)buf))
2537 retval = FAIL;
2538 else
2539 fname = p + 1;
2540 *buf = NUL;
2541 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002542#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002543 if (only_drive)
2544 {
2545 p--;
2546 if (retval != FAIL)
2547 fname--;
2548 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002549#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002550 }
2551 }
2552 if (mch_dirname(buf, len) == FAIL)
2553 {
2554 retval = FAIL;
2555 *buf = NUL;
2556 }
2557 if (p != NULL)
2558 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002559#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002560 if (fd >= 0)
2561 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002562 if (p_verbose >= 5)
2563 {
2564 verbose_enter();
2565 MSG("fchdir() to previous dir");
2566 verbose_leave();
2567 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002568 l = fchdir(fd);
2569 close(fd);
2570 }
2571 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002572#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002573 l = mch_chdir((char *)olddir);
2574 if (l != 0)
2575 EMSG(_(e_prev_dir));
2576 }
2577
2578 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002579 if (l >= len - 1)
2580 retval = FAIL; /* no space for trailing "/" */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002581#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002582 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002583 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002584 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002585#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002587
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002589 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002590 return FAIL;
2591
2592 /* Do not append ".", "/dir/." is equal to "/dir". */
2593 if (STRCMP(fname, ".") != 0)
2594 STRCAT(buf, fname);
2595
2596 return OK;
2597}
2598
2599/*
2600 * Return TRUE if "fname" does not depend on the current directory.
2601 */
2602 int
2603mch_isFullName(fname)
2604 char_u *fname;
2605{
2606#ifdef __EMX__
2607 return _fnisabs(fname);
2608#else
2609# ifdef VMS
2610 return ( fname[0] == '/' || fname[0] == '.' ||
2611 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2612 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2613 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2614# else
2615 return (*fname == '/' || *fname == '~');
2616# endif
2617#endif
2618}
2619
Bram Moolenaar24552be2005-12-10 20:17:30 +00002620#if defined(USE_FNAME_CASE) || defined(PROTO)
2621/*
2622 * Set the case of the file name, if it already exists. This will cause the
2623 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002624 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002625 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002626 void
2627fname_case(name, len)
2628 char_u *name;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002629 int len UNUSED; /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002630{
2631 struct stat st;
2632 char_u *slash, *tail;
2633 DIR *dirp;
2634 struct dirent *dp;
2635
2636 if (lstat((char *)name, &st) >= 0)
2637 {
2638 /* Open the directory where the file is located. */
2639 slash = vim_strrchr(name, '/');
2640 if (slash == NULL)
2641 {
2642 dirp = opendir(".");
2643 tail = name;
2644 }
2645 else
2646 {
2647 *slash = NUL;
2648 dirp = opendir((char *)name);
2649 *slash = '/';
2650 tail = slash + 1;
2651 }
2652
2653 if (dirp != NULL)
2654 {
2655 while ((dp = readdir(dirp)) != NULL)
2656 {
2657 /* Only accept names that differ in case and are the same byte
2658 * length. TODO: accept different length name. */
2659 if (STRICMP(tail, dp->d_name) == 0
2660 && STRLEN(tail) == STRLEN(dp->d_name))
2661 {
2662 char_u newname[MAXPATHL + 1];
2663 struct stat st2;
2664
2665 /* Verify the inode is equal. */
2666 vim_strncpy(newname, name, MAXPATHL);
2667 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2668 MAXPATHL - (tail - name));
2669 if (lstat((char *)newname, &st2) >= 0
2670 && st.st_ino == st2.st_ino
2671 && st.st_dev == st2.st_dev)
2672 {
2673 STRCPY(tail, dp->d_name);
2674 break;
2675 }
2676 }
2677 }
2678
2679 closedir(dirp);
2680 }
2681 }
2682}
2683#endif
2684
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685/*
2686 * Get file permissions for 'name'.
2687 * Returns -1 when it doesn't exist.
2688 */
2689 long
2690mch_getperm(name)
2691 char_u *name;
2692{
2693 struct stat statb;
2694
2695 /* Keep the #ifdef outside of stat(), it may be a macro. */
2696#ifdef VMS
2697 if (stat((char *)vms_fixfilename(name), &statb))
2698#else
2699 if (stat((char *)name, &statb))
2700#endif
2701 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002702#ifdef __INTERIX
2703 /* The top bit makes the value negative, which means the file doesn't
2704 * exist. Remove the bit, we don't use it. */
2705 return statb.st_mode & ~S_ADDACE;
2706#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002707 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002708#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002709}
2710
2711/*
2712 * set file permission for 'name' to 'perm'
2713 *
2714 * return FAIL for failure, OK otherwise
2715 */
2716 int
2717mch_setperm(name, perm)
2718 char_u *name;
2719 long perm;
2720{
2721 return (chmod((char *)
2722#ifdef VMS
2723 vms_fixfilename(name),
2724#else
2725 name,
2726#endif
2727 (mode_t)perm) == 0 ? OK : FAIL);
2728}
2729
2730#if defined(HAVE_ACL) || defined(PROTO)
2731# ifdef HAVE_SYS_ACL_H
2732# include <sys/acl.h>
2733# endif
2734# ifdef HAVE_SYS_ACCESS_H
2735# include <sys/access.h>
2736# endif
2737
2738# ifdef HAVE_SOLARIS_ACL
2739typedef struct vim_acl_solaris_T {
2740 int acl_cnt;
2741 aclent_t *acl_entry;
2742} vim_acl_solaris_T;
2743# endif
2744
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002745#if defined(HAVE_SELINUX) || defined(PROTO)
2746/*
2747 * Copy security info from "from_file" to "to_file".
2748 */
2749 void
2750mch_copy_sec(from_file, to_file)
2751 char_u *from_file;
2752 char_u *to_file;
2753{
2754 if (from_file == NULL)
2755 return;
2756
2757 if (selinux_enabled == -1)
2758 selinux_enabled = is_selinux_enabled();
2759
2760 if (selinux_enabled > 0)
2761 {
2762 security_context_t from_context = NULL;
2763 security_context_t to_context = NULL;
2764
2765 if (getfilecon((char *)from_file, &from_context) < 0)
2766 {
2767 /* If the filesystem doesn't support extended attributes,
2768 the original had no special security context and the
2769 target cannot have one either. */
2770 if (errno == EOPNOTSUPP)
2771 return;
2772
2773 MSG_PUTS(_("\nCould not get security context for "));
2774 msg_outtrans(from_file);
2775 msg_putchar('\n');
2776 return;
2777 }
2778 if (getfilecon((char *)to_file, &to_context) < 0)
2779 {
2780 MSG_PUTS(_("\nCould not get security context for "));
2781 msg_outtrans(to_file);
2782 msg_putchar('\n');
2783 freecon (from_context);
2784 return ;
2785 }
2786 if (strcmp(from_context, to_context) != 0)
2787 {
2788 if (setfilecon((char *)to_file, from_context) < 0)
2789 {
2790 MSG_PUTS(_("\nCould not set security context for "));
2791 msg_outtrans(to_file);
2792 msg_putchar('\n');
2793 }
2794 }
2795 freecon(to_context);
2796 freecon(from_context);
2797 }
2798}
2799#endif /* HAVE_SELINUX */
2800
Bram Moolenaar071d4272004-06-13 20:20:40 +00002801/*
2802 * Return a pointer to the ACL of file "fname" in allocated memory.
2803 * Return NULL if the ACL is not available for whatever reason.
2804 */
2805 vim_acl_T
2806mch_get_acl(fname)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002807 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808{
2809 vim_acl_T ret = NULL;
2810#ifdef HAVE_POSIX_ACL
2811 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2812#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002813#ifdef HAVE_SOLARIS_ZFS_ACL
2814 acl_t *aclent;
2815
2816 if (acl_get((char *)fname, 0, &aclent) < 0)
2817 return NULL;
2818 ret = (vim_acl_T)aclent;
2819#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002820#ifdef HAVE_SOLARIS_ACL
2821 vim_acl_solaris_T *aclent;
2822
2823 aclent = malloc(sizeof(vim_acl_solaris_T));
2824 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2825 {
2826 free(aclent);
2827 return NULL;
2828 }
2829 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2830 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2831 {
2832 free(aclent->acl_entry);
2833 free(aclent);
2834 return NULL;
2835 }
2836 ret = (vim_acl_T)aclent;
2837#else
2838#if defined(HAVE_AIX_ACL)
2839 int aclsize;
2840 struct acl *aclent;
2841
2842 aclsize = sizeof(struct acl);
2843 aclent = malloc(aclsize);
2844 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2845 {
2846 if (errno == ENOSPC)
2847 {
2848 aclsize = aclent->acl_len;
2849 aclent = realloc(aclent, aclsize);
2850 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2851 {
2852 free(aclent);
2853 return NULL;
2854 }
2855 }
2856 else
2857 {
2858 free(aclent);
2859 return NULL;
2860 }
2861 }
2862 ret = (vim_acl_T)aclent;
2863#endif /* HAVE_AIX_ACL */
2864#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002865#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002866#endif /* HAVE_POSIX_ACL */
2867 return ret;
2868}
2869
2870/*
2871 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2872 */
2873 void
2874mch_set_acl(fname, aclent)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002875 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002876 vim_acl_T aclent;
2877{
2878 if (aclent == NULL)
2879 return;
2880#ifdef HAVE_POSIX_ACL
2881 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2882#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002883#ifdef HAVE_SOLARIS_ZFS_ACL
2884 acl_set((char *)fname, (acl_t *)aclent);
2885#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002886#ifdef HAVE_SOLARIS_ACL
2887 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2888 ((vim_acl_solaris_T *)aclent)->acl_entry);
2889#else
2890#ifdef HAVE_AIX_ACL
2891 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2892#endif /* HAVE_AIX_ACL */
2893#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002894#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895#endif /* HAVE_POSIX_ACL */
2896}
2897
2898 void
2899mch_free_acl(aclent)
2900 vim_acl_T aclent;
2901{
2902 if (aclent == NULL)
2903 return;
2904#ifdef HAVE_POSIX_ACL
2905 acl_free((acl_t)aclent);
2906#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002907#ifdef HAVE_SOLARIS_ZFS_ACL
2908 acl_free((acl_t *)aclent);
2909#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910#ifdef HAVE_SOLARIS_ACL
2911 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2912 free(aclent);
2913#else
2914#ifdef HAVE_AIX_ACL
2915 free(aclent);
2916#endif /* HAVE_AIX_ACL */
2917#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002918#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919#endif /* HAVE_POSIX_ACL */
2920}
2921#endif
2922
2923/*
2924 * Set hidden flag for "name".
2925 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002926 void
2927mch_hide(name)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002928 char_u *name UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002929{
2930 /* can't hide a file */
2931}
2932
2933/*
2934 * return TRUE if "name" is a directory
2935 * return FALSE if "name" is not a directory
2936 * return FALSE for error
2937 */
2938 int
2939mch_isdir(name)
2940 char_u *name;
2941{
2942 struct stat statb;
2943
2944 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2945 return FALSE;
2946 if (stat((char *)name, &statb))
2947 return FALSE;
2948#ifdef _POSIX_SOURCE
2949 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2950#else
2951 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2952#endif
2953}
2954
Bram Moolenaar071d4272004-06-13 20:20:40 +00002955static int executable_file __ARGS((char_u *name));
2956
2957/*
2958 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2959 */
2960 static int
2961executable_file(name)
2962 char_u *name;
2963{
2964 struct stat st;
2965
2966 if (stat((char *)name, &st))
2967 return 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01002968#ifdef VMS
2969 /* Like on Unix system file can have executable rights but not necessarily
2970 * be an executable, but on Unix is not a default for an ordianry file to
2971 * have an executable flag - on VMS it is in most cases.
2972 * Therefore, this check does not have any sense - let keep us to the
2973 * conventions instead:
2974 * *.COM and *.EXE files are the executables - the rest are not. This is
2975 * not ideal but better then it was.
2976 */
2977 int vms_executable = 0;
2978 if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
2979 {
2980 if (strstr(vms_tolower((char*)name),".exe") != NULL
2981 || strstr(vms_tolower((char*)name),".com")!= NULL)
2982 vms_executable = 1;
2983 }
2984 return vms_executable;
2985#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002986 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01002987#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002988}
2989
2990/*
2991 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2992 * Return -1 if unknown.
2993 */
2994 int
Bram Moolenaarc7f02552014-04-01 21:00:59 +02002995mch_can_exe(name, path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002996 char_u *name;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02002997 char_u **path;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002998{
2999 char_u *buf;
3000 char_u *p, *e;
3001 int retval;
3002
3003 /* If it's an absolute or relative path don't need to use $PATH. */
3004 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
3005 || (name[1] == '.' && name[2] == '/'))))
Bram Moolenaar206f0112014-03-12 16:51:55 +01003006 {
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003007 if (executable_file(name))
3008 {
3009 if (path != NULL)
3010 {
3011 if (name[0] == '.')
3012 *path = FullName_save(name, TRUE);
3013 else
3014 *path = vim_strsave(name);
3015 }
3016 return TRUE;
3017 }
3018 return FALSE;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003019 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003020
3021 p = (char_u *)getenv("PATH");
3022 if (p == NULL || *p == NUL)
3023 return -1;
3024 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
3025 if (buf == NULL)
3026 return -1;
3027
3028 /*
3029 * Walk through all entries in $PATH to check if "name" exists there and
3030 * is an executable file.
3031 */
3032 for (;;)
3033 {
3034 e = (char_u *)strchr((char *)p, ':');
3035 if (e == NULL)
3036 e = p + STRLEN(p);
3037 if (e - p <= 1) /* empty entry means current dir */
3038 STRCPY(buf, "./");
3039 else
3040 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003041 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003042 add_pathsep(buf);
3043 }
3044 STRCAT(buf, name);
3045 retval = executable_file(buf);
3046 if (retval == 1)
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003047 {
3048 if (path != NULL)
3049 {
3050 if (buf[0] == '.')
3051 *path = FullName_save(buf, TRUE);
3052 else
3053 *path = vim_strsave(buf);
3054 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003055 break;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003056 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057
3058 if (*e != ':')
3059 break;
3060 p = e + 1;
3061 }
3062
3063 vim_free(buf);
3064 return retval;
3065}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066
3067/*
3068 * Check what "name" is:
3069 * NODE_NORMAL: file or directory (or doesn't exist)
3070 * NODE_WRITABLE: writable device, socket, fifo, etc.
3071 * NODE_OTHER: non-writable things
3072 */
3073 int
3074mch_nodetype(name)
3075 char_u *name;
3076{
3077 struct stat st;
3078
3079 if (stat((char *)name, &st))
3080 return NODE_NORMAL;
3081 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3082 return NODE_NORMAL;
3083#ifndef OS2
3084 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
3085 return NODE_OTHER;
3086#endif
3087 /* Everything else is writable? */
3088 return NODE_WRITABLE;
3089}
3090
3091 void
3092mch_early_init()
3093{
3094#ifdef HAVE_CHECK_STACK_GROWTH
3095 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003096
Bram Moolenaar071d4272004-06-13 20:20:40 +00003097 check_stack_growth((char *)&i);
3098
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003099# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100 get_stack_limit();
3101# endif
3102
3103#endif
3104
3105 /*
3106 * Setup an alternative stack for signals. Helps to catch signals when
3107 * running out of stack space.
3108 * Use of sigaltstack() is preferred, it's more portable.
3109 * Ignore any errors.
3110 */
3111#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00003112 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003113 init_signal_stack();
3114#endif
3115}
3116
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003117#if defined(EXITFREE) || defined(PROTO)
3118 void
3119mch_free_mem()
3120{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003121# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3122 if (clip_star.owned)
3123 clip_lose_selection(&clip_star);
3124 if (clip_plus.owned)
3125 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003126# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003127# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003128 if (xterm_Shell != (Widget)0)
3129 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003130# ifndef LESSTIF_VERSION
3131 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003132 if (xterm_dpy != NULL)
3133 XtCloseDisplay(xterm_dpy);
3134 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003135 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003136 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003137# ifdef FEAT_X11
3138 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
3139# endif
3140 }
3141# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003142# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003143# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003144 if (x11_display != NULL
3145# ifdef FEAT_XCLIPBOARD
3146 && x11_display != xterm_dpy
3147# endif
3148 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003149 XCloseDisplay(x11_display);
3150# endif
3151# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
3152 vim_free(signal_stack);
3153 signal_stack = NULL;
3154# endif
3155# ifdef FEAT_TITLE
3156 vim_free(oldtitle);
3157 vim_free(oldicon);
3158# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003159}
3160#endif
3161
Bram Moolenaar071d4272004-06-13 20:20:40 +00003162static void exit_scroll __ARGS((void));
3163
3164/*
3165 * Output a newline when exiting.
3166 * Make sure the newline goes to the same stream as the text.
3167 */
3168 static void
3169exit_scroll()
3170{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003171 if (silent_mode)
3172 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003173 if (newline_on_exit || msg_didout)
3174 {
3175 if (msg_use_printf())
3176 {
3177 if (info_message)
3178 mch_msg("\n");
3179 else
3180 mch_errmsg("\r\n");
3181 }
3182 else
3183 out_char('\n');
3184 }
3185 else
3186 {
3187 restore_cterm_colors(); /* get original colors back */
3188 msg_clr_eos_force(); /* clear the rest of the display */
3189 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3190 }
3191}
3192
3193 void
3194mch_exit(r)
3195 int r;
3196{
3197 exiting = TRUE;
3198
3199#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3200 x11_export_final_selection();
3201#endif
3202
3203#ifdef FEAT_GUI
3204 if (!gui.in_use)
3205#endif
3206 {
3207 settmode(TMODE_COOK);
3208#ifdef FEAT_TITLE
3209 mch_restore_title(3); /* restore xterm title and icon name */
3210#endif
3211 /*
3212 * When t_ti is not empty but it doesn't cause swapping terminal
3213 * pages, need to output a newline when msg_didout is set. But when
3214 * t_ti does swap pages it should not go to the shell page. Do this
3215 * before stoptermcap().
3216 */
3217 if (swapping_screen() && !newline_on_exit)
3218 exit_scroll();
3219
3220 /* Stop termcap: May need to check for T_CRV response, which
3221 * requires RAW mode. */
3222 stoptermcap();
3223
3224 /*
3225 * A newline is only required after a message in the alternate screen.
3226 * This is set to TRUE by wait_return().
3227 */
3228 if (!swapping_screen() || newline_on_exit)
3229 exit_scroll();
3230
3231 /* Cursor may have been switched off without calling starttermcap()
3232 * when doing "vim -u vimrc" and vimrc contains ":q". */
3233 if (full_screen)
3234 cursor_on();
3235 }
3236 out_flush();
3237 ml_close_all(TRUE); /* remove all memfiles */
3238 may_core_dump();
3239#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003240 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003241 gui_exit(r);
3242#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003243
Bram Moolenaar56718732006-03-15 22:53:57 +00003244#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003245 mac_conv_cleanup();
3246#endif
3247
Bram Moolenaar071d4272004-06-13 20:20:40 +00003248#ifdef __QNX__
3249 /* A core dump won't be created if the signal handler
3250 * doesn't return, so we can't call exit() */
3251 if (deadly_signal != 0)
3252 return;
3253#endif
3254
Bram Moolenaar009b2592004-10-24 19:18:58 +00003255#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003256 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003257#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003258
3259#ifdef EXITFREE
3260 free_all_mem();
3261#endif
3262
Bram Moolenaar071d4272004-06-13 20:20:40 +00003263 exit(r);
3264}
3265
3266 static void
3267may_core_dump()
3268{
3269 if (deadly_signal != 0)
3270 {
3271 signal(deadly_signal, SIG_DFL);
3272 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3273 }
3274}
3275
3276#ifndef VMS
3277
3278 void
3279mch_settmode(tmode)
3280 int tmode;
3281{
3282 static int first = TRUE;
3283
3284 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3285#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3286 /*
3287 * for "new" tty systems
3288 */
3289# ifdef HAVE_TERMIOS_H
3290 static struct termios told;
3291 struct termios tnew;
3292# else
3293 static struct termio told;
3294 struct termio tnew;
3295# endif
3296
3297 if (first)
3298 {
3299 first = FALSE;
3300# if defined(HAVE_TERMIOS_H)
3301 tcgetattr(read_cmd_fd, &told);
3302# else
3303 ioctl(read_cmd_fd, TCGETA, &told);
3304# endif
3305 }
3306
3307 tnew = told;
3308 if (tmode == TMODE_RAW)
3309 {
3310 /*
3311 * ~ICRNL enables typing ^V^M
3312 */
3313 tnew.c_iflag &= ~ICRNL;
3314 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3315# if defined(IEXTEN) && !defined(__MINT__)
3316 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3317 /* but it breaks function keys on MINT */
3318# endif
3319 );
3320# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3321 tnew.c_oflag &= ~ONLCR;
3322# endif
3323 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3324 tnew.c_cc[VTIME] = 0; /* don't wait */
3325 }
3326 else if (tmode == TMODE_SLEEP)
3327 tnew.c_lflag &= ~(ECHO);
3328
3329# if defined(HAVE_TERMIOS_H)
3330 {
3331 int n = 10;
3332
3333 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3334 * few times. */
3335 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3336 && errno == EINTR && n > 0)
3337 --n;
3338 }
3339# else
3340 ioctl(read_cmd_fd, TCSETA, &tnew);
3341# endif
3342
3343#else
3344
3345 /*
3346 * for "old" tty systems
3347 */
3348# ifndef TIOCSETN
3349# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3350# endif
3351 static struct sgttyb ttybold;
3352 struct sgttyb ttybnew;
3353
3354 if (first)
3355 {
3356 first = FALSE;
3357 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3358 }
3359
3360 ttybnew = ttybold;
3361 if (tmode == TMODE_RAW)
3362 {
3363 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3364 ttybnew.sg_flags |= RAW;
3365 }
3366 else if (tmode == TMODE_SLEEP)
3367 ttybnew.sg_flags &= ~(ECHO);
3368 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3369#endif
3370 curr_tmode = tmode;
3371}
3372
3373/*
3374 * Try to get the code for "t_kb" from the stty setting
3375 *
3376 * Even if termcap claims a backspace key, the user's setting *should*
3377 * prevail. stty knows more about reality than termcap does, and if
3378 * somebody's usual erase key is DEL (which, for most BSD users, it will
3379 * be), they're going to get really annoyed if their erase key starts
3380 * doing forward deletes for no reason. (Eric Fischer)
3381 */
3382 void
3383get_stty()
3384{
3385 char_u buf[2];
3386 char_u *p;
3387
3388 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3389#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3390 /* for "new" tty systems */
3391# ifdef HAVE_TERMIOS_H
3392 struct termios keys;
3393# else
3394 struct termio keys;
3395# endif
3396
3397# if defined(HAVE_TERMIOS_H)
3398 if (tcgetattr(read_cmd_fd, &keys) != -1)
3399# else
3400 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3401# endif
3402 {
3403 buf[0] = keys.c_cc[VERASE];
3404 intr_char = keys.c_cc[VINTR];
3405#else
3406 /* for "old" tty systems */
3407 struct sgttyb keys;
3408
3409 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3410 {
3411 buf[0] = keys.sg_erase;
3412 intr_char = keys.sg_kill;
3413#endif
3414 buf[1] = NUL;
3415 add_termcode((char_u *)"kb", buf, FALSE);
3416
3417 /*
3418 * If <BS> and <DEL> are now the same, redefine <DEL>.
3419 */
3420 p = find_termcode((char_u *)"kD");
3421 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3422 do_fixdel(NULL);
3423 }
3424#if 0
3425 } /* to keep cindent happy */
3426#endif
3427}
3428
3429#endif /* VMS */
3430
3431#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3432/*
3433 * Set mouse clicks on or off.
3434 */
3435 void
3436mch_setmouse(on)
3437 int on;
3438{
3439 static int ison = FALSE;
3440 int xterm_mouse_vers;
3441
3442 if (on == ison) /* return quickly if nothing to do */
3443 return;
3444
3445 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003446
3447# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003448 if (ttym_flags == TTYM_URXVT)
3449 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003450 out_str_nf((char_u *)
3451 (on
3452 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3453 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
3454 ison = on;
3455 }
3456# endif
3457
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003458# ifdef FEAT_MOUSE_SGR
3459 if (ttym_flags == TTYM_SGR)
3460 {
3461 out_str_nf((char_u *)
3462 (on
3463 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3464 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
3465 ison = on;
3466 }
3467# endif
3468
Bram Moolenaar071d4272004-06-13 20:20:40 +00003469 if (xterm_mouse_vers > 0)
3470 {
3471 if (on) /* enable mouse events, use mouse tracking if available */
3472 out_str_nf((char_u *)
3473 (xterm_mouse_vers > 1
3474 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3475 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3476 else /* disable mouse events, could probably always send the same */
3477 out_str_nf((char_u *)
3478 (xterm_mouse_vers > 1
3479 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3480 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3481 ison = on;
3482 }
3483
3484# ifdef FEAT_MOUSE_DEC
3485 else if (ttym_flags == TTYM_DEC)
3486 {
3487 if (on) /* enable mouse events */
3488 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3489 else /* disable mouse events */
3490 out_str_nf((char_u *)"\033['z");
3491 ison = on;
3492 }
3493# endif
3494
3495# ifdef FEAT_MOUSE_GPM
3496 else
3497 {
3498 if (on)
3499 {
3500 if (gpm_open())
3501 ison = TRUE;
3502 }
3503 else
3504 {
3505 gpm_close();
3506 ison = FALSE;
3507 }
3508 }
3509# endif
3510
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003511# ifdef FEAT_SYSMOUSE
3512 else
3513 {
3514 if (on)
3515 {
3516 if (sysmouse_open() == OK)
3517 ison = TRUE;
3518 }
3519 else
3520 {
3521 sysmouse_close();
3522 ison = FALSE;
3523 }
3524 }
3525# endif
3526
Bram Moolenaar071d4272004-06-13 20:20:40 +00003527# ifdef FEAT_MOUSE_JSB
3528 else
3529 {
3530 if (on)
3531 {
3532 /* D - Enable Mouse up/down messages
3533 * L - Enable Left Button Reporting
3534 * M - Enable Middle Button Reporting
3535 * R - Enable Right Button Reporting
3536 * K - Enable SHIFT and CTRL key Reporting
3537 * + - Enable Advanced messaging of mouse moves and up/down messages
3538 * Q - Quiet No Ack
3539 * # - Numeric value of mouse pointer required
3540 * 0 = Multiview 2000 cursor, used as standard
3541 * 1 = Windows Arrow
3542 * 2 = Windows I Beam
3543 * 3 = Windows Hour Glass
3544 * 4 = Windows Cross Hair
3545 * 5 = Windows UP Arrow
3546 */
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003547# ifdef JSBTERM_MOUSE_NONADVANCED
3548 /* Disables full feedback of pointer movements */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003549 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3550 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003551# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003552 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3553 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003554# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003555 ison = TRUE;
3556 }
3557 else
3558 {
3559 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3560 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3561 ison = FALSE;
3562 }
3563 }
3564# endif
3565# ifdef FEAT_MOUSE_PTERM
3566 else
3567 {
3568 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3569 if (on)
3570 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3571 else
3572 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3573 ison = on;
3574 }
3575# endif
3576}
3577
3578/*
3579 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3580 */
3581 void
3582check_mouse_termcode()
3583{
3584# ifdef FEAT_MOUSE_XTERM
3585 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003586# ifdef FEAT_MOUSE_URXVT
3587 && use_xterm_mouse() != 3
3588# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003589# ifdef FEAT_GUI
3590 && !gui.in_use
3591# endif
3592 )
3593 {
3594 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003595 ? IF_EB("\233M", CSI_STR "M")
3596 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597 if (*p_mouse != NUL)
3598 {
3599 /* force mouse off and maybe on to send possibly new mouse
3600 * activation sequence to the xterm, with(out) drag tracing. */
3601 mch_setmouse(FALSE);
3602 setmouse();
3603 }
3604 }
3605 else
3606 del_mouse_termcode(KS_MOUSE);
3607# endif
3608
3609# ifdef FEAT_MOUSE_GPM
3610 if (!use_xterm_mouse()
3611# ifdef FEAT_GUI
3612 && !gui.in_use
3613# endif
3614 )
3615 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3616# endif
3617
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003618# ifdef FEAT_SYSMOUSE
3619 if (!use_xterm_mouse()
3620# ifdef FEAT_GUI
3621 && !gui.in_use
3622# endif
3623 )
3624 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3625# endif
3626
Bram Moolenaar071d4272004-06-13 20:20:40 +00003627# ifdef FEAT_MOUSE_JSB
3628 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3629 if (!use_xterm_mouse()
3630# ifdef FEAT_GUI
3631 && !gui.in_use
3632# endif
3633 )
3634 set_mouse_termcode(KS_JSBTERM_MOUSE,
3635 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3636 else
3637 del_mouse_termcode(KS_JSBTERM_MOUSE);
3638# endif
3639
3640# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003641 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003642 * define it in the GUI or when using an xterm. */
3643 if (!use_xterm_mouse()
3644# ifdef FEAT_GUI
3645 && !gui.in_use
3646# endif
3647 )
3648 set_mouse_termcode(KS_NETTERM_MOUSE,
3649 (char_u *)IF_EB("\033}", ESC_STR "}"));
3650 else
3651 del_mouse_termcode(KS_NETTERM_MOUSE);
3652# endif
3653
3654# ifdef FEAT_MOUSE_DEC
3655 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3656 if (!use_xterm_mouse()
3657# ifdef FEAT_GUI
3658 && !gui.in_use
3659# endif
3660 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003661 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3662 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663 else
3664 del_mouse_termcode(KS_DEC_MOUSE);
3665# endif
3666# ifdef FEAT_MOUSE_PTERM
3667 /* same as the dec mouse */
3668 if (!use_xterm_mouse()
3669# ifdef FEAT_GUI
3670 && !gui.in_use
3671# endif
3672 )
3673 set_mouse_termcode(KS_PTERM_MOUSE,
3674 (char_u *) IF_EB("\033[", ESC_STR "["));
3675 else
3676 del_mouse_termcode(KS_PTERM_MOUSE);
3677# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003678# ifdef FEAT_MOUSE_URXVT
3679 /* same as the dec mouse */
3680 if (use_xterm_mouse() == 3
3681# ifdef FEAT_GUI
3682 && !gui.in_use
3683# endif
3684 )
3685 {
3686 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3687 ? IF_EB("\233", CSI_STR)
3688 : IF_EB("\033[", ESC_STR "[")));
3689
3690 if (*p_mouse != NUL)
3691 {
3692 mch_setmouse(FALSE);
3693 setmouse();
3694 }
3695 }
3696 else
3697 del_mouse_termcode(KS_URXVT_MOUSE);
3698# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003699# ifdef FEAT_MOUSE_SGR
3700 /* same as the dec mouse */
3701 if (use_xterm_mouse() == 4
3702# ifdef FEAT_GUI
3703 && !gui.in_use
3704# endif
3705 )
3706 {
3707 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3708 ? IF_EB("\233<", CSI_STR "<")
3709 : IF_EB("\033[<", ESC_STR "[<")));
3710
3711 if (*p_mouse != NUL)
3712 {
3713 mch_setmouse(FALSE);
3714 setmouse();
3715 }
3716 }
3717 else
3718 del_mouse_termcode(KS_SGR_MOUSE);
3719# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720}
3721#endif
3722
3723/*
3724 * set screen mode, always fails.
3725 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003726 int
3727mch_screenmode(arg)
Bram Moolenaar78a15312009-05-15 19:33:18 +00003728 char_u *arg UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729{
3730 EMSG(_(e_screenmode));
3731 return FAIL;
3732}
3733
3734#ifndef VMS
3735
3736/*
3737 * Try to get the current window size:
3738 * 1. with an ioctl(), most accurate method
3739 * 2. from the environment variables LINES and COLUMNS
3740 * 3. from the termcap
3741 * 4. keep using the old values
3742 * Return OK when size could be determined, FAIL otherwise.
3743 */
3744 int
3745mch_get_shellsize()
3746{
3747 long rows = 0;
3748 long columns = 0;
3749 char_u *p;
3750
3751 /*
3752 * For OS/2 use _scrsize().
3753 */
3754# ifdef __EMX__
3755 {
3756 int s[2];
3757
3758 _scrsize(s);
3759 columns = s[0];
3760 rows = s[1];
3761 }
3762# endif
3763
3764 /*
3765 * 1. try using an ioctl. It is the most accurate method.
3766 *
3767 * Try using TIOCGWINSZ first, some systems that have it also define
3768 * TIOCGSIZE but don't have a struct ttysize.
3769 */
3770# ifdef TIOCGWINSZ
3771 {
3772 struct winsize ws;
3773 int fd = 1;
3774
3775 /* When stdout is not a tty, use stdin for the ioctl(). */
3776 if (!isatty(fd) && isatty(read_cmd_fd))
3777 fd = read_cmd_fd;
3778 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3779 {
3780 columns = ws.ws_col;
3781 rows = ws.ws_row;
3782 }
3783 }
3784# else /* TIOCGWINSZ */
3785# ifdef TIOCGSIZE
3786 {
3787 struct ttysize ts;
3788 int fd = 1;
3789
3790 /* When stdout is not a tty, use stdin for the ioctl(). */
3791 if (!isatty(fd) && isatty(read_cmd_fd))
3792 fd = read_cmd_fd;
3793 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3794 {
3795 columns = ts.ts_cols;
3796 rows = ts.ts_lines;
3797 }
3798 }
3799# endif /* TIOCGSIZE */
3800# endif /* TIOCGWINSZ */
3801
3802 /*
3803 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003804 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3805 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003806 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003807 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 {
3809 if ((p = (char_u *)getenv("LINES")))
3810 rows = atoi((char *)p);
3811 if ((p = (char_u *)getenv("COLUMNS")))
3812 columns = atoi((char *)p);
3813 }
3814
3815#ifdef HAVE_TGETENT
3816 /*
3817 * 3. try reading "co" and "li" entries from termcap
3818 */
3819 if (columns == 0 || rows == 0)
3820 getlinecol(&columns, &rows);
3821#endif
3822
3823 /*
3824 * 4. If everything fails, use the old values
3825 */
3826 if (columns <= 0 || rows <= 0)
3827 return FAIL;
3828
3829 Rows = rows;
3830 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02003831 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832 return OK;
3833}
3834
3835/*
3836 * Try to set the window size to Rows and Columns.
3837 */
3838 void
3839mch_set_shellsize()
3840{
3841 if (*T_CWS)
3842 {
3843 /*
3844 * NOTE: if you get an error here that term_set_winsize() is
3845 * undefined, check the output of configure. It could probably not
3846 * find a ncurses, termcap or termlib library.
3847 */
3848 term_set_winsize((int)Rows, (int)Columns);
3849 out_flush();
3850 screen_start(); /* don't know where cursor is now */
3851 }
3852}
3853
3854#endif /* VMS */
3855
3856/*
3857 * Rows and/or Columns has changed.
3858 */
3859 void
3860mch_new_shellsize()
3861{
3862 /* Nothing to do. */
3863}
3864
Bram Moolenaar205b8862011-09-07 15:04:31 +02003865/*
3866 * Wait for process "child" to end.
3867 * Return "child" if it exited properly, <= 0 on error.
3868 */
3869 static pid_t
3870wait4pid(child, status)
3871 pid_t child;
3872 waitstatus *status;
3873{
3874 pid_t wait_pid = 0;
3875
3876 while (wait_pid != child)
3877 {
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003878 /* When compiled with Python threads are probably used, in which case
3879 * wait() sometimes hangs for no obvious reason. Use waitpid()
3880 * instead and loop (like the GUI). Also needed for other interfaces,
3881 * they might call system(). */
3882# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02003883 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003884# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02003885 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003886# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02003887 if (wait_pid == 0)
3888 {
Bram Moolenaar75676462013-01-30 14:55:42 +01003889 /* Wait for 10 msec before trying again. */
Bram Moolenaar205b8862011-09-07 15:04:31 +02003890 mch_delay(10L, TRUE);
3891 continue;
3892 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02003893 if (wait_pid <= 0
3894# ifdef ECHILD
3895 && errno == ECHILD
3896# endif
3897 )
3898 break;
3899 }
3900 return wait_pid;
3901}
3902
Bram Moolenaar071d4272004-06-13 20:20:40 +00003903 int
3904mch_call_shell(cmd, options)
3905 char_u *cmd;
3906 int options; /* SHELL_*, see vim.h */
3907{
3908#ifdef VMS
3909 char *ifn = NULL;
3910 char *ofn = NULL;
3911#endif
3912 int tmode = cur_tmode;
3913#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3914 int x;
3915# ifndef __EMX__
3916 char_u *newcmd; /* only needed for unix */
3917# else
3918 /*
3919 * Set the preferred shell in the EMXSHELL environment variable (but
3920 * only if it is different from what is already in the environment).
3921 * Emx then takes care of whether to use "/c" or "-c" in an
3922 * intelligent way. Simply pass the whole thing to emx's system() call.
3923 * Emx also starts an interactive shell if system() is passed an empty
3924 * string.
3925 */
3926 char_u *p, *old;
3927
3928 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3929 {
3930 /* should check HAVE_SETENV, but I know we don't have it. */
3931 p = alloc(10 + strlen(p_sh));
3932 if (p)
3933 {
3934 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3935 putenv((char *)p); /* don't free the pointer! */
3936 }
3937 }
3938# endif
3939
3940 out_flush();
3941
3942 if (options & SHELL_COOKED)
3943 settmode(TMODE_COOK); /* set to normal mode */
3944
Bram Moolenaar62b42182010-09-21 22:09:37 +02003945# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01003946 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02003947 loose_clipboard();
3948# endif
3949
Bram Moolenaar071d4272004-06-13 20:20:40 +00003950# ifdef __EMX__
3951 if (cmd == NULL)
3952 x = system(""); /* this starts an interactive shell in emx */
3953 else
3954 x = system((char *)cmd);
3955 /* system() returns -1 when error occurs in starting shell */
3956 if (x == -1 && !emsg_silent)
3957 {
3958 MSG_PUTS(_("\nCannot execute shell "));
3959 msg_outtrans(p_sh);
3960 msg_putchar('\n');
3961 }
3962# else /* not __EMX__ */
3963 if (cmd == NULL)
3964 x = system((char *)p_sh);
3965 else
3966 {
3967# ifdef VMS
3968 if (ofn = strchr((char *)cmd, '>'))
3969 *ofn++ = '\0';
3970 if (ifn = strchr((char *)cmd, '<'))
3971 {
3972 char *p;
3973
3974 *ifn++ = '\0';
3975 p = strchr(ifn,' '); /* chop off any trailing spaces */
3976 if (p)
3977 *p = '\0';
3978 }
3979 if (ofn)
3980 x = vms_sys((char *)cmd, ofn, ifn);
3981 else
3982 x = system((char *)cmd);
3983# else
3984 newcmd = lalloc(STRLEN(p_sh)
3985 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3986 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3987 if (newcmd == NULL)
3988 x = 0;
3989 else
3990 {
3991 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3992 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3993 (char *)p_shcf,
3994 (char *)cmd);
3995 x = system((char *)newcmd);
3996 vim_free(newcmd);
3997 }
3998# endif
3999 }
4000# ifdef VMS
4001 x = vms_sys_status(x);
4002# endif
4003 if (emsg_silent)
4004 ;
4005 else if (x == 127)
4006 MSG_PUTS(_("\nCannot execute shell sh\n"));
4007# endif /* __EMX__ */
4008 else if (x && !(options & SHELL_SILENT))
4009 {
4010 MSG_PUTS(_("\nshell returned "));
4011 msg_outnum((long)x);
4012 msg_putchar('\n');
4013 }
4014
4015 if (tmode == TMODE_RAW)
4016 settmode(TMODE_RAW); /* set to raw mode */
4017# ifdef FEAT_TITLE
4018 resettitle();
4019# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004020# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4021 restore_clipboard();
4022# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023 return x;
4024
4025#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
4026
Bram Moolenaardf177f62005-02-22 08:39:57 +00004027# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
4028 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004029
4030 char_u *newcmd = NULL;
4031 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004032 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004033 pid_t wait_pid = 0;
4034# ifdef HAVE_UNION_WAIT
4035 union wait status;
4036# else
4037 int status = -1;
4038# endif
4039 int retval = -1;
4040 char **argv = NULL;
4041 int argc;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004042 char_u *p_shcf_copy = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004043 int i;
4044 char_u *p;
4045 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004046 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004047# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004048 int pty_slave_fd = -1;
4049 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004050# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004051 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004052 int fd_fromshell[2];
4053 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004054# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004055 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004056# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004057 static char envbuf_Rows[20];
4058 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004059# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004060 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004061
Bram Moolenaar62b42182010-09-21 22:09:37 +02004062 newcmd = vim_strsave(p_sh);
4063 if (newcmd == NULL) /* out of memory */
4064 goto error;
4065
Bram Moolenaar071d4272004-06-13 20:20:40 +00004066 out_flush();
4067 if (options & SHELL_COOKED)
4068 settmode(TMODE_COOK); /* set to normal mode */
4069
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004070 /*
4071 * Do this loop twice:
4072 * 1: find number of arguments
4073 * 2: separate them and build argv[]
4074 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004075 for (i = 0; i < 2; ++i)
4076 {
4077 p = newcmd;
4078 inquote = FALSE;
4079 argc = 0;
4080 for (;;)
4081 {
4082 if (i == 1)
4083 argv[argc] = (char *)p;
4084 ++argc;
4085 while (*p && (inquote || (*p != ' ' && *p != TAB)))
4086 {
4087 if (*p == '"')
4088 inquote = !inquote;
4089 ++p;
4090 }
4091 if (*p == NUL)
4092 break;
4093 if (i == 1)
4094 *p++ = NUL;
4095 p = skipwhite(p);
4096 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00004097 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098 {
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004099 /*
4100 * Account for possible multiple args in p_shcf.
4101 */
4102 p = p_shcf;
4103 for (;;)
4104 {
4105 p = skiptowhite(p);
4106 if (*p == NUL)
4107 break;
4108 ++argc;
4109 p = skipwhite(p);
4110 }
4111
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
4113 if (argv == NULL) /* out of memory */
4114 goto error;
4115 }
4116 }
4117 if (cmd != NULL)
4118 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004119 char_u *s;
4120
Bram Moolenaar071d4272004-06-13 20:20:40 +00004121 if (extra_shell_arg != NULL)
4122 argv[argc++] = (char *)extra_shell_arg;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004123
4124 /* Break 'shellcmdflag' into white separated parts. This doesn't
4125 * handle quoted strings, they are very unlikely to appear. */
4126 p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
4127 if (p_shcf_copy == NULL) /* out of memory */
4128 goto error;
4129 s = p_shcf_copy;
4130 p = p_shcf;
4131 while (*p != NUL)
4132 {
4133 argv[argc++] = (char *)s;
4134 while (*p && *p != ' ' && *p != TAB)
4135 *s++ = *p++;
4136 *s++ = NUL;
4137 p = skipwhite(p);
4138 }
4139
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140 argv[argc++] = (char *)cmd;
4141 }
4142 argv[argc] = NULL;
4143
Bram Moolenaar071d4272004-06-13 20:20:40 +00004144 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004145 * For the GUI, when writing the output into the buffer and when reading
4146 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4147 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004148 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004149 if ((options & (SHELL_READ|SHELL_WRITE))
4150# ifdef FEAT_GUI
4151 || (gui.in_use && show_shell_mess)
4152# endif
4153 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004155# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004156 /*
4157 * Try to open a master pty.
4158 * If this works, open the slave pty.
4159 * If the slave can't be opened, close the master pty.
4160 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004161 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162 {
4163 pty_master_fd = OpenPTY(&tty_name); /* open pty */
Bram Moolenaare70172e2011-08-04 19:36:52 +02004164 if (pty_master_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004165 {
Bram Moolenaare70172e2011-08-04 19:36:52 +02004166 /* Leaving out O_NOCTTY may lead to waitpid() always returning
4167 * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4168 * adding O_NOCTTY always works when defined. */
4169#ifdef O_NOCTTY
4170 pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4171#else
4172 pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4173#endif
4174 if (pty_slave_fd < 0)
4175 {
4176 close(pty_master_fd);
4177 pty_master_fd = -1;
4178 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179 }
4180 }
4181 /*
4182 * If not opening a pty or it didn't work, try using pipes.
4183 */
4184 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004185# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004186 {
4187 pipe_error = (pipe(fd_toshell) < 0);
4188 if (!pipe_error) /* pipe create OK */
4189 {
4190 pipe_error = (pipe(fd_fromshell) < 0);
4191 if (pipe_error) /* pipe create failed */
4192 {
4193 close(fd_toshell[0]);
4194 close(fd_toshell[1]);
4195 }
4196 }
4197 if (pipe_error)
4198 {
4199 MSG_PUTS(_("\nCannot create pipes\n"));
4200 out_flush();
4201 }
4202 }
4203 }
4204
4205 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004206 {
4207# ifdef __BEOS__
4208 beos_cleanup_read_thread();
4209# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004210
Bram Moolenaar071d4272004-06-13 20:20:40 +00004211 if ((pid = fork()) == -1) /* maybe we should use vfork() */
4212 {
4213 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004214 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004215# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004216 || (gui.in_use && show_shell_mess)
4217# endif
4218 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004220# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004221 if (pty_master_fd >= 0) /* close the pseudo tty */
4222 {
4223 close(pty_master_fd);
4224 close(pty_slave_fd);
4225 }
4226 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004227# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228 {
4229 close(fd_toshell[0]);
4230 close(fd_toshell[1]);
4231 close(fd_fromshell[0]);
4232 close(fd_fromshell[1]);
4233 }
4234 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235 }
4236 else if (pid == 0) /* child */
4237 {
4238 reset_signals(); /* handle signals normally */
4239
4240 if (!show_shell_mess || (options & SHELL_EXPAND))
4241 {
4242 int fd;
4243
4244 /*
4245 * Don't want to show any message from the shell. Can't just
4246 * close stdout and stderr though, because some systems will
4247 * break if you try to write to them after that, so we must
4248 * use dup() to replace them with something else -- webb
4249 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4250 * waiting for input.
4251 */
4252 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4253 fclose(stdin);
4254 fclose(stdout);
4255 fclose(stderr);
4256
4257 /*
4258 * If any of these open()'s and dup()'s fail, we just continue
4259 * anyway. It's not fatal, and on most systems it will make
4260 * no difference at all. On a few it will cause the execvp()
4261 * to exit with a non-zero status even when the completion
4262 * could be done, which is nothing too serious. If the open()
4263 * or dup() failed we'd just do the same thing ourselves
4264 * anyway -- webb
4265 */
4266 if (fd >= 0)
4267 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004268 ignored = dup(fd); /* To replace stdin (fd 0) */
4269 ignored = dup(fd); /* To replace stdout (fd 1) */
4270 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271
4272 /* Don't need this now that we've duplicated it */
4273 close(fd);
4274 }
4275 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004276 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004277# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004278 || gui.in_use
4279# endif
4280 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004281 {
4282
Bram Moolenaardf177f62005-02-22 08:39:57 +00004283# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004284 /* Create our own process group, so that the child and all its
4285 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004286 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004287 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004288 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004289 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004290# if defined(SIGHUP)
4291 /* When doing "!xterm&" and 'shell' is bash: the shell
4292 * will exit and send SIGHUP to all processes in its
4293 * group, killing the just started process. Ignore SIGHUP
4294 * to avoid that. (suggested by Simon Schubert)
4295 */
4296 signal(SIGHUP, SIG_IGN);
4297# endif
4298 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004299# endif
4300# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004301 if (pty_slave_fd >= 0)
4302 {
4303 /* push stream discipline modules */
4304 if (options & SHELL_COOKED)
4305 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004306# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004307 /* Try to become controlling tty (probably doesn't work,
4308 * unless run by root) */
4309 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004310# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004311 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004312# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004313 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004314# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004315 setenv("TERM", "dumb", 1);
4316 sprintf((char *)envbuf, "%ld", Rows);
4317 setenv("ROWS", (char *)envbuf, 1);
4318 sprintf((char *)envbuf, "%ld", Rows);
4319 setenv("LINES", (char *)envbuf, 1);
4320 sprintf((char *)envbuf, "%ld", Columns);
4321 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004322# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323 /*
4324 * Putenv does not copy the string, it has to remain valid.
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004325 * Use a static array to avoid losing allocated memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004326 */
4327 putenv("TERM=dumb");
4328 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
4329 putenv(envbuf_Rows);
4330 sprintf(envbuf_Rows, "LINES=%ld", Rows);
4331 putenv(envbuf_Rows);
4332 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
4333 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004334# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335
Bram Moolenaara5792f52005-11-23 21:25:05 +00004336 /*
4337 * stderr is only redirected when using the GUI, so that a
4338 * program like gpg can still access the terminal to get a
4339 * passphrase using stderr.
4340 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004341# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342 if (pty_master_fd >= 0)
4343 {
4344 close(pty_master_fd); /* close master side of pty */
4345
4346 /* set up stdin/stdout/stderr for the child */
4347 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004348 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004350 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004351 if (gui.in_use)
4352 {
4353 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004354 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004355 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004356
4357 close(pty_slave_fd); /* has been dupped, close it now */
4358 }
4359 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004360# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004361 {
4362 /* set up stdin for the child */
4363 close(fd_toshell[1]);
4364 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004365 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004366 close(fd_toshell[0]);
4367
4368 /* set up stdout for the child */
4369 close(fd_fromshell[0]);
4370 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004371 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004372 close(fd_fromshell[1]);
4373
Bram Moolenaara5792f52005-11-23 21:25:05 +00004374# ifdef FEAT_GUI
4375 if (gui.in_use)
4376 {
4377 /* set up stderr for the child */
4378 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004379 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004380 }
4381# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382 }
4383 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004384
Bram Moolenaar071d4272004-06-13 20:20:40 +00004385 /*
4386 * There is no type cast for the argv, because the type may be
4387 * different on different machines. This may cause a warning
4388 * message with strict compilers, don't worry about it.
4389 * Call _exit() instead of exit() to avoid closing the connection
4390 * to the X server (esp. with GTK, which uses atexit()).
4391 */
4392 execvp(argv[0], argv);
4393 _exit(EXEC_FAILED); /* exec failed, return failure code */
4394 }
4395 else /* parent */
4396 {
4397 /*
4398 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004399 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004400 */
4401 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004402 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004403
4404 /*
4405 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004406 * This is also used to pipe stdin/stdout to/from the external
4407 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004408 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004409 if ((options & (SHELL_READ|SHELL_WRITE))
4410# ifdef FEAT_GUI
4411 || (gui.in_use && show_shell_mess)
4412# endif
4413 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004415# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004416 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004417# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004418 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004419# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004420 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4421 int ta_len = 0; /* valid bytes in ta_buf[] */
4422 int len;
4423 int p_more_save;
4424 int old_State;
4425 int c;
4426 int toshell_fd;
4427 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004428 garray_T ga;
4429 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004430# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4431 struct timeval start_tv;
4432# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433
Bram Moolenaardf177f62005-02-22 08:39:57 +00004434# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004435 if (pty_master_fd >= 0)
4436 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004437 fromshell_fd = pty_master_fd;
4438 toshell_fd = dup(pty_master_fd);
4439 }
4440 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004441# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004442 {
4443 close(fd_toshell[0]);
4444 close(fd_fromshell[1]);
4445 toshell_fd = fd_toshell[1];
4446 fromshell_fd = fd_fromshell[0];
4447 }
4448
4449 /*
4450 * Write to the child if there are typed characters.
4451 * Read from the child if there are characters available.
4452 * Repeat the reading a few times if more characters are
4453 * available. Need to check for typed keys now and then, but
4454 * not too often (delays when no chars are available).
4455 * This loop is quit if no characters can be read from the pty
4456 * (WaitForChar detected special condition), or there are no
4457 * characters available and the child has exited.
4458 * Only check if the child has exited when there is no more
4459 * output. The child may exit before all the output has
4460 * been printed.
4461 *
4462 * Currently this busy loops!
4463 * This can probably dead-lock when the write blocks!
4464 */
4465 p_more_save = p_more;
4466 p_more = FALSE;
4467 old_State = State;
4468 State = EXTERNCMD; /* don't redraw at window resize */
4469
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004470 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004471 {
4472 /* Fork a process that will write the lines to the
4473 * external program. */
4474 if ((wpid = fork()) == -1)
4475 {
4476 MSG_PUTS(_("\nCannot fork\n"));
4477 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004478 else if (wpid == 0) /* child */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004479 {
4480 linenr_T lnum = curbuf->b_op_start.lnum;
4481 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004482 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004483 size_t l;
4484
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004485 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004486 for (;;)
4487 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004488 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004489 if (l == 0)
4490 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004491 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004492 /* NL -> NUL translation */
4493 len = write(toshell_fd, "", (size_t)1);
4494 else
4495 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004496 char_u *s = vim_strchr(lp + written, NL);
4497
Bram Moolenaar89d40322006-08-29 15:30:07 +00004498 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004499 s == NULL ? l
4500 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004501 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004502 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004503 {
4504 /* Finished a line, add a NL, unless this line
4505 * should not have one. */
4506 if (lnum != curbuf->b_op_end.lnum
4507 || !curbuf->b_p_bin
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004508 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004509 && (lnum !=
4510 curbuf->b_ml.ml_line_count
4511 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004512 ignored = write(toshell_fd, "\n",
4513 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004514 ++lnum;
4515 if (lnum > curbuf->b_op_end.lnum)
4516 {
4517 /* finished all the lines, close pipe */
4518 close(toshell_fd);
4519 toshell_fd = -1;
4520 break;
4521 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004522 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004523 written = 0;
4524 }
4525 else if (len > 0)
4526 written += len;
4527 }
4528 _exit(0);
4529 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004530 else /* parent */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004531 {
4532 close(toshell_fd);
4533 toshell_fd = -1;
4534 }
4535 }
4536
4537 if (options & SHELL_READ)
4538 ga_init2(&ga, 1, BUFLEN);
4539
4540 noread_cnt = 0;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004541# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4542 gettimeofday(&start_tv, NULL);
4543# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004544 for (;;)
4545 {
4546 /*
4547 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004548 * if there are any.
4549 * Don't do this if we are expanding wild cards (would eat
4550 * typeahead).
4551 * Don't do this when filtering and terminal is in cooked
4552 * mode, the shell command will handle the I/O. Avoids
4553 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004554 * Don't get characters when the child has already
4555 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004556 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004557 * while (noread_cnt > 4), avoids that ":r !ls" eats
4558 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559 */
4560 len = 0;
4561 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004562 && ((options &
4563 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4564 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004565# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004566 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004567# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004568 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004569 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004570 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004572 if (ta_len == 0)
4573 {
4574 /* Get extra characters when we don't have any.
4575 * Reset the counter and timer. */
4576 noread_cnt = 0;
4577# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4578 gettimeofday(&start_tv, NULL);
4579# endif
4580 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4581 }
4582 if (ta_len > 0 || len > 0)
4583 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584 /*
4585 * For pipes:
4586 * Check for CTRL-C: send interrupt signal to child.
4587 * Check for CTRL-D: EOF, close pipe to child.
4588 */
4589 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4590 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004591# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592 /*
4593 * Send SIGINT to the child's group or all
4594 * processes in our group.
4595 */
4596 if (ta_buf[ta_len] == Ctrl_C
4597 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004598 {
4599# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004601# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004602 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004603# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004604 if (wpid > 0)
4605 kill(wpid, SIGINT);
4606 }
4607# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004608 if (pty_master_fd < 0 && toshell_fd >= 0
4609 && ta_buf[ta_len] == Ctrl_D)
4610 {
4611 close(toshell_fd);
4612 toshell_fd = -1;
4613 }
4614 }
4615
4616 /* replace K_BS by <BS> and K_DEL by <DEL> */
4617 for (i = ta_len; i < ta_len + len; ++i)
4618 {
4619 if (ta_buf[i] == CSI && len - i > 2)
4620 {
4621 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4622 if (c == K_DEL || c == K_KDEL || c == K_BS)
4623 {
4624 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4625 (size_t)(len - i - 2));
4626 if (c == K_DEL || c == K_KDEL)
4627 ta_buf[i] = DEL;
4628 else
4629 ta_buf[i] = Ctrl_H;
4630 len -= 2;
4631 }
4632 }
4633 else if (ta_buf[i] == '\r')
4634 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004635# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00004637 i += (*mb_ptr2len_len)(ta_buf + i,
4638 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004639# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004640 }
4641
4642 /*
4643 * For pipes: echo the typed characters.
4644 * For a pty this does not seem to work.
4645 */
4646 if (pty_master_fd < 0)
4647 {
4648 for (i = ta_len; i < ta_len + len; ++i)
4649 {
4650 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4651 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004652# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653 else if (has_mbyte)
4654 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004655 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004656
4657 msg_outtrans_len(ta_buf + i, l);
4658 i += l - 1;
4659 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004660# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661 else
4662 msg_outtrans_len(ta_buf + i, 1);
4663 }
4664 windgoto(msg_row, msg_col);
4665 out_flush();
4666 }
4667
4668 ta_len += len;
4669
4670 /*
4671 * Write the characters to the child, unless EOF has
4672 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004673 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004674 * When writing buffer lines, drop the typed
4675 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004677 if (options & SHELL_WRITE)
4678 ta_len = 0;
4679 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004680 {
4681 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4682 if (len > 0)
4683 {
4684 ta_len -= len;
4685 mch_memmove(ta_buf, ta_buf + len, ta_len);
4686 }
4687 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004688 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004689 }
4690
Bram Moolenaardf177f62005-02-22 08:39:57 +00004691 if (got_int)
4692 {
4693 /* CTRL-C sends a signal to the child, we ignore it
4694 * ourselves */
4695# ifdef HAVE_SETSID
4696 kill(-pid, SIGINT);
4697# else
4698 kill(0, SIGINT);
4699# endif
4700 if (wpid > 0)
4701 kill(wpid, SIGINT);
4702 got_int = FALSE;
4703 }
4704
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705 /*
4706 * Check if the child has any characters to be printed.
4707 * Read them and write them to our window. Repeat this as
4708 * long as there is something to do, avoid the 10ms wait
4709 * for mch_inchar(), or sending typeahead characters to
4710 * the external process.
4711 * TODO: This should handle escape sequences, compatible
4712 * to some terminal (vt52?).
4713 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004714 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004715 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4716 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004717 len = read_eintr(fromshell_fd, buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004718# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004719 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004720# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004722# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004723 );
4724 if (len <= 0) /* end of file or error */
4725 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004726
4727 noread_cnt = 0;
4728 if (options & SHELL_READ)
4729 {
4730 /* Do NUL -> NL translation, append NL separated
4731 * lines to the current buffer. */
4732 for (i = 0; i < len; ++i)
4733 {
4734 if (buffer[i] == NL)
4735 append_ga_line(&ga);
4736 else if (buffer[i] == NUL)
4737 ga_append(&ga, NL);
4738 else
4739 ga_append(&ga, buffer[i]);
4740 }
4741 }
4742# ifdef FEAT_MBYTE
4743 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004744 {
4745 int l;
4746
Bram Moolenaardf177f62005-02-22 08:39:57 +00004747 len += buffer_off;
4748 buffer[len] = NUL;
4749
Bram Moolenaar071d4272004-06-13 20:20:40 +00004750 /* Check if the last character in buffer[] is
4751 * incomplete, keep these bytes for the next
4752 * round. */
4753 for (p = buffer; p < buffer + len; p += l)
4754 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004755 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004756 if (l == 0)
4757 l = 1; /* NUL byte? */
4758 else if (MB_BYTE2LEN(*p) != l)
4759 break;
4760 }
4761 if (p == buffer) /* no complete character */
4762 {
4763 /* avoid getting stuck at an illegal byte */
4764 if (len >= 12)
4765 ++p;
4766 else
4767 {
4768 buffer_off = len;
4769 continue;
4770 }
4771 }
4772 c = *p;
4773 *p = NUL;
4774 msg_puts(buffer);
4775 if (p < buffer + len)
4776 {
4777 *p = c;
4778 buffer_off = (buffer + len) - p;
4779 mch_memmove(buffer, p, buffer_off);
4780 continue;
4781 }
4782 buffer_off = 0;
4783 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004784# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004785 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 {
4787 buffer[len] = NUL;
4788 msg_puts(buffer);
4789 }
4790
4791 windgoto(msg_row, msg_col);
4792 cursor_on();
4793 out_flush();
4794 if (got_int)
4795 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004796
4797# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4798 {
4799 struct timeval now_tv;
4800 long msec;
4801
4802 /* Avoid that we keep looping here without
4803 * checking for a CTRL-C for a long time. Don't
4804 * break out too often to avoid losing typeahead. */
4805 gettimeofday(&now_tv, NULL);
4806 msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
4807 + (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
4808 if (msec > 2000)
4809 {
4810 noread_cnt = 5;
4811 break;
4812 }
4813 }
4814# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815 }
4816
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004817 /* If we already detected the child has finished break the
4818 * loop now. */
4819 if (wait_pid == pid)
4820 break;
4821
Bram Moolenaar071d4272004-06-13 20:20:40 +00004822 /*
4823 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004824 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004825 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004826# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004827 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004828# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004829 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004830# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004831 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4832 || (wait_pid == pid && WIFEXITED(status)))
4833 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004834 /* Don't break the loop yet, try reading more
4835 * characters from "fromshell_fd" first. When using
4836 * pipes there might still be something to read and
4837 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004838 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004840 else
4841 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004842
Bram Moolenaar95a51352013-03-21 22:53:50 +01004843# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004844 /* Handle any X events, e.g. serving the clipboard. */
4845 clip_update();
4846# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004847 }
4848finished:
4849 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004850 if (options & SHELL_READ)
4851 {
4852 if (ga.ga_len > 0)
4853 {
4854 append_ga_line(&ga);
4855 /* remember that the NL was missing */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004856 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004857 }
4858 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004859 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004860 ga_clear(&ga);
4861 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862
Bram Moolenaar071d4272004-06-13 20:20:40 +00004863 /*
4864 * Give all typeahead that wasn't used back to ui_inchar().
4865 */
4866 if (ta_len)
4867 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004868 State = old_State;
4869 if (toshell_fd >= 0)
4870 close(toshell_fd);
4871 close(fromshell_fd);
4872 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01004873# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004874 else
4875 {
4876 /*
4877 * Similar to the loop above, but only handle X events, no
4878 * I/O.
4879 */
4880 for (;;)
4881 {
4882 if (got_int)
4883 {
4884 /* CTRL-C sends a signal to the child, we ignore it
4885 * ourselves */
4886# ifdef HAVE_SETSID
4887 kill(-pid, SIGINT);
4888# else
4889 kill(0, SIGINT);
4890# endif
4891 got_int = FALSE;
4892 }
4893# ifdef __NeXT__
4894 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4895# else
4896 wait_pid = waitpid(pid, &status, WNOHANG);
4897# endif
4898 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4899 || (wait_pid == pid && WIFEXITED(status)))
4900 {
4901 wait_pid = pid;
4902 break;
4903 }
4904
4905 /* Handle any X events, e.g. serving the clipboard. */
4906 clip_update();
4907
4908 mch_delay(10L, TRUE);
4909 }
4910 }
4911# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004912
4913 /*
4914 * Wait until our child has exited.
4915 * Ignore wait() returning pids of other children and returning
4916 * because of some signal like SIGWINCH.
4917 * Don't wait if wait_pid was already set above, indicating the
4918 * child already exited.
4919 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02004920 if (wait_pid != pid)
4921 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004922
Bram Moolenaar624891f2010-10-13 16:22:09 +02004923# ifdef FEAT_GUI
4924 /* Close slave side of pty. Only do this after the child has
4925 * exited, otherwise the child may hang when it tries to write on
4926 * the pty. */
4927 if (pty_master_fd >= 0)
4928 close(pty_slave_fd);
4929# endif
4930
Bram Moolenaardf177f62005-02-22 08:39:57 +00004931 /* Make sure the child that writes to the external program is
4932 * dead. */
4933 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004934 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004935 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02004936 wait4pid(wpid, NULL);
4937 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004938
Bram Moolenaar071d4272004-06-13 20:20:40 +00004939 /*
4940 * Set to raw mode right now, otherwise a CTRL-C after
4941 * catch_signals() will kill Vim.
4942 */
4943 if (tmode == TMODE_RAW)
4944 settmode(TMODE_RAW);
4945 did_settmode = TRUE;
4946 set_signals();
4947
4948 if (WIFEXITED(status))
4949 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004950 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004951 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01004952 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004953 {
4954 if (retval == EXEC_FAILED)
4955 {
4956 MSG_PUTS(_("\nCannot execute shell "));
4957 msg_outtrans(p_sh);
4958 msg_putchar('\n');
4959 }
4960 else if (!(options & SHELL_SILENT))
4961 {
4962 MSG_PUTS(_("\nshell returned "));
4963 msg_outnum((long)retval);
4964 msg_putchar('\n');
4965 }
4966 }
4967 }
4968 else
4969 MSG_PUTS(_("\nCommand terminated\n"));
4970 }
4971 }
4972 vim_free(argv);
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004973 vim_free(p_shcf_copy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004974
4975error:
4976 if (!did_settmode)
4977 if (tmode == TMODE_RAW)
4978 settmode(TMODE_RAW); /* set to raw mode */
4979# ifdef FEAT_TITLE
4980 resettitle();
4981# endif
4982 vim_free(newcmd);
4983
4984 return retval;
4985
4986#endif /* USE_SYSTEM */
4987}
4988
4989/*
4990 * Check for CTRL-C typed by reading all available characters.
4991 * In cooked mode we should get SIGINT, no need to check.
4992 */
4993 void
4994mch_breakcheck()
4995{
4996 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4997 fill_input_buf(FALSE);
4998}
4999
5000/*
5001 * Wait "msec" msec until a character is available from the keyboard or from
5002 * inbuf[]. msec == -1 will block forever.
5003 * When a GUI is being used, this will never get called -- webb
5004 */
5005 static int
5006WaitForChar(msec)
5007 long msec;
5008{
5009#ifdef FEAT_MOUSE_GPM
5010 int gpm_process_wanted;
5011#endif
5012#ifdef FEAT_XCLIPBOARD
5013 int rest;
5014#endif
5015 int avail;
5016
5017 if (input_available()) /* something in inbuf[] */
5018 return 1;
5019
5020#if defined(FEAT_MOUSE_DEC)
5021 /* May need to query the mouse position. */
5022 if (WantQueryMouse)
5023 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00005024 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005025 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
5026 }
5027#endif
5028
5029 /*
5030 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
5031 * events. This is a bit complicated, because they might both be defined.
5032 */
5033#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
5034# ifdef FEAT_XCLIPBOARD
5035 rest = 0;
5036 if (do_xterm_trace())
5037 rest = msec;
5038# endif
5039 do
5040 {
5041# ifdef FEAT_XCLIPBOARD
5042 if (rest != 0)
5043 {
5044 msec = XT_TRACE_DELAY;
5045 if (rest >= 0 && rest < XT_TRACE_DELAY)
5046 msec = rest;
5047 if (rest >= 0)
5048 rest -= msec;
5049 }
5050# endif
5051# ifdef FEAT_MOUSE_GPM
5052 gpm_process_wanted = 0;
5053 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
5054# else
5055 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
5056# endif
5057 if (!avail)
5058 {
5059 if (input_available())
5060 return 1;
5061# ifdef FEAT_XCLIPBOARD
5062 if (rest == 0 || !do_xterm_trace())
5063# endif
5064 break;
5065 }
5066 }
5067 while (FALSE
5068# ifdef FEAT_MOUSE_GPM
5069 || (gpm_process_wanted && mch_gpm_process() == 0)
5070# endif
5071# ifdef FEAT_XCLIPBOARD
5072 || (!avail && rest != 0)
5073# endif
5074 );
5075
5076#else
5077 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
5078#endif
5079 return avail;
5080}
5081
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01005082#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00005083/*
5084 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005085 * "msec" == 0 will check for characters once.
5086 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087 * When a GUI is being used, this will not be used for input -- webb
5088 * Returns also, when a request from Sniff is waiting -- toni.
5089 * Or when a Linux GPM mouse event is waiting.
5090 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005091#if defined(__BEOS__)
5092 int
5093#else
5094 static int
5095#endif
5096RealWaitForChar(fd, msec, check_for_gpm)
5097 int fd;
5098 long msec;
Bram Moolenaar78a15312009-05-15 19:33:18 +00005099 int *check_for_gpm UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005100{
5101 int ret;
Bram Moolenaar67c53842010-05-22 18:28:27 +02005102#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02005103 int nb_fd = netbeans_filedesc();
Bram Moolenaar67c53842010-05-22 18:28:27 +02005104#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005105#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005106 static int busy = FALSE;
5107
5108 /* May retry getting characters after an event was handled. */
5109# define MAY_LOOP
5110
5111# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5112 /* Remember at what time we started, so that we know how much longer we
5113 * should wait after being interrupted. */
5114# define USE_START_TV
5115 struct timeval start_tv;
5116
5117 if (msec > 0 && (
5118# ifdef FEAT_XCLIPBOARD
5119 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005120# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121 ||
5122# endif
5123# endif
5124# ifdef USE_XSMP
5125 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005126# ifdef FEAT_MZSCHEME
5127 ||
5128# endif
5129# endif
5130# ifdef FEAT_MZSCHEME
5131 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005132# endif
5133 ))
5134 gettimeofday(&start_tv, NULL);
5135# endif
5136
5137 /* Handle being called recursively. This may happen for the session
5138 * manager stuff, it may save the file, which does a breakcheck. */
5139 if (busy)
5140 return 0;
5141#endif
5142
5143#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00005144 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005145#endif
5146 {
5147#ifdef MAY_LOOP
5148 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005149# ifdef FEAT_MZSCHEME
5150 int mzquantum_used = FALSE;
5151# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005152#endif
5153#ifndef HAVE_SELECT
Bram Moolenaar67c53842010-05-22 18:28:27 +02005154 struct pollfd fds[6];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005155 int nfd;
5156# ifdef FEAT_XCLIPBOARD
5157 int xterm_idx = -1;
5158# endif
5159# ifdef FEAT_MOUSE_GPM
5160 int gpm_idx = -1;
5161# endif
5162# ifdef USE_XSMP
5163 int xsmp_idx = -1;
5164# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005165# ifdef FEAT_NETBEANS_INTG
5166 int nb_idx = -1;
5167# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005168 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005169
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005170# ifdef FEAT_MZSCHEME
5171 mzvim_check_threads();
5172 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5173 {
5174 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
5175 mzquantum_used = TRUE;
5176 }
5177# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005178 fds[0].fd = fd;
5179 fds[0].events = POLLIN;
5180 nfd = 1;
5181
5182# ifdef FEAT_SNIFF
5183# define SNIFF_IDX 1
5184 if (want_sniff_request)
5185 {
5186 fds[SNIFF_IDX].fd = fd_from_sniff;
5187 fds[SNIFF_IDX].events = POLLIN;
5188 nfd++;
5189 }
5190# endif
5191# ifdef FEAT_XCLIPBOARD
5192 if (xterm_Shell != (Widget)0)
5193 {
5194 xterm_idx = nfd;
5195 fds[nfd].fd = ConnectionNumber(xterm_dpy);
5196 fds[nfd].events = POLLIN;
5197 nfd++;
5198 }
5199# endif
5200# ifdef FEAT_MOUSE_GPM
5201 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5202 {
5203 gpm_idx = nfd;
5204 fds[nfd].fd = gpm_fd;
5205 fds[nfd].events = POLLIN;
5206 nfd++;
5207 }
5208# endif
5209# ifdef USE_XSMP
5210 if (xsmp_icefd != -1)
5211 {
5212 xsmp_idx = nfd;
5213 fds[nfd].fd = xsmp_icefd;
5214 fds[nfd].events = POLLIN;
5215 nfd++;
5216 }
5217# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005218#ifdef FEAT_NETBEANS_INTG
5219 if (nb_fd != -1)
5220 {
5221 nb_idx = nfd;
5222 fds[nfd].fd = nb_fd;
5223 fds[nfd].events = POLLIN;
5224 nfd++;
5225 }
5226#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005227
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005228 ret = poll(fds, nfd, towait);
5229# ifdef FEAT_MZSCHEME
5230 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005231 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005232 finished = FALSE;
5233# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005234
5235# ifdef FEAT_SNIFF
5236 if (ret < 0)
5237 sniff_disconnect(1);
5238 else if (want_sniff_request)
5239 {
5240 if (fds[SNIFF_IDX].revents & POLLHUP)
5241 sniff_disconnect(1);
5242 if (fds[SNIFF_IDX].revents & POLLIN)
5243 sniff_request_waiting = 1;
5244 }
5245# endif
5246# ifdef FEAT_XCLIPBOARD
5247 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
5248 {
5249 xterm_update(); /* Maybe we should hand out clipboard */
5250 if (--ret == 0 && !input_available())
5251 /* Try again */
5252 finished = FALSE;
5253 }
5254# endif
5255# ifdef FEAT_MOUSE_GPM
5256 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
5257 {
5258 *check_for_gpm = 1;
5259 }
5260# endif
5261# ifdef USE_XSMP
5262 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
5263 {
5264 if (fds[xsmp_idx].revents & POLLIN)
5265 {
5266 busy = TRUE;
5267 xsmp_handle_requests();
5268 busy = FALSE;
5269 }
5270 else if (fds[xsmp_idx].revents & POLLHUP)
5271 {
5272 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005273 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005274 xsmp_close();
5275 }
5276 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005277 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005278 }
5279# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005280#ifdef FEAT_NETBEANS_INTG
5281 if (ret > 0 && nb_idx != -1 && fds[nb_idx].revents & POLLIN)
5282 {
5283 netbeans_read();
5284 --ret;
5285 }
5286#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005287
5288
5289#else /* HAVE_SELECT */
5290
5291 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005292 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005293 fd_set rfds, efds;
5294 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005295 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005296
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005297# ifdef FEAT_MZSCHEME
5298 mzvim_check_threads();
5299 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5300 {
5301 towait = p_mzq; /* don't wait longer than 'mzquantum' */
5302 mzquantum_used = TRUE;
5303 }
5304# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005305# ifdef __EMX__
5306 /* don't check for incoming chars if not in raw mode, because select()
5307 * always returns TRUE then (in some version of emx.dll) */
5308 if (curr_tmode != TMODE_RAW)
5309 return 0;
5310# endif
5311
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005312 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005313 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005314 tv.tv_sec = towait / 1000;
5315 tv.tv_usec = (towait % 1000) * (1000000/1000);
5316 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005317 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005318 else
5319 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005320
5321 /*
5322 * Select on ready for reading and exceptional condition (end of file).
5323 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005324select_eintr:
5325 FD_ZERO(&rfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005326 FD_ZERO(&efds);
5327 FD_SET(fd, &rfds);
5328# if !defined(__QNX__) && !defined(__CYGWIN32__)
5329 /* For QNX select() always returns 1 if this is set. Why? */
5330 FD_SET(fd, &efds);
5331# endif
5332 maxfd = fd;
5333
5334# ifdef FEAT_SNIFF
5335 if (want_sniff_request)
5336 {
5337 FD_SET(fd_from_sniff, &rfds);
5338 FD_SET(fd_from_sniff, &efds);
5339 if (maxfd < fd_from_sniff)
5340 maxfd = fd_from_sniff;
5341 }
5342# endif
5343# ifdef FEAT_XCLIPBOARD
5344 if (xterm_Shell != (Widget)0)
5345 {
5346 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
5347 if (maxfd < ConnectionNumber(xterm_dpy))
5348 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02005349
5350 /* An event may have already been read but not handled. In
5351 * particulary, XFlush may cause this. */
5352 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005353 }
5354# endif
5355# ifdef FEAT_MOUSE_GPM
5356 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5357 {
5358 FD_SET(gpm_fd, &rfds);
5359 FD_SET(gpm_fd, &efds);
5360 if (maxfd < gpm_fd)
5361 maxfd = gpm_fd;
5362 }
5363# endif
5364# ifdef USE_XSMP
5365 if (xsmp_icefd != -1)
5366 {
5367 FD_SET(xsmp_icefd, &rfds);
5368 FD_SET(xsmp_icefd, &efds);
5369 if (maxfd < xsmp_icefd)
5370 maxfd = xsmp_icefd;
5371 }
5372# endif
Bram Moolenaardd82d692012-08-15 17:26:57 +02005373# ifdef FEAT_NETBEANS_INTG
Bram Moolenaar67c53842010-05-22 18:28:27 +02005374 if (nb_fd != -1)
5375 {
5376 FD_SET(nb_fd, &rfds);
5377 if (maxfd < nb_fd)
5378 maxfd = nb_fd;
5379 }
Bram Moolenaardd82d692012-08-15 17:26:57 +02005380# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005381
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005382 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005383# ifdef EINTR
5384 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005385 {
5386 /* Check whether window has been resized, EINTR may be caused by
5387 * SIGWINCH. */
5388 if (do_resize)
5389 handle_resize();
5390
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005391 /* Interrupted by a signal, need to try again. We ignore msec
5392 * here, because we do want to check even after a timeout if
5393 * characters are available. Needed for reading output of an
5394 * external command after the process has finished. */
5395 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005396 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005397# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00005398# ifdef __TANDEM
5399 if (ret == -1 && errno == ENOTSUP)
5400 {
5401 FD_ZERO(&rfds);
5402 FD_ZERO(&efds);
5403 ret = 0;
5404 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005405# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005406# ifdef FEAT_MZSCHEME
5407 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005408 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005409 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005410# endif
5411
5412# ifdef FEAT_SNIFF
5413 if (ret < 0 )
5414 sniff_disconnect(1);
5415 else if (ret > 0 && want_sniff_request)
5416 {
5417 if (FD_ISSET(fd_from_sniff, &efds))
5418 sniff_disconnect(1);
5419 if (FD_ISSET(fd_from_sniff, &rfds))
5420 sniff_request_waiting = 1;
5421 }
5422# endif
5423# ifdef FEAT_XCLIPBOARD
5424 if (ret > 0 && xterm_Shell != (Widget)0
5425 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
5426 {
5427 xterm_update(); /* Maybe we should hand out clipboard */
5428 /* continue looping when we only got the X event and the input
5429 * buffer is empty */
5430 if (--ret == 0 && !input_available())
5431 {
5432 /* Try again */
5433 finished = FALSE;
5434 }
5435 }
5436# endif
5437# ifdef FEAT_MOUSE_GPM
5438 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
5439 {
5440 if (FD_ISSET(gpm_fd, &efds))
5441 gpm_close();
5442 else if (FD_ISSET(gpm_fd, &rfds))
5443 *check_for_gpm = 1;
5444 }
5445# endif
5446# ifdef USE_XSMP
5447 if (ret > 0 && xsmp_icefd != -1)
5448 {
5449 if (FD_ISSET(xsmp_icefd, &efds))
5450 {
5451 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005452 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005453 xsmp_close();
5454 if (--ret == 0)
5455 finished = FALSE; /* keep going if event was only one */
5456 }
5457 else if (FD_ISSET(xsmp_icefd, &rfds))
5458 {
5459 busy = TRUE;
5460 xsmp_handle_requests();
5461 busy = FALSE;
5462 if (--ret == 0)
5463 finished = FALSE; /* keep going if event was only one */
5464 }
5465 }
5466# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005467#ifdef FEAT_NETBEANS_INTG
5468 if (ret > 0 && nb_fd != -1 && FD_ISSET(nb_fd, &rfds))
5469 {
5470 netbeans_read();
5471 --ret;
5472 }
5473#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005474
5475#endif /* HAVE_SELECT */
5476
5477#ifdef MAY_LOOP
5478 if (finished || msec == 0)
5479 break;
5480
5481 /* We're going to loop around again, find out for how long */
5482 if (msec > 0)
5483 {
5484# ifdef USE_START_TV
5485 struct timeval mtv;
5486
5487 /* Compute remaining wait time. */
5488 gettimeofday(&mtv, NULL);
5489 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
5490 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
5491# else
5492 /* Guess we got interrupted halfway. */
5493 msec = msec / 2;
5494# endif
5495 if (msec <= 0)
5496 break; /* waited long enough */
5497 }
5498#endif
5499 }
5500
5501 return (ret > 0);
5502}
5503
Bram Moolenaar071d4272004-06-13 20:20:40 +00005504#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00005505/*
Bram Moolenaar02743632005-07-25 20:42:36 +00005506 * Expand a path into all matching files and/or directories. Handles "*",
5507 * "?", "[a-z]", "**", etc.
5508 * "path" has backslashes before chars that are not to be expanded.
5509 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005510 */
5511 int
5512mch_expandpath(gap, path, flags)
5513 garray_T *gap;
5514 char_u *path;
5515 int flags; /* EW_* flags */
5516{
Bram Moolenaar02743632005-07-25 20:42:36 +00005517 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005518}
5519#endif
5520
5521/*
5522 * mch_expand_wildcards() - this code does wild-card pattern matching using
5523 * the shell
5524 *
5525 * return OK for success, FAIL for error (you may lose some memory) and put
5526 * an error message in *file.
5527 *
5528 * num_pat is number of input patterns
5529 * pat is array of pointers to input patterns
5530 * num_file is pointer to number of matched file names
5531 * file is pointer to array of pointers to matched file names
5532 */
5533
5534#ifndef SEEK_SET
5535# define SEEK_SET 0
5536#endif
5537#ifndef SEEK_END
5538# define SEEK_END 2
5539#endif
5540
Bram Moolenaar5555acc2006-04-07 21:33:12 +00005541#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00005542
Bram Moolenaar071d4272004-06-13 20:20:40 +00005543 int
5544mch_expand_wildcards(num_pat, pat, num_file, file, flags)
5545 int num_pat;
5546 char_u **pat;
5547 int *num_file;
5548 char_u ***file;
5549 int flags; /* EW_* flags */
5550{
5551 int i;
5552 size_t len;
5553 char_u *p;
5554 int dir;
5555#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00005556 /*
5557 * This is the OS/2 implementation.
5558 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005559# define EXPL_ALLOC_INC 16
5560 char_u **expl_files;
5561 size_t files_alloced, files_free;
5562 char_u *buf;
5563 int has_wildcard;
5564
5565 *num_file = 0; /* default: no files found */
5566 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
5567 files_free = EXPL_ALLOC_INC; /* how much space is not used */
5568 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
5569 if (*file == NULL)
5570 return FAIL;
5571
5572 for (; num_pat > 0; num_pat--, pat++)
5573 {
5574 expl_files = NULL;
5575 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
5576 /* expand environment var or home dir */
5577 buf = expand_env_save(*pat);
5578 else
5579 buf = vim_strsave(*pat);
5580 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005581 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005582 if (has_wildcard) /* yes, so expand them */
5583 expl_files = (char_u **)_fnexplode(buf);
5584
5585 /*
5586 * return value of buf if no wildcards left,
5587 * OR if no match AND EW_NOTFOUND is set.
5588 */
5589 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
5590 || (expl_files == NULL && (flags & EW_NOTFOUND)))
5591 { /* simply save the current contents of *buf */
5592 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
5593 if (expl_files != NULL)
5594 {
5595 expl_files[0] = vim_strsave(buf);
5596 expl_files[1] = NULL;
5597 }
5598 }
5599 vim_free(buf);
5600
5601 /*
5602 * Count number of names resulting from expansion,
5603 * At the same time add a backslash to the end of names that happen to
5604 * be directories, and replace slashes with backslashes.
5605 */
5606 if (expl_files)
5607 {
5608 for (i = 0; (p = expl_files[i]) != NULL; i++)
5609 {
5610 dir = mch_isdir(p);
5611 /* If we don't want dirs and this is one, skip it */
5612 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5613 continue;
5614
Bram Moolenaara2031822006-03-07 22:29:51 +00005615 /* Skip files that are not executable if we check for that. */
Bram Moolenaarc7f02552014-04-01 21:00:59 +02005616 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p, NULL))
Bram Moolenaara2031822006-03-07 22:29:51 +00005617 continue;
5618
Bram Moolenaar071d4272004-06-13 20:20:40 +00005619 if (--files_free == 0)
5620 {
5621 /* need more room in table of pointers */
5622 files_alloced += EXPL_ALLOC_INC;
5623 *file = (char_u **)vim_realloc(*file,
5624 sizeof(char_u **) * files_alloced);
5625 if (*file == NULL)
5626 {
5627 EMSG(_(e_outofmem));
5628 *num_file = 0;
5629 return FAIL;
5630 }
5631 files_free = EXPL_ALLOC_INC;
5632 }
5633 slash_adjust(p);
5634 if (dir)
5635 {
5636 /* For a directory we add a '/', unless it's already
5637 * there. */
5638 len = STRLEN(p);
5639 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5640 {
5641 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005642 if (!after_pathsep((*file)[*num_file],
5643 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005644 {
5645 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005646 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005647 }
5648 }
5649 }
5650 else
5651 {
5652 (*file)[*num_file] = vim_strsave(p);
5653 }
5654
5655 /*
5656 * Error message already given by either alloc or vim_strsave.
5657 * Should return FAIL, but returning OK works also.
5658 */
5659 if ((*file)[*num_file] == NULL)
5660 break;
5661 (*num_file)++;
5662 }
5663 _fnexplodefree((char **)expl_files);
5664 }
5665 }
5666 return OK;
5667
5668#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005669 /*
5670 * This is the non-OS/2 implementation (really Unix).
5671 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005672 int j;
5673 char_u *tempname;
5674 char_u *command;
5675 FILE *fd;
5676 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005677#define STYLE_ECHO 0 /* use "echo", the default */
5678#define STYLE_GLOB 1 /* use "glob", for csh */
5679#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5680#define STYLE_PRINT 3 /* use "print -N", for zsh */
5681#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5682 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005683 int shell_style = STYLE_ECHO;
5684 int check_spaces;
5685 static int did_find_nul = FALSE;
5686 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005687 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005688 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005689
5690 *num_file = 0; /* default: no files found */
5691 *file = NULL;
5692
5693 /*
5694 * If there are no wildcards, just copy the names to allocated memory.
5695 * Saves a lot of time, because we don't have to start a new shell.
5696 */
5697 if (!have_wildcard(num_pat, pat))
5698 return save_patterns(num_pat, pat, num_file, file);
5699
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005700# ifdef HAVE_SANDBOX
5701 /* Don't allow any shell command in the sandbox. */
5702 if (sandbox != 0 && check_secure())
5703 return FAIL;
5704# endif
5705
Bram Moolenaar071d4272004-06-13 20:20:40 +00005706 /*
5707 * Don't allow the use of backticks in secure and restricted mode.
5708 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005709 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005710 for (i = 0; i < num_pat; ++i)
5711 if (vim_strchr(pat[i], '`') != NULL
5712 && (check_restricted() || check_secure()))
5713 return FAIL;
5714
5715 /*
5716 * get a name for the temp file
5717 */
5718 if ((tempname = vim_tempname('o')) == NULL)
5719 {
5720 EMSG(_(e_notmp));
5721 return FAIL;
5722 }
5723
5724 /*
5725 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005726 * file.
5727 * STYLE_BT: NL separated
5728 * If expanding `cmd` execute it directly.
5729 * STYLE_GLOB: NUL separated
5730 * If we use *csh, "glob" will work better than "echo".
5731 * STYLE_PRINT: NL or NUL separated
5732 * If we use *zsh, "print -N" will work better than "glob".
5733 * STYLE_VIMGLOB: NL separated
5734 * If we use *sh*, we define "vimglob()".
5735 * STYLE_ECHO: space separated.
5736 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005737 */
5738 if (num_pat == 1 && *pat[0] == '`'
5739 && (len = STRLEN(pat[0])) > 2
5740 && *(pat[0] + len - 1) == '`')
5741 shell_style = STYLE_BT;
5742 else if ((len = STRLEN(p_sh)) >= 3)
5743 {
5744 if (STRCMP(p_sh + len - 3, "csh") == 0)
5745 shell_style = STYLE_GLOB;
5746 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5747 shell_style = STYLE_PRINT;
5748 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005749 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5750 "sh") != NULL)
5751 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005752
Bram Moolenaarc7247912008-01-13 12:54:11 +00005753 /* Compute the length of the command. We need 2 extra bytes: for the
5754 * optional '&' and for the NUL.
5755 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005756 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005757 if (shell_style == STYLE_VIMGLOB)
5758 len += STRLEN(sh_vimglob_func);
5759
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005760 for (i = 0; i < num_pat; ++i)
5761 {
5762 /* Count the length of the patterns in the same way as they are put in
5763 * "command" below. */
5764#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005765 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005766#else
5767 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005768 for (j = 0; pat[i][j] != NUL; ++j)
5769 {
5770 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5771 ++len; /* may add a backslash */
5772 ++len;
5773 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005774#endif
5775 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005776 command = alloc(len);
5777 if (command == NULL)
5778 {
5779 /* out of memory */
5780 vim_free(tempname);
5781 return FAIL;
5782 }
5783
5784 /*
5785 * Build the shell command:
5786 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5787 * recognizes this).
5788 * - Add the shell command to print the expanded names.
5789 * - Add the temp file name.
5790 * - Add the file name patterns.
5791 */
5792 if (shell_style == STYLE_BT)
5793 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005794 /* change `command; command& ` to (command; command ) */
5795 STRCPY(command, "(");
5796 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005797 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005798 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005799 while (p > command && vim_iswhite(*p))
5800 --p;
5801 if (*p == '&') /* remove trailing '&' */
5802 {
5803 ampersent = TRUE;
5804 *p = ' ';
5805 }
5806 STRCAT(command, ">");
5807 }
5808 else
5809 {
5810 if (flags & EW_NOTFOUND)
5811 STRCPY(command, "set nonomatch; ");
5812 else
5813 STRCPY(command, "unset nonomatch; ");
5814 if (shell_style == STYLE_GLOB)
5815 STRCAT(command, "glob >");
5816 else if (shell_style == STYLE_PRINT)
5817 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005818 else if (shell_style == STYLE_VIMGLOB)
5819 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005820 else
5821 STRCAT(command, "echo >");
5822 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005823
Bram Moolenaar071d4272004-06-13 20:20:40 +00005824 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005825
Bram Moolenaar071d4272004-06-13 20:20:40 +00005826 if (shell_style != STYLE_BT)
5827 for (i = 0; i < num_pat; ++i)
5828 {
5829 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005830 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005831 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005832#ifdef USE_SYSTEM
5833 STRCAT(command, " \"");
5834 STRCAT(command, pat[i]);
5835 STRCAT(command, "\"");
5836#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005837 int intick = FALSE;
5838
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839 p = command + STRLEN(command);
5840 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005841 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005842 {
5843 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005844 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005845 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5846 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005847 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005848 * backslash inside backticks, before a special character
5849 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005850 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005851 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5852 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005853 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005854 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005855 }
5856 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005857 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005858 /* Put a backslash before a special character, but not
5859 * when inside ``. */
5860 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005861
5862 /* Copy one character. */
5863 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005864 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005865 *p = NUL;
5866#endif
5867 }
5868 if (flags & EW_SILENT)
5869 show_shell_mess = FALSE;
5870 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00005871 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005872
5873 /*
5874 * Using zsh -G: If a pattern has no matches, it is just deleted from
5875 * the argument list, otherwise zsh gives an error message and doesn't
5876 * expand any other pattern.
5877 */
5878 if (shell_style == STYLE_PRINT)
5879 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5880
5881 /*
5882 * If we use -f then shell variables set in .cshrc won't get expanded.
5883 * vi can do it, so we will too, but it is only necessary if there is a "$"
5884 * in one of the patterns, otherwise we can still use the fast option.
5885 */
5886 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5887 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5888
5889 /*
5890 * execute the shell command
5891 */
5892 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5893
5894 /* When running in the background, give it some time to create the temp
5895 * file, but don't wait for it to finish. */
5896 if (ampersent)
5897 mch_delay(10L, TRUE);
5898
5899 extra_shell_arg = NULL; /* cleanup */
5900 show_shell_mess = TRUE;
5901 vim_free(command);
5902
Bram Moolenaarc7247912008-01-13 12:54:11 +00005903 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005904 {
5905 mch_remove(tempname);
5906 vim_free(tempname);
5907 /*
5908 * With interactive completion, the error message is not printed.
5909 * However with USE_SYSTEM, I don't know how to turn off error messages
5910 * from the shell, so screen may still get messed up -- webb.
5911 */
5912#ifndef USE_SYSTEM
5913 if (!(flags & EW_SILENT))
5914#endif
5915 {
5916 redraw_later_clear(); /* probably messed up screen */
5917 msg_putchar('\n'); /* clear bottom line quickly */
5918 cmdline_row = Rows - 1; /* continue on last line */
5919#ifdef USE_SYSTEM
5920 if (!(flags & EW_SILENT))
5921#endif
5922 {
5923 MSG(_(e_wildexpand));
5924 msg_start(); /* don't overwrite this message */
5925 }
5926 }
5927 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5928 * EW_NOTFOUND is given */
5929 if (shell_style == STYLE_BT)
5930 return FAIL;
5931 goto notfound;
5932 }
5933
5934 /*
5935 * read the names from the file into memory
5936 */
5937 fd = fopen((char *)tempname, READBIN);
5938 if (fd == NULL)
5939 {
5940 /* Something went wrong, perhaps a file name with a special char. */
5941 if (!(flags & EW_SILENT))
5942 {
5943 MSG(_(e_wildexpand));
5944 msg_start(); /* don't overwrite this message */
5945 }
5946 vim_free(tempname);
5947 goto notfound;
5948 }
5949 fseek(fd, 0L, SEEK_END);
5950 len = ftell(fd); /* get size of temp file */
5951 fseek(fd, 0L, SEEK_SET);
5952 buffer = alloc(len + 1);
5953 if (buffer == NULL)
5954 {
5955 /* out of memory */
5956 mch_remove(tempname);
5957 vim_free(tempname);
5958 fclose(fd);
5959 return FAIL;
5960 }
5961 i = fread((char *)buffer, 1, len, fd);
5962 fclose(fd);
5963 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00005964 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005965 {
5966 /* unexpected read error */
5967 EMSG2(_(e_notread), tempname);
5968 vim_free(tempname);
5969 vim_free(buffer);
5970 return FAIL;
5971 }
5972 vim_free(tempname);
5973
Bram Moolenaarc7247912008-01-13 12:54:11 +00005974# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005975 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5976 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02005977 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005978 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5979 *p++ = buffer[i];
5980 len = p - buffer;
5981# endif
5982
5983
5984 /* file names are separated with Space */
5985 if (shell_style == STYLE_ECHO)
5986 {
5987 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5988 p = buffer;
5989 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5990 {
5991 while (*p != ' ' && *p != '\n')
5992 ++p;
5993 p = skipwhite(p); /* skip to next entry */
5994 }
5995 }
5996 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005997 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005998 {
5999 buffer[len] = NUL; /* make sure the buffer ends in NUL */
6000 p = buffer;
6001 for (i = 0; *p != NUL; ++i) /* count number of entries */
6002 {
6003 while (*p != '\n' && *p != NUL)
6004 ++p;
6005 if (*p != NUL)
6006 ++p;
6007 p = skipwhite(p); /* skip leading white space */
6008 }
6009 }
6010 /* file names are separated with NUL */
6011 else
6012 {
6013 /*
6014 * Some versions of zsh use spaces instead of NULs to separate
6015 * results. Only do this when there is no NUL before the end of the
6016 * buffer, otherwise we would never be able to use file names with
6017 * embedded spaces when zsh does use NULs.
6018 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6019 * don't check for spaces again.
6020 */
6021 check_spaces = FALSE;
6022 if (shell_style == STYLE_PRINT && !did_find_nul)
6023 {
6024 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006025 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006026 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006027 did_find_nul = TRUE;
6028 else
6029 check_spaces = TRUE;
6030 }
6031
6032 /*
6033 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6034 * already is one, for STYLE_GLOB it needs to be added.
6035 */
6036 if (len && buffer[len - 1] == NUL)
6037 --len;
6038 else
6039 buffer[len] = NUL;
6040 i = 0;
6041 for (p = buffer; p < buffer + len; ++p)
6042 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
6043 {
6044 ++i;
6045 *p = NUL;
6046 }
6047 if (len)
6048 ++i; /* count last entry */
6049 }
6050 if (i == 0)
6051 {
6052 /*
6053 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6054 * /bin/sh will happily expand it to nothing rather than returning an
6055 * error; and hey, it's good to check anyway -- webb.
6056 */
6057 vim_free(buffer);
6058 goto notfound;
6059 }
6060 *num_file = i;
6061 *file = (char_u **)alloc(sizeof(char_u *) * i);
6062 if (*file == NULL)
6063 {
6064 /* out of memory */
6065 vim_free(buffer);
6066 return FAIL;
6067 }
6068
6069 /*
6070 * Isolate the individual file names.
6071 */
6072 p = buffer;
6073 for (i = 0; i < *num_file; ++i)
6074 {
6075 (*file)[i] = p;
6076 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006077 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6078 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006079 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006080 while (!(shell_style == STYLE_ECHO && *p == ' ')
6081 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006082 ++p;
6083 if (p == buffer + len) /* last entry */
6084 *p = NUL;
6085 else
6086 {
6087 *p++ = NUL;
6088 p = skipwhite(p); /* skip to next entry */
6089 }
6090 }
6091 else /* NUL separates */
6092 {
6093 while (*p && p < buffer + len) /* skip entry */
6094 ++p;
6095 ++p; /* skip NUL */
6096 }
6097 }
6098
6099 /*
6100 * Move the file names to allocated memory.
6101 */
6102 for (j = 0, i = 0; i < *num_file; ++i)
6103 {
6104 /* Require the files to exist. Helps when using /bin/sh */
6105 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6106 continue;
6107
6108 /* check if this entry should be included */
6109 dir = (mch_isdir((*file)[i]));
6110 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6111 continue;
6112
Bram Moolenaara2031822006-03-07 22:29:51 +00006113 /* Skip files that are not executable if we check for that. */
Bram Moolenaarc7f02552014-04-01 21:00:59 +02006114 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i], NULL))
Bram Moolenaara2031822006-03-07 22:29:51 +00006115 continue;
6116
Bram Moolenaar071d4272004-06-13 20:20:40 +00006117 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
6118 if (p)
6119 {
6120 STRCPY(p, (*file)[i]);
6121 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00006122 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006123 (*file)[j++] = p;
6124 }
6125 }
6126 vim_free(buffer);
6127 *num_file = j;
6128
6129 if (*num_file == 0) /* rejected all entries */
6130 {
6131 vim_free(*file);
6132 *file = NULL;
6133 goto notfound;
6134 }
6135
6136 return OK;
6137
6138notfound:
6139 if (flags & EW_NOTFOUND)
6140 return save_patterns(num_pat, pat, num_file, file);
6141 return FAIL;
6142
6143#endif /* __EMX__ */
6144}
6145
6146#endif /* VMS */
6147
6148#ifndef __EMX__
6149 static int
6150save_patterns(num_pat, pat, num_file, file)
6151 int num_pat;
6152 char_u **pat;
6153 int *num_file;
6154 char_u ***file;
6155{
6156 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006157 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006158
6159 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
6160 if (*file == NULL)
6161 return FAIL;
6162 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006163 {
6164 s = vim_strsave(pat[i]);
6165 if (s != NULL)
6166 /* Be compatible with expand_filename(): halve the number of
6167 * backslashes. */
6168 backslash_halve(s);
6169 (*file)[i] = s;
6170 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006171 *num_file = num_pat;
6172 return OK;
6173}
6174#endif
6175
Bram Moolenaar071d4272004-06-13 20:20:40 +00006176/*
6177 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
6178 * expand.
6179 */
6180 int
6181mch_has_exp_wildcard(p)
6182 char_u *p;
6183{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006184 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006185 {
6186#ifndef OS2
6187 if (*p == '\\' && p[1] != NUL)
6188 ++p;
6189 else
6190#endif
6191 if (vim_strchr((char_u *)
6192#ifdef VMS
6193 "*?%"
6194#else
6195# ifdef OS2
6196 "*?"
6197# else
6198 "*?[{'"
6199# endif
6200#endif
6201 , *p) != NULL)
6202 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006203 }
6204 return FALSE;
6205}
6206
6207/*
6208 * Return TRUE if the string "p" contains a wildcard.
6209 * Don't recognize '~' at the end as a wildcard.
6210 */
6211 int
6212mch_has_wildcard(p)
6213 char_u *p;
6214{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006215 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006216 {
6217#ifndef OS2
6218 if (*p == '\\' && p[1] != NUL)
6219 ++p;
6220 else
6221#endif
6222 if (vim_strchr((char_u *)
6223#ifdef VMS
6224 "*?%$"
6225#else
6226# ifdef OS2
6227# ifdef VIM_BACKTICK
6228 "*?$`"
6229# else
6230 "*?$"
6231# endif
6232# else
6233 "*?[{`'$"
6234# endif
6235#endif
6236 , *p) != NULL
6237 || (*p == '~' && p[1] != NUL))
6238 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006239 }
6240 return FALSE;
6241}
6242
6243#ifndef __EMX__
6244 static int
6245have_wildcard(num, file)
6246 int num;
6247 char_u **file;
6248{
6249 int i;
6250
6251 for (i = 0; i < num; i++)
6252 if (mch_has_wildcard(file[i]))
6253 return 1;
6254 return 0;
6255}
6256
6257 static int
6258have_dollars(num, file)
6259 int num;
6260 char_u **file;
6261{
6262 int i;
6263
6264 for (i = 0; i < num; i++)
6265 if (vim_strchr(file[i], '$') != NULL)
6266 return TRUE;
6267 return FALSE;
6268}
6269#endif /* ifndef __EMX__ */
6270
6271#ifndef HAVE_RENAME
6272/*
6273 * Scaled-down version of rename(), which is missing in Xenix.
6274 * This version can only move regular files and will fail if the
6275 * destination exists.
6276 */
6277 int
6278mch_rename(src, dest)
6279 const char *src, *dest;
6280{
6281 struct stat st;
6282
6283 if (stat(dest, &st) >= 0) /* fail if destination exists */
6284 return -1;
6285 if (link(src, dest) != 0) /* link file to new name */
6286 return -1;
6287 if (mch_remove(src) == 0) /* delete link to old name */
6288 return 0;
6289 return -1;
6290}
6291#endif /* !HAVE_RENAME */
6292
6293#ifdef FEAT_MOUSE_GPM
6294/*
6295 * Initializes connection with gpm (if it isn't already opened)
6296 * Return 1 if succeeded (or connection already opened), 0 if failed
6297 */
6298 static int
6299gpm_open()
6300{
6301 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
6302
6303 if (!gpm_flag)
6304 {
6305 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
6306 gpm_connect.defaultMask = ~GPM_HARD;
6307 /* Default handling for mouse move*/
6308 gpm_connect.minMod = 0; /* Handle any modifier keys */
6309 gpm_connect.maxMod = 0xffff;
6310 if (Gpm_Open(&gpm_connect, 0) > 0)
6311 {
6312 /* gpm library tries to handling TSTP causes
6313 * problems. Anyways, we close connection to Gpm whenever
6314 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006315 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00006316 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006317# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00006318 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006319# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006320 return 1; /* succeed */
6321 }
6322 if (gpm_fd == -2)
6323 Gpm_Close(); /* We don't want to talk to xterm via gpm */
6324 return 0;
6325 }
6326 return 1; /* already open */
6327}
6328
6329/*
6330 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00006331 */
6332 static void
6333gpm_close()
6334{
6335 if (gpm_flag && gpm_fd >= 0) /* if Open */
6336 Gpm_Close();
6337}
6338
6339/* Reads gpm event and adds special keys to input buf. Returns length of
6340 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02006341 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00006342 */
6343 static int
6344mch_gpm_process()
6345{
6346 int button;
6347 static Gpm_Event gpm_event;
6348 char_u string[6];
6349 int_u vim_modifiers;
6350 int row,col;
6351 unsigned char buttons_mask;
6352 unsigned char gpm_modifiers;
6353 static unsigned char old_buttons = 0;
6354
6355 Gpm_GetEvent(&gpm_event);
6356
6357#ifdef FEAT_GUI
6358 /* Don't put events in the input queue now. */
6359 if (hold_gui_events)
6360 return 0;
6361#endif
6362
6363 row = gpm_event.y - 1;
6364 col = gpm_event.x - 1;
6365
6366 string[0] = ESC; /* Our termcode */
6367 string[1] = 'M';
6368 string[2] = 'G';
6369 switch (GPM_BARE_EVENTS(gpm_event.type))
6370 {
6371 case GPM_DRAG:
6372 string[3] = MOUSE_DRAG;
6373 break;
6374 case GPM_DOWN:
6375 buttons_mask = gpm_event.buttons & ~old_buttons;
6376 old_buttons = gpm_event.buttons;
6377 switch (buttons_mask)
6378 {
6379 case GPM_B_LEFT:
6380 button = MOUSE_LEFT;
6381 break;
6382 case GPM_B_MIDDLE:
6383 button = MOUSE_MIDDLE;
6384 break;
6385 case GPM_B_RIGHT:
6386 button = MOUSE_RIGHT;
6387 break;
6388 default:
6389 return 0;
6390 /*Don't know what to do. Can more than one button be
6391 * reported in one event? */
6392 }
6393 string[3] = (char_u)(button | 0x20);
6394 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
6395 break;
6396 case GPM_UP:
6397 string[3] = MOUSE_RELEASE;
6398 old_buttons &= ~gpm_event.buttons;
6399 break;
6400 default:
6401 return 0;
6402 }
6403 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
6404 gpm_modifiers = gpm_event.modifiers;
6405 vim_modifiers = 0x0;
6406 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
6407 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
6408 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
6409 */
6410 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
6411 vim_modifiers |= MOUSE_SHIFT;
6412
6413 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
6414 vim_modifiers |= MOUSE_CTRL;
6415 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
6416 vim_modifiers |= MOUSE_ALT;
6417 string[3] |= vim_modifiers;
6418 string[4] = (char_u)(col + ' ' + 1);
6419 string[5] = (char_u)(row + ' ' + 1);
6420 add_to_input_buf(string, 6);
6421 return 6;
6422}
6423#endif /* FEAT_MOUSE_GPM */
6424
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006425#ifdef FEAT_SYSMOUSE
6426/*
6427 * Initialize connection with sysmouse.
6428 * Let virtual console inform us with SIGUSR2 for pending sysmouse
6429 * output, any sysmouse output than will be processed via sig_sysmouse().
6430 * Return OK if succeeded, FAIL if failed.
6431 */
6432 static int
6433sysmouse_open()
6434{
6435 struct mouse_info mouse;
6436
6437 mouse.operation = MOUSE_MODE;
6438 mouse.u.mode.mode = 0;
6439 mouse.u.mode.signal = SIGUSR2;
6440 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
6441 {
6442 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
6443 mouse.operation = MOUSE_SHOW;
6444 ioctl(1, CONS_MOUSECTL, &mouse);
6445 return OK;
6446 }
6447 return FAIL;
6448}
6449
6450/*
6451 * Stop processing SIGUSR2 signals, and also make sure that
6452 * virtual console do not send us any sysmouse related signal.
6453 */
6454 static void
6455sysmouse_close()
6456{
6457 struct mouse_info mouse;
6458
6459 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
6460 mouse.operation = MOUSE_MODE;
6461 mouse.u.mode.mode = 0;
6462 mouse.u.mode.signal = 0;
6463 ioctl(1, CONS_MOUSECTL, &mouse);
6464}
6465
6466/*
6467 * Gets info from sysmouse and adds special keys to input buf.
6468 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006469 static RETSIGTYPE
6470sig_sysmouse SIGDEFARG(sigarg)
6471{
6472 struct mouse_info mouse;
6473 struct video_info video;
6474 char_u string[6];
6475 int row, col;
6476 int button;
6477 int buttons;
6478 static int oldbuttons = 0;
6479
6480#ifdef FEAT_GUI
6481 /* Don't put events in the input queue now. */
6482 if (hold_gui_events)
6483 return;
6484#endif
6485
6486 mouse.operation = MOUSE_GETINFO;
6487 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
6488 && ioctl(1, FBIO_MODEINFO, &video) != -1
6489 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
6490 && video.vi_cheight > 0 && video.vi_cwidth > 0)
6491 {
6492 row = mouse.u.data.y / video.vi_cheight;
6493 col = mouse.u.data.x / video.vi_cwidth;
6494 buttons = mouse.u.data.buttons;
6495 string[0] = ESC; /* Our termcode */
6496 string[1] = 'M';
6497 string[2] = 'S';
6498 if (oldbuttons == buttons && buttons != 0)
6499 {
6500 button = MOUSE_DRAG;
6501 }
6502 else
6503 {
6504 switch (buttons)
6505 {
6506 case 0:
6507 button = MOUSE_RELEASE;
6508 break;
6509 case 1:
6510 button = MOUSE_LEFT;
6511 break;
6512 case 2:
6513 button = MOUSE_MIDDLE;
6514 break;
6515 case 4:
6516 button = MOUSE_RIGHT;
6517 break;
6518 default:
6519 return;
6520 }
6521 oldbuttons = buttons;
6522 }
6523 string[3] = (char_u)(button);
6524 string[4] = (char_u)(col + ' ' + 1);
6525 string[5] = (char_u)(row + ' ' + 1);
6526 add_to_input_buf(string, 6);
6527 }
6528 return;
6529}
6530#endif /* FEAT_SYSMOUSE */
6531
Bram Moolenaar071d4272004-06-13 20:20:40 +00006532#if defined(FEAT_LIBCALL) || defined(PROTO)
6533typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
6534typedef char_u * (*INTPROCSTR)__ARGS((int));
6535typedef int (*STRPROCINT)__ARGS((char_u *));
6536typedef int (*INTPROCINT)__ARGS((int));
6537
6538/*
6539 * Call a DLL routine which takes either a string or int param
6540 * and returns an allocated string.
6541 */
6542 int
6543mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
6544 char_u *libname;
6545 char_u *funcname;
6546 char_u *argstring; /* NULL when using a argint */
6547 int argint;
6548 char_u **string_result;/* NULL when using number_result */
6549 int *number_result;
6550{
6551# if defined(USE_DLOPEN)
6552 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006553 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006554# else
6555 shl_t hinstLib;
6556# endif
6557 STRPROCSTR ProcAdd;
6558 INTPROCSTR ProcAddI;
6559 char_u *retval_str = NULL;
6560 int retval_int = 0;
6561 int success = FALSE;
6562
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006563 /*
6564 * Get a handle to the DLL module.
6565 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006566# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006567 /* First clear any error, it's not cleared by the dlopen() call. */
6568 (void)dlerror();
6569
Bram Moolenaar071d4272004-06-13 20:20:40 +00006570 hinstLib = dlopen((char *)libname, RTLD_LAZY
6571# ifdef RTLD_LOCAL
6572 | RTLD_LOCAL
6573# endif
6574 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006575 if (hinstLib == NULL)
6576 {
6577 /* "dlerr" must be used before dlclose() */
6578 dlerr = (char *)dlerror();
6579 if (dlerr != NULL)
6580 EMSG2(_("dlerror = \"%s\""), dlerr);
6581 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006582# else
6583 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
6584# endif
6585
6586 /* If the handle is valid, try to get the function address. */
6587 if (hinstLib != NULL)
6588 {
6589# ifdef HAVE_SETJMP_H
6590 /*
6591 * Catch a crash when calling the library function. For example when
6592 * using a number where a string pointer is expected.
6593 */
6594 mch_startjmp();
6595 if (SETJMP(lc_jump_env) != 0)
6596 {
6597 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006598# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006599 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006600# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006601 mch_didjmp();
6602 }
6603 else
6604# endif
6605 {
6606 retval_str = NULL;
6607 retval_int = 0;
6608
6609 if (argstring != NULL)
6610 {
6611# if defined(USE_DLOPEN)
6612 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006613 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006614# else
6615 if (shl_findsym(&hinstLib, (const char *)funcname,
6616 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
6617 ProcAdd = NULL;
6618# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006619 if ((success = (ProcAdd != NULL
6620# if defined(USE_DLOPEN)
6621 && dlerr == NULL
6622# endif
6623 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006624 {
6625 if (string_result == NULL)
6626 retval_int = ((STRPROCINT)ProcAdd)(argstring);
6627 else
6628 retval_str = (ProcAdd)(argstring);
6629 }
6630 }
6631 else
6632 {
6633# if defined(USE_DLOPEN)
6634 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006635 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006636# else
6637 if (shl_findsym(&hinstLib, (const char *)funcname,
6638 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
6639 ProcAddI = NULL;
6640# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006641 if ((success = (ProcAddI != NULL
6642# if defined(USE_DLOPEN)
6643 && dlerr == NULL
6644# endif
6645 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006646 {
6647 if (string_result == NULL)
6648 retval_int = ((INTPROCINT)ProcAddI)(argint);
6649 else
6650 retval_str = (ProcAddI)(argint);
6651 }
6652 }
6653
6654 /* Save the string before we free the library. */
6655 /* Assume that a "1" or "-1" result is an illegal pointer. */
6656 if (string_result == NULL)
6657 *number_result = retval_int;
6658 else if (retval_str != NULL
6659 && retval_str != (char_u *)1
6660 && retval_str != (char_u *)-1)
6661 *string_result = vim_strsave(retval_str);
6662 }
6663
6664# ifdef HAVE_SETJMP_H
6665 mch_endjmp();
6666# ifdef SIGHASARG
6667 if (lc_signal != 0)
6668 {
6669 int i;
6670
6671 /* try to find the name of this signal */
6672 for (i = 0; signal_info[i].sig != -1; i++)
6673 if (lc_signal == signal_info[i].sig)
6674 break;
6675 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6676 }
6677# endif
6678# endif
6679
Bram Moolenaar071d4272004-06-13 20:20:40 +00006680# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006681 /* "dlerr" must be used before dlclose() */
6682 if (dlerr != NULL)
6683 EMSG2(_("dlerror = \"%s\""), dlerr);
6684
6685 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006686 (void)dlclose(hinstLib);
6687# else
6688 (void)shl_unload(hinstLib);
6689# endif
6690 }
6691
6692 if (!success)
6693 {
6694 EMSG2(_(e_libcall), funcname);
6695 return FAIL;
6696 }
6697
6698 return OK;
6699}
6700#endif
6701
6702#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6703static int xterm_trace = -1; /* default: disabled */
6704static int xterm_button;
6705
6706/*
6707 * Setup a dummy window for X selections in a terminal.
6708 */
6709 void
6710setup_term_clip()
6711{
6712 int z = 0;
6713 char *strp = "";
6714 Widget AppShell;
6715
6716 if (!x_connect_to_server())
6717 return;
6718
6719 open_app_context();
6720 if (app_context != NULL && xterm_Shell == (Widget)0)
6721 {
6722 int (*oldhandler)();
6723#if defined(HAVE_SETJMP_H)
6724 int (*oldIOhandler)();
6725#endif
6726# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6727 struct timeval start_tv;
6728
6729 if (p_verbose > 0)
6730 gettimeofday(&start_tv, NULL);
6731# endif
6732
6733 /* Ignore X errors while opening the display */
6734 oldhandler = XSetErrorHandler(x_error_check);
6735
6736#if defined(HAVE_SETJMP_H)
6737 /* Ignore X IO errors while opening the display */
6738 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6739 mch_startjmp();
6740 if (SETJMP(lc_jump_env) != 0)
6741 {
6742 mch_didjmp();
6743 xterm_dpy = NULL;
6744 }
6745 else
6746#endif
6747 {
6748 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6749 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6750#if defined(HAVE_SETJMP_H)
6751 mch_endjmp();
6752#endif
6753 }
6754
6755#if defined(HAVE_SETJMP_H)
6756 /* Now handle X IO errors normally. */
6757 (void)XSetIOErrorHandler(oldIOhandler);
6758#endif
6759 /* Now handle X errors normally. */
6760 (void)XSetErrorHandler(oldhandler);
6761
6762 if (xterm_dpy == NULL)
6763 {
6764 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006765 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006766 return;
6767 }
6768
6769 /* Catch terminating error of the X server connection. */
6770 (void)XSetIOErrorHandler(x_IOerror_handler);
6771
6772# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6773 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006774 {
6775 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006776 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006777 verbose_leave();
6778 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006779# endif
6780
6781 /* Create a Shell to make converters work. */
6782 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6783 applicationShellWidgetClass, xterm_dpy,
6784 NULL);
6785 if (AppShell == (Widget)0)
6786 return;
6787 xterm_Shell = XtVaCreatePopupShell("VIM",
6788 topLevelShellWidgetClass, AppShell,
6789 XtNmappedWhenManaged, 0,
6790 XtNwidth, 1,
6791 XtNheight, 1,
6792 NULL);
6793 if (xterm_Shell == (Widget)0)
6794 return;
6795
6796 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02006797 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006798 if (x11_display == NULL)
6799 x11_display = xterm_dpy;
6800
6801 XtRealizeWidget(xterm_Shell);
6802 XSync(xterm_dpy, False);
6803 xterm_update();
6804 }
6805 if (xterm_Shell != (Widget)0)
6806 {
6807 clip_init(TRUE);
6808 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6809 x11_window = (Window)atol(strp);
6810 /* Check if $WINDOWID is valid. */
6811 if (test_x11_window(xterm_dpy) == FAIL)
6812 x11_window = 0;
6813 if (x11_window != 0)
6814 xterm_trace = 0;
6815 }
6816}
6817
6818 void
6819start_xterm_trace(button)
6820 int button;
6821{
6822 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6823 return;
6824 xterm_trace = 1;
6825 xterm_button = button;
6826 do_xterm_trace();
6827}
6828
6829
6830 void
6831stop_xterm_trace()
6832{
6833 if (xterm_trace < 0)
6834 return;
6835 xterm_trace = 0;
6836}
6837
6838/*
6839 * Query the xterm pointer and generate mouse termcodes if necessary
6840 * return TRUE if dragging is active, else FALSE
6841 */
6842 static int
6843do_xterm_trace()
6844{
6845 Window root, child;
6846 int root_x, root_y;
6847 int win_x, win_y;
6848 int row, col;
6849 int_u mask_return;
6850 char_u buf[50];
6851 char_u *strp;
6852 long got_hints;
6853 static char_u *mouse_code;
6854 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6855 static int prev_row = 0, prev_col = 0;
6856 static XSizeHints xterm_hints;
6857
6858 if (xterm_trace <= 0)
6859 return FALSE;
6860
6861 if (xterm_trace == 1)
6862 {
6863 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006864 * have changed recently. */
6865 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6866 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006867 || xterm_hints.width_inc <= 1
6868 || xterm_hints.height_inc <= 1)
6869 {
6870 xterm_trace = -1; /* Not enough data -- disable tracing */
6871 return FALSE;
6872 }
6873
6874 /* Rely on the same mouse code for the duration of this */
6875 mouse_code = find_termcode(mouse_name);
6876 prev_row = mouse_row;
6877 prev_row = mouse_col;
6878 xterm_trace = 2;
6879
6880 /* Find the offset of the chars, there might be a scrollbar on the
6881 * left of the window and/or a menu on the top (eterm etc.) */
6882 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6883 &win_x, &win_y, &mask_return);
6884 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6885 - (xterm_hints.height_inc / 2);
6886 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6887 xterm_hints.y = 2;
6888 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6889 - (xterm_hints.width_inc / 2);
6890 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6891 xterm_hints.x = 2;
6892 return TRUE;
6893 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006894 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006895 {
6896 xterm_trace = 0;
6897 return FALSE;
6898 }
6899
6900 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6901 &win_x, &win_y, &mask_return);
6902
6903 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6904 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6905 if (row == prev_row && col == prev_col)
6906 return TRUE;
6907
6908 STRCPY(buf, mouse_code);
6909 strp = buf + STRLEN(buf);
6910 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6911 *strp++ = (char_u)(col + ' ' + 1);
6912 *strp++ = (char_u)(row + ' ' + 1);
6913 *strp = 0;
6914 add_to_input_buf(buf, STRLEN(buf));
6915
6916 prev_row = row;
6917 prev_col = col;
6918 return TRUE;
6919}
6920
6921# if defined(FEAT_GUI) || defined(PROTO)
6922/*
6923 * Destroy the display, window and app_context. Required for GTK.
6924 */
6925 void
6926clear_xterm_clip()
6927{
6928 if (xterm_Shell != (Widget)0)
6929 {
6930 XtDestroyWidget(xterm_Shell);
6931 xterm_Shell = (Widget)0;
6932 }
6933 if (xterm_dpy != NULL)
6934 {
Bram Moolenaare8208012008-06-20 09:59:25 +00006935# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006936 /* Lesstif and Solaris crash here, lose some memory */
6937 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00006938# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006939 if (x11_display == xterm_dpy)
6940 x11_display = NULL;
6941 xterm_dpy = NULL;
6942 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006943# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006944 if (app_context != (XtAppContext)NULL)
6945 {
6946 /* Lesstif and Solaris crash here, lose some memory */
6947 XtDestroyApplicationContext(app_context);
6948 app_context = (XtAppContext)NULL;
6949 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006950# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006951}
6952# endif
6953
6954/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01006955 * Catch up with GUI or X events.
6956 */
6957 static void
6958clip_update()
6959{
6960# ifdef FEAT_GUI
6961 if (gui.in_use)
6962 gui_mch_update();
6963 else
6964# endif
6965 if (xterm_Shell != (Widget)0)
6966 xterm_update();
6967}
6968
6969/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006970 * Catch up with any queued X events. This may put keyboard input into the
6971 * input buffer, call resize call-backs, trigger timers etc. If there is
6972 * nothing in the X event queue (& no timers pending), then we return
6973 * immediately.
6974 */
6975 static void
6976xterm_update()
6977{
6978 XEvent event;
6979
6980 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6981 {
6982 XtAppNextEvent(app_context, &event);
6983#ifdef FEAT_CLIENTSERVER
6984 {
6985 XPropertyEvent *e = (XPropertyEvent *)&event;
6986
6987 if (e->type == PropertyNotify && e->window == commWindow
6988 && e->atom == commProperty && e->state == PropertyNewValue)
6989 serverEventProc(xterm_dpy, &event);
6990 }
6991#endif
6992 XtDispatchEvent(&event);
6993 }
6994}
6995
6996 int
6997clip_xterm_own_selection(cbd)
6998 VimClipboard *cbd;
6999{
7000 if (xterm_Shell != (Widget)0)
7001 return clip_x11_own_selection(xterm_Shell, cbd);
7002 return FAIL;
7003}
7004
7005 void
7006clip_xterm_lose_selection(cbd)
7007 VimClipboard *cbd;
7008{
7009 if (xterm_Shell != (Widget)0)
7010 clip_x11_lose_selection(xterm_Shell, cbd);
7011}
7012
7013 void
7014clip_xterm_request_selection(cbd)
7015 VimClipboard *cbd;
7016{
7017 if (xterm_Shell != (Widget)0)
7018 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7019}
7020
7021 void
7022clip_xterm_set_selection(cbd)
7023 VimClipboard *cbd;
7024{
7025 clip_x11_set_selection(cbd);
7026}
7027#endif
7028
7029
7030#if defined(USE_XSMP) || defined(PROTO)
7031/*
7032 * Code for X Session Management Protocol.
7033 */
7034static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
7035static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
7036static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
7037static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
7038static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
7039
7040
7041# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7042static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
7043
7044/*
7045 * This is our chance to ask the user if they want to save,
7046 * or abort the logout
7047 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007048 static void
7049xsmp_handle_interaction(smc_conn, client_data)
7050 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007051 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007052{
7053 cmdmod_T save_cmdmod;
7054 int cancel_shutdown = False;
7055
7056 save_cmdmod = cmdmod;
7057 cmdmod.confirm = TRUE;
7058 if (check_changed_any(FALSE))
7059 /* Mustn't logout */
7060 cancel_shutdown = True;
7061 cmdmod = save_cmdmod;
7062 setcursor(); /* position cursor */
7063 out_flush();
7064
7065 /* Done interaction */
7066 SmcInteractDone(smc_conn, cancel_shutdown);
7067
7068 /* Finish off
7069 * Only end save-yourself here if we're not cancelling shutdown;
7070 * we'll get a cancelled callback later in which we'll end it.
7071 * Hopefully get around glitchy SMs (like GNOME-1)
7072 */
7073 if (!cancel_shutdown)
7074 {
7075 xsmp.save_yourself = False;
7076 SmcSaveYourselfDone(smc_conn, True);
7077 }
7078}
7079# endif
7080
7081/*
7082 * Callback that starts save-yourself.
7083 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007084 static void
7085xsmp_handle_save_yourself(smc_conn, client_data, save_type,
7086 shutdown, interact_style, fast)
7087 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007088 SmPointer client_data UNUSED;
7089 int save_type UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007090 Bool shutdown;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007091 int interact_style UNUSED;
7092 Bool fast UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007093{
7094 /* Handle already being in saveyourself */
7095 if (xsmp.save_yourself)
7096 SmcSaveYourselfDone(smc_conn, True);
7097 xsmp.save_yourself = True;
7098 xsmp.shutdown = shutdown;
7099
7100 /* First up, preserve all files */
7101 out_flush();
7102 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
7103
7104 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007105 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007106
7107# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7108 /* Now see if we can ask about unsaved files */
7109 if (shutdown && !fast && gui.in_use)
7110 /* Need to interact with user, but need SM's permission */
7111 SmcInteractRequest(smc_conn, SmDialogError,
7112 xsmp_handle_interaction, client_data);
7113 else
7114# endif
7115 {
7116 /* Can stop the cycle here */
7117 SmcSaveYourselfDone(smc_conn, True);
7118 xsmp.save_yourself = False;
7119 }
7120}
7121
7122
7123/*
7124 * Callback to warn us of imminent death.
7125 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007126 static void
7127xsmp_die(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007128 SmcConn smc_conn UNUSED;
7129 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007130{
7131 xsmp_close();
7132
7133 /* quit quickly leaving swapfiles for modified buffers behind */
7134 getout_preserve_modified(0);
7135}
7136
7137
7138/*
7139 * Callback to tell us that save-yourself has completed.
7140 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007141 static void
7142xsmp_save_complete(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007143 SmcConn smc_conn UNUSED;
7144 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007145{
7146 xsmp.save_yourself = False;
7147}
7148
7149
7150/*
7151 * Callback to tell us that an instigated shutdown was cancelled
7152 * (maybe even by us)
7153 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007154 static void
7155xsmp_shutdown_cancelled(smc_conn, client_data)
7156 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007157 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007158{
7159 if (xsmp.save_yourself)
7160 SmcSaveYourselfDone(smc_conn, True);
7161 xsmp.save_yourself = False;
7162 xsmp.shutdown = False;
7163}
7164
7165
7166/*
7167 * Callback to tell us that a new ICE connection has been established.
7168 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007169 static void
7170xsmp_ice_connection(iceConn, clientData, opening, watchData)
7171 IceConn iceConn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007172 IcePointer clientData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007173 Bool opening;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007174 IcePointer *watchData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007175{
7176 /* Intercept creation of ICE connection fd */
7177 if (opening)
7178 {
7179 xsmp_icefd = IceConnectionNumber(iceConn);
7180 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7181 }
7182}
7183
7184
7185/* Handle any ICE processing that's required; return FAIL if SM lost */
7186 int
7187xsmp_handle_requests()
7188{
7189 Bool rep;
7190
7191 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7192 == IceProcessMessagesIOError)
7193 {
7194 /* Lost ICE */
7195 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007196 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007197 xsmp_close();
7198 return FAIL;
7199 }
7200 else
7201 return OK;
7202}
7203
7204static int dummy;
7205
7206/* Set up X Session Management Protocol */
7207 void
7208xsmp_init(void)
7209{
7210 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007211 SmcCallbacks smcallbacks;
7212#if 0
7213 SmPropValue smname;
7214 SmProp smnameprop;
7215 SmProp *smprops[1];
7216#endif
7217
7218 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007219 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007220
7221 xsmp.save_yourself = xsmp.shutdown = False;
7222
7223 /* Set up SM callbacks - must have all, even if they're not used */
7224 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
7225 smcallbacks.save_yourself.client_data = NULL;
7226 smcallbacks.die.callback = xsmp_die;
7227 smcallbacks.die.client_data = NULL;
7228 smcallbacks.save_complete.callback = xsmp_save_complete;
7229 smcallbacks.save_complete.client_data = NULL;
7230 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
7231 smcallbacks.shutdown_cancelled.client_data = NULL;
7232
7233 /* Set up a watch on ICE connection creations. The "dummy" argument is
7234 * apparently required for FreeBSD (we get a BUS error when using NULL). */
7235 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
7236 {
7237 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007238 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007239 return;
7240 }
7241
7242 /* Create an SM connection */
7243 xsmp.smcconn = SmcOpenConnection(
7244 NULL,
7245 NULL,
7246 SmProtoMajor,
7247 SmProtoMinor,
7248 SmcSaveYourselfProcMask | SmcDieProcMask
7249 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
7250 &smcallbacks,
7251 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00007252 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007253 sizeof(errorstring),
7254 errorstring);
7255 if (xsmp.smcconn == NULL)
7256 {
7257 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00007258
Bram Moolenaar071d4272004-06-13 20:20:40 +00007259 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007260 {
7261 vim_snprintf(errorreport, sizeof(errorreport),
7262 _("XSMP SmcOpenConnection failed: %s"), errorstring);
7263 verb_msg((char_u *)errorreport);
7264 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007265 return;
7266 }
7267 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
7268
7269#if 0
7270 /* ID ourselves */
7271 smname.value = "vim";
7272 smname.length = 3;
7273 smnameprop.name = "SmProgram";
7274 smnameprop.type = "SmARRAY8";
7275 smnameprop.num_vals = 1;
7276 smnameprop.vals = &smname;
7277
7278 smprops[0] = &smnameprop;
7279 SmcSetProperties(xsmp.smcconn, 1, smprops);
7280#endif
7281}
7282
7283
7284/* Shut down XSMP comms. */
7285 void
7286xsmp_close()
7287{
7288 if (xsmp_icefd != -1)
7289 {
7290 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00007291 if (xsmp.clientid != NULL)
7292 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00007293 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007294 xsmp_icefd = -1;
7295 }
7296}
7297#endif /* USE_XSMP */
7298
7299
7300#ifdef EBCDIC
7301/* Translate character to its CTRL- value */
7302char CtrlTable[] =
7303{
7304/* 00 - 5E */
7305 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7306 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7307 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7308 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7309 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7310 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7311/* ^ */ 0x1E,
7312/* - */ 0x1F,
7313/* 61 - 6C */
7314 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7315/* _ */ 0x1F,
7316/* 6E - 80 */
7317 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7318/* a */ 0x01,
7319/* b */ 0x02,
7320/* c */ 0x03,
7321/* d */ 0x37,
7322/* e */ 0x2D,
7323/* f */ 0x2E,
7324/* g */ 0x2F,
7325/* h */ 0x16,
7326/* i */ 0x05,
7327/* 8A - 90 */
7328 0, 0, 0, 0, 0, 0, 0,
7329/* j */ 0x15,
7330/* k */ 0x0B,
7331/* l */ 0x0C,
7332/* m */ 0x0D,
7333/* n */ 0x0E,
7334/* o */ 0x0F,
7335/* p */ 0x10,
7336/* q */ 0x11,
7337/* r */ 0x12,
7338/* 9A - A1 */
7339 0, 0, 0, 0, 0, 0, 0, 0,
7340/* s */ 0x13,
7341/* t */ 0x3C,
7342/* u */ 0x3D,
7343/* v */ 0x32,
7344/* w */ 0x26,
7345/* x */ 0x18,
7346/* y */ 0x19,
7347/* z */ 0x3F,
7348/* AA - AC */
7349 0, 0, 0,
7350/* [ */ 0x27,
7351/* AE - BC */
7352 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7353/* ] */ 0x1D,
7354/* BE - C0 */ 0, 0, 0,
7355/* A */ 0x01,
7356/* B */ 0x02,
7357/* C */ 0x03,
7358/* D */ 0x37,
7359/* E */ 0x2D,
7360/* F */ 0x2E,
7361/* G */ 0x2F,
7362/* H */ 0x16,
7363/* I */ 0x05,
7364/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
7365/* J */ 0x15,
7366/* K */ 0x0B,
7367/* L */ 0x0C,
7368/* M */ 0x0D,
7369/* N */ 0x0E,
7370/* O */ 0x0F,
7371/* P */ 0x10,
7372/* Q */ 0x11,
7373/* R */ 0x12,
7374/* DA - DF */ 0, 0, 0, 0, 0, 0,
7375/* \ */ 0x1C,
7376/* E1 */ 0,
7377/* S */ 0x13,
7378/* T */ 0x3C,
7379/* U */ 0x3D,
7380/* V */ 0x32,
7381/* W */ 0x26,
7382/* X */ 0x18,
7383/* Y */ 0x19,
7384/* Z */ 0x3F,
7385/* EA - FF*/ 0, 0, 0, 0, 0, 0,
7386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7387};
7388
7389char MetaCharTable[]=
7390{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7391 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
7392 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
7393 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
7394 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
7395};
7396
7397
7398/* TODO: Use characters NOT numbers!!! */
7399char CtrlCharTable[]=
7400{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7401 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
7402 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
7403 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
7404 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
7405};
7406
7407
7408#endif