blob: cc026534d3f1f7900cfea7a24153915ab6ca82b3 [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));
171#if defined(__BEOS__)
172int 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 Moolenaar48bae372010-07-29 23:12:15 +0200438#ifndef VMS /* VMS: must try reading, WaitForChar() does nothing. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439 /*
Bram Moolenaar48bae372010-07-29 23:12:15 +0200440 * We want to be interrupted by the winch signal
441 * or by an event on the monitored file descriptors.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000442 */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200443 if (WaitForChar(-1L) == 0)
444 {
445 if (do_resize) /* interrupted by SIGWINCH signal */
446 handle_resize();
447 return 0;
448 }
Bram Moolenaar48bae372010-07-29 23:12:15 +0200449#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000450
451 /* If input was put directly in typeahead buffer bail out here. */
452 if (typebuf_changed(tb_change_cnt))
453 return 0;
454
455 /*
456 * For some terminals we only get one character at a time.
457 * We want the get all available characters, so we could keep on
458 * trying until none is available
459 * For some other terminals this is quite slow, that's why we don't do
460 * it.
461 */
462 len = read_from_input_buf(buf, (long)maxlen);
463 if (len > 0)
464 {
465#ifdef OS2
466 int i;
467
468 for (i = 0; i < len; i++)
469 if (buf[i] == 0)
470 buf[i] = K_NUL;
471#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000472 return len;
473 }
474 }
475}
476
477 static void
478handle_resize()
479{
480 do_resize = FALSE;
481 shell_resized();
482}
483
484/*
485 * return non-zero if a character is available
486 */
487 int
488mch_char_avail()
489{
490 return WaitForChar(0L);
491}
492
493#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
494# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000495# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496# endif
497# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
498# include <sys/sysctl.h>
499# endif
500# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
501# include <sys/sysinfo.h>
502# endif
503
504/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000505 * Return total amount of memory available in Kbyte.
506 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000508 long_u
509mch_total_mem(special)
Bram Moolenaar78a15312009-05-15 19:33:18 +0000510 int special UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511{
512# ifdef __EMX__
Bram Moolenaar914572a2007-05-01 11:37:47 +0000513 return ulimit(3, 0L) >> 10; /* always 32MB? */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000514# else
515 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000516 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517
518# ifdef HAVE_SYSCTL
519 int mib[2], physmem;
520 size_t len;
521
522 /* BSD way of getting the amount of RAM available. */
523 mib[0] = CTL_HW;
524 mib[1] = HW_USERMEM;
525 len = sizeof(physmem);
526 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
527 mem = (long_u)physmem;
528# endif
529
530# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
531 if (mem == 0)
532 {
533 struct sysinfo sinfo;
534
535 /* Linux way of getting amount of RAM available */
536 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000537 {
538# ifdef HAVE_SYSINFO_MEM_UNIT
539 /* avoid overflow as much as possible */
540 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
541 {
542 sinfo.mem_unit = sinfo.mem_unit >> 1;
543 --shiftright;
544 }
545 mem = sinfo.totalram * sinfo.mem_unit;
546# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547 mem = sinfo.totalram;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000548# endif
549 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 }
551# endif
552
553# ifdef HAVE_SYSCONF
554 if (mem == 0)
555 {
556 long pagesize, pagecount;
557
558 /* Solaris way of getting amount of RAM available */
559 pagesize = sysconf(_SC_PAGESIZE);
560 pagecount = sysconf(_SC_PHYS_PAGES);
561 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000562 {
563 /* avoid overflow as much as possible */
564 while (shiftright > 0 && (pagesize & 1) == 0)
565 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000566 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000567 --shiftright;
568 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000569 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000570 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000571 }
572# endif
573
574 /* Return the minimum of the physical memory and the user limit, because
575 * using more than the user limit may cause Vim to be terminated. */
576# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
577 {
578 struct rlimit rlp;
579
580 if (getrlimit(RLIMIT_DATA, &rlp) == 0
581 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
582# ifdef RLIM_INFINITY
583 && rlp.rlim_cur != RLIM_INFINITY
584# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000585 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000586 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000587 {
588 mem = (long_u)rlp.rlim_cur;
589 shiftright = 10;
590 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000591 }
592# endif
593
594 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000595 return mem >> shiftright;
596 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597# endif
598}
599#endif
600
601 void
602mch_delay(msec, ignoreinput)
603 long msec;
604 int ignoreinput;
605{
606 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000607#ifdef FEAT_MZSCHEME
608 long total = msec; /* remember original value */
609#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610
611 if (ignoreinput)
612 {
613 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000614 * here. But we don't want QUIT to kill us (CTRL-\ used in a
615 * shell may produce SIGQUIT). */
616 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000617 old_tmode = curr_tmode;
618 if (curr_tmode == TMODE_RAW)
619 settmode(TMODE_SLEEP);
620
621 /*
622 * Everybody sleeps in a different way...
623 * Prefer nanosleep(), some versions of usleep() can only sleep up to
624 * one second.
625 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000626#ifdef FEAT_MZSCHEME
627 do
628 {
629 /* if total is large enough, wait by portions in p_mzq */
630 if (total > p_mzq)
631 msec = p_mzq;
632 else
633 msec = total;
634 total -= msec;
635#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000636#ifdef HAVE_NANOSLEEP
637 {
638 struct timespec ts;
639
640 ts.tv_sec = msec / 1000;
641 ts.tv_nsec = (msec % 1000) * 1000000;
642 (void)nanosleep(&ts, NULL);
643 }
644#else
645# ifdef HAVE_USLEEP
646 while (msec >= 1000)
647 {
648 usleep((unsigned int)(999 * 1000));
649 msec -= 999;
650 }
651 usleep((unsigned int)(msec * 1000));
652# else
653# ifndef HAVE_SELECT
654 poll(NULL, 0, (int)msec);
655# else
656# ifdef __EMX__
657 _sleep2(msec);
658# else
659 {
660 struct timeval tv;
661
662 tv.tv_sec = msec / 1000;
663 tv.tv_usec = (msec % 1000) * 1000;
664 /*
665 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
666 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
667 */
668 select(0, NULL, NULL, NULL, &tv);
669 }
670# endif /* __EMX__ */
671# endif /* HAVE_SELECT */
672# endif /* HAVE_NANOSLEEP */
673#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000674#ifdef FEAT_MZSCHEME
675 }
676 while (total > 0);
677#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000678
679 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000680 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681 }
682 else
683 WaitForChar(msec);
684}
685
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000686#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
688# define HAVE_CHECK_STACK_GROWTH
689/*
690 * Support for checking for an almost-out-of-stack-space situation.
691 */
692
693/*
694 * Return a pointer to an item on the stack. Used to find out if the stack
695 * grows up or down.
696 */
697static void check_stack_growth __ARGS((char *p));
698static int stack_grows_downwards;
699
700/*
701 * Find out if the stack grows upwards or downwards.
702 * "p" points to a variable on the stack of the caller.
703 */
704 static void
705check_stack_growth(p)
706 char *p;
707{
708 int i;
709
710 stack_grows_downwards = (p > (char *)&i);
711}
712#endif
713
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000714#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000715static char *stack_limit = NULL;
716
717#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
718# include <pthread.h>
719# include <pthread_np.h>
720#endif
721
722/*
723 * Find out until how var the stack can grow without getting into trouble.
724 * Called when starting up and when switching to the signal stack in
725 * deathtrap().
726 */
727 static void
728get_stack_limit()
729{
730 struct rlimit rlp;
731 int i;
732 long lim;
733
734 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
735 * limit doesn't fit in a long (rlim_cur might be "long long"). */
736 if (getrlimit(RLIMIT_STACK, &rlp) == 0
737 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
738# ifdef RLIM_INFINITY
739 && rlp.rlim_cur != RLIM_INFINITY
740# endif
741 )
742 {
743 lim = (long)rlp.rlim_cur;
744#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
745 {
746 pthread_attr_t attr;
747 size_t size;
748
749 /* On FreeBSD the initial thread always has a fixed stack size, no
750 * matter what the limits are set to. Normally it's 1 Mbyte. */
751 pthread_attr_init(&attr);
752 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
753 {
754 pthread_attr_getstacksize(&attr, &size);
755 if (lim > (long)size)
756 lim = (long)size;
757 }
758 pthread_attr_destroy(&attr);
759 }
760#endif
761 if (stack_grows_downwards)
762 {
763 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
764 if (stack_limit >= (char *)&i)
765 /* overflow, set to 1/16 of current stack position */
766 stack_limit = (char *)((long)&i / 16L);
767 }
768 else
769 {
770 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
771 if (stack_limit <= (char *)&i)
772 stack_limit = NULL; /* overflow */
773 }
774 }
775}
776
777/*
778 * Return FAIL when running out of stack space.
779 * "p" must point to any variable local to the caller that's on the stack.
780 */
781 int
782mch_stackcheck(p)
783 char *p;
784{
785 if (stack_limit != NULL)
786 {
787 if (stack_grows_downwards)
788 {
789 if (p < stack_limit)
790 return FAIL;
791 }
792 else if (p > stack_limit)
793 return FAIL;
794 }
795 return OK;
796}
797#endif
798
799#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
800/*
801 * Support for using the signal stack.
802 * This helps when we run out of stack space, which causes a SIGSEGV. The
803 * signal handler then must run on another stack, since the normal stack is
804 * completely full.
805 */
806
807#ifndef SIGSTKSZ
808# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
809#endif
810
811# ifdef HAVE_SIGALTSTACK
812static stack_t sigstk; /* for sigaltstack() */
813# else
814static struct sigstack sigstk; /* for sigstack() */
815# endif
816
817static void init_signal_stack __ARGS((void));
818static char *signal_stack;
819
820 static void
821init_signal_stack()
822{
823 if (signal_stack != NULL)
824 {
825# ifdef HAVE_SIGALTSTACK
Bram Moolenaar1a3d0862007-08-30 09:47:38 +0000826# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
827 || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000828 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
829 * "struct sigaltstack" needs to be declared. */
830 extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
831# endif
832
833# ifdef HAVE_SS_BASE
834 sigstk.ss_base = signal_stack;
835# else
836 sigstk.ss_sp = signal_stack;
837# endif
838 sigstk.ss_size = SIGSTKSZ;
839 sigstk.ss_flags = 0;
840 (void)sigaltstack(&sigstk, NULL);
841# else
842 sigstk.ss_sp = signal_stack;
843 if (stack_grows_downwards)
844 sigstk.ss_sp += SIGSTKSZ - 1;
845 sigstk.ss_onstack = 0;
846 (void)sigstack(&sigstk, NULL);
847# endif
848 }
849}
850#endif
851
852/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000853 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854 * will barf when the second argument to signal() is ``wrong''.
855 * Let me try it with a few tricky defines from my own osdef.h (jw).
856 */
857#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000858 static RETSIGTYPE
859sig_winch SIGDEFARG(sigarg)
860{
861 /* this is not required on all systems, but it doesn't hurt anybody */
862 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
863 do_resize = TRUE;
864 SIGRETURN;
865}
866#endif
867
868#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 static RETSIGTYPE
870catch_sigint SIGDEFARG(sigarg)
871{
872 /* this is not required on all systems, but it doesn't hurt anybody */
873 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
874 got_int = TRUE;
875 SIGRETURN;
876}
877#endif
878
879#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 static RETSIGTYPE
881catch_sigpwr SIGDEFARG(sigarg)
882{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000883 /* this is not required on all systems, but it doesn't hurt anybody */
884 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885 /*
886 * I'm not sure we get the SIGPWR signal when the system is really going
887 * down or when the batteries are almost empty. Just preserve the swap
888 * files and don't exit, that can't do any harm.
889 */
890 ml_sync_all(FALSE, FALSE);
891 SIGRETURN;
892}
893#endif
894
895#ifdef SET_SIG_ALARM
896/*
897 * signal function for alarm().
898 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000899 static RETSIGTYPE
900sig_alarm SIGDEFARG(sigarg)
901{
902 /* doesn't do anything, just to break a system call */
903 sig_alarm_called = TRUE;
904 SIGRETURN;
905}
906#endif
907
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000908#if (defined(HAVE_SETJMP_H) \
909 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
910 || defined(FEAT_LIBCALL))) \
911 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000912/*
913 * A simplistic version of setjmp() that only allows one level of using.
914 * Don't call twice before calling mch_endjmp()!.
915 * Usage:
916 * mch_startjmp();
917 * if (SETJMP(lc_jump_env) != 0)
918 * {
919 * mch_didjmp();
920 * EMSG("crash!");
921 * }
922 * else
923 * {
924 * do_the_work;
925 * mch_endjmp();
926 * }
927 * Note: Can't move SETJMP() here, because a function calling setjmp() must
928 * not return before the saved environment is used.
929 * Returns OK for normal return, FAIL when the protected code caused a
930 * problem and LONGJMP() was used.
931 */
932 void
933mch_startjmp()
934{
935#ifdef SIGHASARG
936 lc_signal = 0;
937#endif
938 lc_active = TRUE;
939}
940
941 void
942mch_endjmp()
943{
944 lc_active = FALSE;
945}
946
947 void
948mch_didjmp()
949{
950# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
951 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
952 * otherwise catching the signal only works once. */
953 init_signal_stack();
954# endif
955}
956#endif
957
958/*
959 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200960 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000961 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200962 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
963 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000964 */
965 static RETSIGTYPE
966deathtrap SIGDEFARG(sigarg)
967{
968 static int entered = 0; /* count the number of times we got here.
969 Note: when memory has been corrupted
970 this may get an arbitrary value! */
971#ifdef SIGHASARG
972 int i;
973#endif
974
975#if defined(HAVE_SETJMP_H)
976 /*
977 * Catch a crash in protected code.
978 * Restores the environment saved in lc_jump_env, which looks like
979 * SETJMP() returns 1.
980 */
981 if (lc_active)
982 {
983# if defined(SIGHASARG)
984 lc_signal = sigarg;
985# endif
986 lc_active = FALSE; /* don't jump again */
987 LONGJMP(lc_jump_env, 1);
988 /* NOTREACHED */
989 }
990#endif
991
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000992#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000993# ifdef SIGQUIT
994 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
995 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
996 * pressing CTRL-\, but we don't want Vim to exit then. */
997 if (in_mch_delay && sigarg == SIGQUIT)
998 SIGRETURN;
999# endif
1000
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001001 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
1002 * here. This avoids that a non-reentrant function is interrupted, e.g.,
1003 * free(). Calling free() again may then cause a crash. */
1004 if (entered == 0
1005 && (0
1006# ifdef SIGHUP
1007 || sigarg == SIGHUP
1008# endif
1009# ifdef SIGQUIT
1010 || sigarg == SIGQUIT
1011# endif
1012# ifdef SIGTERM
1013 || sigarg == SIGTERM
1014# endif
1015# ifdef SIGPWR
1016 || sigarg == SIGPWR
1017# endif
1018# ifdef SIGUSR1
1019 || sigarg == SIGUSR1
1020# endif
1021# ifdef SIGUSR2
1022 || sigarg == SIGUSR2
1023# endif
1024 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001025 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001026 SIGRETURN;
1027#endif
1028
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029 /* Remember how often we have been called. */
1030 ++entered;
1031
1032#ifdef FEAT_EVAL
1033 /* Set the v:dying variable. */
1034 set_vim_var_nr(VV_DYING, (long)entered);
1035#endif
1036
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001037#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001038 /* Since we are now using the signal stack, need to reset the stack
1039 * limit. Otherwise using a regexp will fail. */
1040 get_stack_limit();
1041#endif
1042
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001043#if 0
1044 /* This is for opening gdb the moment Vim crashes.
1045 * You need to manually adjust the file name and Vim executable name.
1046 * Suggested by SungHyun Nam. */
1047 {
1048# define VI_GDB_FILE "/tmp/vimgdb"
1049# define VIM_NAME "/usr/bin/vim"
1050 FILE *fp = fopen(VI_GDB_FILE, "w");
1051 if (fp)
1052 {
1053 fprintf(fp,
1054 "file %s\n"
1055 "attach %d\n"
1056 "set height 1000\n"
1057 "bt full\n"
1058 , VIM_NAME, getpid());
1059 fclose(fp);
1060 system("xterm -e gdb -x "VI_GDB_FILE);
1061 unlink(VI_GDB_FILE);
1062 }
1063 }
1064#endif
1065
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066#ifdef SIGHASARG
1067 /* try to find the name of this signal */
1068 for (i = 0; signal_info[i].sig != -1; i++)
1069 if (sigarg == signal_info[i].sig)
1070 break;
1071 deadly_signal = sigarg;
1072#endif
1073
1074 full_screen = FALSE; /* don't write message to the GUI, it might be
1075 * part of the problem... */
1076 /*
1077 * If something goes wrong after entering here, we may get here again.
1078 * When this happens, give a message and try to exit nicely (resetting the
1079 * terminal mode, etc.)
1080 * When this happens twice, just exit, don't even try to give a message,
1081 * stack may be corrupt or something weird.
1082 * When this still happens again (or memory was corrupted in such a way
1083 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1084 */
1085 if (entered >= 3)
1086 {
1087 reset_signals(); /* don't catch any signals anymore */
1088 may_core_dump();
1089 if (entered >= 4)
1090 _exit(8);
1091 exit(7);
1092 }
1093 if (entered == 2)
1094 {
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001095 /* No translation, it may call malloc(). */
1096 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097 out_flush();
1098 getout(1);
1099 }
1100
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001101 /* No translation, it may call malloc(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001102#ifdef SIGHASARG
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001103 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104 signal_info[i].name);
1105#else
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001106 sprintf((char *)IObuff, "Vim: Caught deadly signal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001107#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001108
1109 /* Preserve files and exit. This sets the really_exiting flag to prevent
1110 * calling free(). */
1111 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112
Bram Moolenaar009b2592004-10-24 19:18:58 +00001113#ifdef NBDEBUG
1114 reset_signals();
1115 may_core_dump();
1116 abort();
1117#endif
1118
Bram Moolenaar071d4272004-06-13 20:20:40 +00001119 SIGRETURN;
1120}
1121
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001122#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001123/*
1124 * On Solaris with multi-threading, suspending might not work immediately.
1125 * Catch the SIGCONT signal, which will be used as an indication whether the
1126 * suspending has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001127 *
1128 * On Linux, signal is not always handled immediately either.
1129 * See https://bugs.launchpad.net/bugs/291373
1130 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001131 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001132 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001133static volatile int sigcont_received;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001134static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1135
1136/*
1137 * signal handler for SIGCONT
1138 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001139 static RETSIGTYPE
1140sigcont_handler SIGDEFARG(sigarg)
1141{
1142 sigcont_received = TRUE;
1143 SIGRETURN;
1144}
1145#endif
1146
Bram Moolenaar62b42182010-09-21 22:09:37 +02001147# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1148static void loose_clipboard __ARGS((void));
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001149# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001150static void save_clipboard __ARGS((void));
1151static void restore_clipboard __ARGS((void));
1152
1153static void *clip_star_save = NULL;
1154static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001155# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001156
1157/*
1158 * Called when Vim is going to sleep or execute a shell command.
1159 * We can't respond to requests for the X selections. Lose them, otherwise
1160 * other applications will hang. But first copy the text to cut buffer 0.
1161 */
1162 static void
1163loose_clipboard()
1164{
1165 if (clip_star.owned || clip_plus.owned)
1166 {
1167 x11_export_final_selection();
1168 if (clip_star.owned)
1169 clip_lose_selection(&clip_star);
1170 if (clip_plus.owned)
1171 clip_lose_selection(&clip_plus);
1172 if (x11_display != NULL)
1173 XFlush(x11_display);
1174 }
1175}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001176
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001177# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001178/*
1179 * Save clipboard text to restore later.
1180 */
1181 static void
1182save_clipboard()
1183{
1184 if (clip_star.owned)
1185 clip_star_save = get_register('*', TRUE);
1186 if (clip_plus.owned)
1187 clip_plus_save = get_register('+', TRUE);
1188}
1189
1190/*
1191 * Restore clipboard text if no one own the X selection.
1192 */
1193 static void
1194restore_clipboard()
1195{
1196 if (clip_star_save != NULL)
1197 {
1198 if (!clip_gen_owner_exists(&clip_star))
1199 put_register('*', clip_star_save);
1200 else
1201 free_register(clip_star_save);
1202 clip_star_save = NULL;
1203 }
1204 if (clip_plus_save != NULL)
1205 {
1206 if (!clip_gen_owner_exists(&clip_plus))
1207 put_register('+', clip_plus_save);
1208 else
1209 free_register(clip_plus_save);
1210 clip_plus_save = NULL;
1211 }
1212}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001213# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001214#endif
1215
Bram Moolenaar071d4272004-06-13 20:20:40 +00001216/*
1217 * If the machine has job control, use it to suspend the program,
1218 * otherwise fake it by starting a new shell.
1219 */
1220 void
1221mch_suspend()
1222{
1223 /* BeOS does have SIGTSTP, but it doesn't work. */
1224#if defined(SIGTSTP) && !defined(__BEOS__)
1225 out_flush(); /* needed to make cursor visible on some systems */
1226 settmode(TMODE_COOK);
1227 out_flush(); /* needed to disable mouse on some systems */
1228
1229# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001230 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001231# endif
1232
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001233# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001234 sigcont_received = FALSE;
1235# endif
1236 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001237# if defined(_REENTRANT) && defined(SIGCONT)
1238 /*
1239 * Wait for the SIGCONT signal to be handled. It generally happens
1240 * immediately, but somehow not all the time. Do not call pause()
1241 * because there would be race condition which would hang Vim if
1242 * signal happened in between the test of sigcont_received and the
1243 * call to pause(). If signal is not yet received, call sleep(0)
1244 * to just yield CPU. Signal should then be received. If somehow
1245 * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
1246 * further if signal is not received after 1+2+3+4 ms (not expected
1247 * to happen).
1248 */
1249 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001250 long wait_time;
1251 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001252 /* Loop is not entered most of the time */
Bram Moolenaar262735e2009-07-14 10:20:22 +00001253 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001254 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001255# endif
1256
1257# ifdef FEAT_TITLE
1258 /*
1259 * Set oldtitle to NULL, so the current title is obtained again.
1260 */
1261 vim_free(oldtitle);
1262 oldtitle = NULL;
1263# endif
1264 settmode(TMODE_RAW);
1265 need_check_timestamps = TRUE;
1266 did_check_timestamps = FALSE;
1267#else
1268 suspend_shell();
1269#endif
1270}
1271
1272 void
1273mch_init()
1274{
1275 Columns = 80;
1276 Rows = 24;
1277
1278 out_flush();
1279 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001280
Bram Moolenaar56718732006-03-15 22:53:57 +00001281#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001282 mac_conv_init();
1283#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001284#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1285 win_clip_init();
1286#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287}
1288
1289 static void
1290set_signals()
1291{
1292#if defined(SIGWINCH)
1293 /*
1294 * WINDOW CHANGE signal is handled with sig_winch().
1295 */
1296 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1297#endif
1298
1299 /*
1300 * We want the STOP signal to work, to make mch_suspend() work.
1301 * For "rvim" the STOP signal is ignored.
1302 */
1303#ifdef SIGTSTP
1304 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1305#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001306#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307 signal(SIGCONT, sigcont_handler);
1308#endif
1309
1310 /*
1311 * We want to ignore breaking of PIPEs.
1312 */
1313#ifdef SIGPIPE
1314 signal(SIGPIPE, SIG_IGN);
1315#endif
1316
Bram Moolenaar071d4272004-06-13 20:20:40 +00001317#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001318 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001319#endif
1320
1321 /*
1322 * Ignore alarm signals (Perl's alarm() generates it).
1323 */
1324#ifdef SIGALRM
1325 signal(SIGALRM, SIG_IGN);
1326#endif
1327
1328 /*
1329 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1330 * work will be lost.
1331 */
1332#ifdef SIGPWR
1333 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1334#endif
1335
1336 /*
1337 * Arrange for other signals to gracefully shutdown Vim.
1338 */
1339 catch_signals(deathtrap, SIG_ERR);
1340
1341#if defined(FEAT_GUI) && defined(SIGHUP)
1342 /*
1343 * When the GUI is running, ignore the hangup signal.
1344 */
1345 if (gui.in_use)
1346 signal(SIGHUP, SIG_IGN);
1347#endif
1348}
1349
Bram Moolenaardf177f62005-02-22 08:39:57 +00001350#if defined(SIGINT) || defined(PROTO)
1351/*
1352 * Catch CTRL-C (only works while in Cooked mode).
1353 */
1354 static void
1355catch_int_signal()
1356{
1357 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1358}
1359#endif
1360
Bram Moolenaar071d4272004-06-13 20:20:40 +00001361 void
1362reset_signals()
1363{
1364 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001365#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001366 /* SIGCONT isn't in the list, because its default action is ignore */
1367 signal(SIGCONT, SIG_DFL);
1368#endif
1369}
1370
1371 static void
1372catch_signals(func_deadly, func_other)
1373 RETSIGTYPE (*func_deadly)();
1374 RETSIGTYPE (*func_other)();
1375{
1376 int i;
1377
1378 for (i = 0; signal_info[i].sig != -1; i++)
1379 if (signal_info[i].deadly)
1380 {
1381#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1382 struct sigaction sa;
1383
1384 /* Setup to use the alternate stack for the signal function. */
1385 sa.sa_handler = func_deadly;
1386 sigemptyset(&sa.sa_mask);
1387# if defined(__linux__) && defined(_REENTRANT)
1388 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1389 * thread handling in combination with using the alternate stack:
1390 * pthread library functions try to use the stack pointer to
1391 * identify the current thread, causing a SEGV signal, which
1392 * recursively calls deathtrap() and hangs. */
1393 sa.sa_flags = 0;
1394# else
1395 sa.sa_flags = SA_ONSTACK;
1396# endif
1397 sigaction(signal_info[i].sig, &sa, NULL);
1398#else
1399# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1400 struct sigvec sv;
1401
1402 /* Setup to use the alternate stack for the signal function. */
1403 sv.sv_handler = func_deadly;
1404 sv.sv_mask = 0;
1405 sv.sv_flags = SV_ONSTACK;
1406 sigvec(signal_info[i].sig, &sv, NULL);
1407# else
1408 signal(signal_info[i].sig, func_deadly);
1409# endif
1410#endif
1411 }
1412 else if (func_other != SIG_ERR)
1413 signal(signal_info[i].sig, func_other);
1414}
1415
1416/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001417 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001418 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1419 * return TRUE
1420 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1421 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001422 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001423 * Returns TRUE when Vim should exit.
1424 */
1425 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001426vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001427 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001428{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001429 static int got_signal = 0;
1430 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001431
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001432 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001433 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001434 case SIGNAL_BLOCK: blocked = TRUE;
1435 break;
1436
1437 case SIGNAL_UNBLOCK: blocked = FALSE;
1438 if (got_signal != 0)
1439 {
1440 kill(getpid(), got_signal);
1441 got_signal = 0;
1442 }
1443 break;
1444
1445 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001446 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001447 got_signal = sig;
1448#ifdef SIGPWR
1449 if (sig != SIGPWR)
1450#endif
1451 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001452 break;
1453 }
1454 return FALSE;
1455}
1456
1457/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001458 * Check_win checks whether we have an interactive stdout.
1459 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001460 int
1461mch_check_win(argc, argv)
Bram Moolenaar78a15312009-05-15 19:33:18 +00001462 int argc UNUSED;
1463 char **argv UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001464{
1465#ifdef OS2
1466 /*
1467 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1468 * name, mostly it's just "vim" and found in the path, which is unusable.
1469 */
1470 if (mch_isFullName(argv[0]))
1471 exe_name = vim_strsave((char_u *)argv[0]);
1472#endif
1473 if (isatty(1))
1474 return OK;
1475 return FAIL;
1476}
1477
1478/*
1479 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1480 */
1481 int
1482mch_input_isatty()
1483{
1484 if (isatty(read_cmd_fd))
1485 return TRUE;
1486 return FALSE;
1487}
1488
1489#ifdef FEAT_X11
1490
1491# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1492 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1493
1494static void xopen_message __ARGS((struct timeval *tvp));
1495
1496/*
1497 * Give a message about the elapsed time for opening the X window.
1498 */
1499 static void
1500xopen_message(tvp)
1501 struct timeval *tvp; /* must contain start time */
1502{
1503 struct timeval end_tv;
1504
1505 /* Compute elapsed time. */
1506 gettimeofday(&end_tv, NULL);
1507 smsg((char_u *)_("Opening the X display took %ld msec"),
1508 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001509 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001510}
1511# endif
1512#endif
1513
1514#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1515/*
1516 * A few functions shared by X11 title and clipboard code.
1517 */
1518static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1519static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1520static int x_connect_to_server __ARGS((void));
1521static int test_x11_window __ARGS((Display *dpy));
1522
1523static int got_x_error = FALSE;
1524
1525/*
1526 * X Error handler, otherwise X just exits! (very rude) -- webb
1527 */
1528 static int
1529x_error_handler(dpy, error_event)
1530 Display *dpy;
1531 XErrorEvent *error_event;
1532{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001533 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001534 STRCAT(IObuff, _("\nVim: Got X error\n"));
1535
1536 /* We cannot print a message and continue, because no X calls are allowed
1537 * here (causes my system to hang). Silently continuing might be an
1538 * alternative... */
1539 preserve_exit(); /* preserve files and exit */
1540
1541 return 0; /* NOTREACHED */
1542}
1543
1544/*
1545 * Another X Error handler, just used to check for errors.
1546 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001547 static int
1548x_error_check(dpy, error_event)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001549 Display *dpy UNUSED;
1550 XErrorEvent *error_event UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001551{
1552 got_x_error = TRUE;
1553 return 0;
1554}
1555
1556#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1557# if defined(HAVE_SETJMP_H)
1558/*
1559 * An X IO Error handler, used to catch error while opening the display.
1560 */
1561static int x_IOerror_check __ARGS((Display *dpy));
1562
Bram Moolenaar071d4272004-06-13 20:20:40 +00001563 static int
1564x_IOerror_check(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001565 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001566{
1567 /* This function should not return, it causes exit(). Longjump instead. */
1568 LONGJMP(lc_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001569# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001570 return 0; /* avoid the compiler complains about missing return value */
1571# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001572}
1573# endif
1574
1575/*
1576 * An X IO Error handler, used to catch terminal errors.
1577 */
1578static int x_IOerror_handler __ARGS((Display *dpy));
1579
Bram Moolenaar071d4272004-06-13 20:20:40 +00001580 static int
1581x_IOerror_handler(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001582 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001583{
1584 xterm_dpy = NULL;
1585 x11_window = 0;
1586 x11_display = NULL;
1587 xterm_Shell = (Widget)0;
1588
1589 /* This function should not return, it causes exit(). Longjump instead. */
1590 LONGJMP(x_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001591# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001592 return 0; /* avoid the compiler complains about missing return value */
1593# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001594}
1595#endif
1596
1597/*
1598 * Return TRUE when connection to the X server is desired.
1599 */
1600 static int
1601x_connect_to_server()
1602{
1603 regmatch_T regmatch;
1604
1605#if defined(FEAT_CLIENTSERVER)
1606 if (x_force_connect)
1607 return TRUE;
1608#endif
1609 if (x_no_connect)
1610 return FALSE;
1611
1612 /* Check for a match with "exclude:" from 'clipboard'. */
1613 if (clip_exclude_prog != NULL)
1614 {
1615 regmatch.rm_ic = FALSE; /* Don't ignore case */
1616 regmatch.regprog = clip_exclude_prog;
1617 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1618 return FALSE;
1619 }
1620 return TRUE;
1621}
1622
1623/*
1624 * Test if "dpy" and x11_window are valid by getting the window title.
1625 * I don't actually want it yet, so there may be a simpler call to use, but
1626 * this will cause the error handler x_error_check() to be called if anything
1627 * is wrong, such as the window pointer being invalid (as can happen when the
1628 * user changes his DISPLAY, but not his WINDOWID) -- webb
1629 */
1630 static int
1631test_x11_window(dpy)
1632 Display *dpy;
1633{
1634 int (*old_handler)();
1635 XTextProperty text_prop;
1636
1637 old_handler = XSetErrorHandler(x_error_check);
1638 got_x_error = FALSE;
1639 if (XGetWMName(dpy, x11_window, &text_prop))
1640 XFree((void *)text_prop.value);
1641 XSync(dpy, False);
1642 (void)XSetErrorHandler(old_handler);
1643
1644 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001645 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001646
1647 return (got_x_error ? FAIL : OK);
1648}
1649#endif
1650
1651#ifdef FEAT_TITLE
1652
1653#ifdef FEAT_X11
1654
1655static int get_x11_thing __ARGS((int get_title, int test_only));
1656
1657/*
1658 * try to get x11 window and display
1659 *
1660 * return FAIL for failure, OK otherwise
1661 */
1662 static int
1663get_x11_windis()
1664{
1665 char *winid;
1666 static int result = -1;
1667#define XD_NONE 0 /* x11_display not set here */
1668#define XD_HERE 1 /* x11_display opened here */
1669#define XD_GUI 2 /* x11_display used from gui.dpy */
1670#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1671 static int x11_display_from = XD_NONE;
1672 static int did_set_error_handler = FALSE;
1673
1674 if (!did_set_error_handler)
1675 {
1676 /* X just exits if it finds an error otherwise! */
1677 (void)XSetErrorHandler(x_error_handler);
1678 did_set_error_handler = TRUE;
1679 }
1680
Bram Moolenaar9372a112005-12-06 19:59:18 +00001681#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001682 if (gui.in_use)
1683 {
1684 /*
1685 * If the X11 display was opened here before, for the window where Vim
1686 * was started, close that one now to avoid a memory leak.
1687 */
1688 if (x11_display_from == XD_HERE && x11_display != NULL)
1689 {
1690 XCloseDisplay(x11_display);
1691 x11_display_from = XD_NONE;
1692 }
1693 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1694 {
1695 x11_display_from = XD_GUI;
1696 return OK;
1697 }
1698 x11_display = NULL;
1699 return FAIL;
1700 }
1701 else if (x11_display_from == XD_GUI)
1702 {
1703 /* GUI must have stopped somehow, clear x11_display */
1704 x11_window = 0;
1705 x11_display = NULL;
1706 x11_display_from = XD_NONE;
1707 }
1708#endif
1709
1710 /* When started with the "-X" argument, don't try connecting. */
1711 if (!x_connect_to_server())
1712 return FAIL;
1713
1714 /*
1715 * If WINDOWID not set, should try another method to find out
1716 * what the current window number is. The only code I know for
1717 * this is very complicated.
1718 * We assume that zero is invalid for WINDOWID.
1719 */
1720 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1721 x11_window = (Window)atol(winid);
1722
1723#ifdef FEAT_XCLIPBOARD
1724 if (xterm_dpy != NULL && x11_window != 0)
1725 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001726 /* We may have checked it already, but Gnome terminal can move us to
1727 * another window, so we need to check every time. */
1728 if (x11_display_from != XD_XTERM)
1729 {
1730 /*
1731 * If the X11 display was opened here before, for the window where
1732 * Vim was started, close that one now to avoid a memory leak.
1733 */
1734 if (x11_display_from == XD_HERE && x11_display != NULL)
1735 XCloseDisplay(x11_display);
1736 x11_display = xterm_dpy;
1737 x11_display_from = XD_XTERM;
1738 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001739 if (test_x11_window(x11_display) == FAIL)
1740 {
1741 /* probably bad $WINDOWID */
1742 x11_window = 0;
1743 x11_display = NULL;
1744 x11_display_from = XD_NONE;
1745 return FAIL;
1746 }
1747 return OK;
1748 }
1749#endif
1750
1751 if (x11_window == 0 || x11_display == NULL)
1752 result = -1;
1753
1754 if (result != -1) /* Have already been here and set this */
1755 return result; /* Don't do all these X calls again */
1756
1757 if (x11_window != 0 && x11_display == NULL)
1758 {
1759#ifdef SET_SIG_ALARM
1760 RETSIGTYPE (*sig_save)();
1761#endif
1762#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1763 struct timeval start_tv;
1764
1765 if (p_verbose > 0)
1766 gettimeofday(&start_tv, NULL);
1767#endif
1768
1769#ifdef SET_SIG_ALARM
1770 /*
1771 * Opening the Display may hang if the DISPLAY setting is wrong, or
1772 * the network connection is bad. Set an alarm timer to get out.
1773 */
1774 sig_alarm_called = FALSE;
1775 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1776 (RETSIGTYPE (*)())sig_alarm);
1777 alarm(2);
1778#endif
1779 x11_display = XOpenDisplay(NULL);
1780
1781#ifdef SET_SIG_ALARM
1782 alarm(0);
1783 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1784 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001785 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001786#endif
1787 if (x11_display != NULL)
1788 {
1789# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1790 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001791 {
1792 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001794 verbose_leave();
1795 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001796# endif
1797 if (test_x11_window(x11_display) == FAIL)
1798 {
1799 /* Maybe window id is bad */
1800 x11_window = 0;
1801 XCloseDisplay(x11_display);
1802 x11_display = NULL;
1803 }
1804 else
1805 x11_display_from = XD_HERE;
1806 }
1807 }
1808 if (x11_window == 0 || x11_display == NULL)
1809 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001810
1811# ifdef FEAT_EVAL
1812 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1813# endif
1814
Bram Moolenaar071d4272004-06-13 20:20:40 +00001815 return (result = OK);
1816}
1817
1818/*
1819 * Determine original x11 Window Title
1820 */
1821 static int
1822get_x11_title(test_only)
1823 int test_only;
1824{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001825 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826}
1827
1828/*
1829 * Determine original x11 Window icon
1830 */
1831 static int
1832get_x11_icon(test_only)
1833 int test_only;
1834{
1835 int retval = FALSE;
1836
1837 retval = get_x11_thing(FALSE, test_only);
1838
1839 /* could not get old icon, use terminal name */
1840 if (oldicon == NULL && !test_only)
1841 {
1842 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001843 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001844 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001845 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001846 }
1847
1848 return retval;
1849}
1850
1851 static int
1852get_x11_thing(get_title, test_only)
1853 int get_title; /* get title string */
1854 int test_only;
1855{
1856 XTextProperty text_prop;
1857 int retval = FALSE;
1858 Status status;
1859
1860 if (get_x11_windis() == OK)
1861 {
1862 /* Get window/icon name if any */
1863 if (get_title)
1864 status = XGetWMName(x11_display, x11_window, &text_prop);
1865 else
1866 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1867
1868 /*
1869 * If terminal is xterm, then x11_window may be a child window of the
1870 * outer xterm window that actually contains the window/icon name, so
1871 * keep traversing up the tree until a window with a title/icon is
1872 * found.
1873 */
1874 /* Previously this was only done for xterm and alikes. I don't see a
1875 * reason why it would fail for other terminal emulators.
1876 * if (term_is_xterm) */
1877 {
1878 Window root;
1879 Window parent;
1880 Window win = x11_window;
1881 Window *children;
1882 unsigned int num_children;
1883
1884 while (!status || text_prop.value == NULL)
1885 {
1886 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1887 &num_children))
1888 break;
1889 if (children)
1890 XFree((void *)children);
1891 if (parent == root || parent == 0)
1892 break;
1893
1894 win = parent;
1895 if (get_title)
1896 status = XGetWMName(x11_display, win, &text_prop);
1897 else
1898 status = XGetWMIconName(x11_display, win, &text_prop);
1899 }
1900 }
1901 if (status && text_prop.value != NULL)
1902 {
1903 retval = TRUE;
1904 if (!test_only)
1905 {
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001906#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
1907 if (text_prop.encoding == XA_STRING
1908# ifdef FEAT_MBYTE
1909 && !has_mbyte
1910# endif
1911 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912 {
1913#endif
1914 if (get_title)
1915 oldtitle = vim_strsave((char_u *)text_prop.value);
1916 else
1917 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001918#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001919 }
1920 else
1921 {
1922 char **cl;
1923 Status transform_status;
1924 int n = 0;
1925
1926 transform_status = XmbTextPropertyToTextList(x11_display,
1927 &text_prop,
1928 &cl, &n);
1929 if (transform_status >= Success && n > 0 && cl[0])
1930 {
1931 if (get_title)
1932 oldtitle = vim_strsave((char_u *) cl[0]);
1933 else
1934 oldicon = vim_strsave((char_u *) cl[0]);
1935 XFreeStringList(cl);
1936 }
1937 else
1938 {
1939 if (get_title)
1940 oldtitle = vim_strsave((char_u *)text_prop.value);
1941 else
1942 oldicon = vim_strsave((char_u *)text_prop.value);
1943 }
1944 }
1945#endif
1946 }
1947 XFree((void *)text_prop.value);
1948 }
1949 }
1950 return retval;
1951}
1952
1953/* Are Xutf8 functions available? Avoid error from old compilers. */
1954#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1955# if X_HAVE_UTF8_STRING
1956# define USE_UTF8_STRING
1957# endif
1958#endif
1959
1960/*
1961 * Set x11 Window Title
1962 *
1963 * get_x11_windis() must be called before this and have returned OK
1964 */
1965 static void
1966set_x11_title(title)
1967 char_u *title;
1968{
1969 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1970 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1971 * supported everywhere and STRING doesn't work for multi-byte titles.
1972 */
1973#ifdef USE_UTF8_STRING
1974 if (enc_utf8)
1975 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1976 NULL, NULL, 0, NULL, NULL, NULL);
1977 else
1978#endif
1979 {
1980#if XtSpecificationRelease >= 4
1981# ifdef FEAT_XFONTSET
1982 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1983 NULL, NULL, 0, NULL, NULL, NULL);
1984# else
1985 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001986 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001987
1988 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001989 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001990 XSetWMProperties(x11_display, x11_window, &text_prop,
1991 NULL, NULL, 0, NULL, NULL, NULL);
1992# endif
1993#else
1994 XStoreName(x11_display, x11_window, (char *)title);
1995#endif
1996 }
1997 XFlush(x11_display);
1998}
1999
2000/*
2001 * Set x11 Window icon
2002 *
2003 * get_x11_windis() must be called before this and have returned OK
2004 */
2005 static void
2006set_x11_icon(icon)
2007 char_u *icon;
2008{
2009 /* See above for comments about using X*SetWMProperties(). */
2010#ifdef USE_UTF8_STRING
2011 if (enc_utf8)
2012 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2013 NULL, 0, NULL, NULL, NULL);
2014 else
2015#endif
2016 {
2017#if XtSpecificationRelease >= 4
2018# ifdef FEAT_XFONTSET
2019 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2020 NULL, 0, NULL, NULL, NULL);
2021# else
2022 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002023 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002024
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002025 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002026 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2027 NULL, 0, NULL, NULL, NULL);
2028# endif
2029#else
2030 XSetIconName(x11_display, x11_window, (char *)icon);
2031#endif
2032 }
2033 XFlush(x11_display);
2034}
2035
2036#else /* FEAT_X11 */
2037
Bram Moolenaar071d4272004-06-13 20:20:40 +00002038 static int
2039get_x11_title(test_only)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002040 int test_only UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002041{
2042 return FALSE;
2043}
2044
2045 static int
2046get_x11_icon(test_only)
2047 int test_only;
2048{
2049 if (!test_only)
2050 {
2051 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002052 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002054 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002055 }
2056 return FALSE;
2057}
2058
2059#endif /* FEAT_X11 */
2060
2061 int
2062mch_can_restore_title()
2063{
2064 return get_x11_title(TRUE);
2065}
2066
2067 int
2068mch_can_restore_icon()
2069{
2070 return get_x11_icon(TRUE);
2071}
2072
2073/*
2074 * Set the window title and icon.
2075 */
2076 void
2077mch_settitle(title, icon)
2078 char_u *title;
2079 char_u *icon;
2080{
2081 int type = 0;
2082 static int recursive = 0;
2083
2084 if (T_NAME == NULL) /* no terminal name (yet) */
2085 return;
2086 if (title == NULL && icon == NULL) /* nothing to do */
2087 return;
2088
2089 /* When one of the X11 functions causes a deadly signal, we get here again
2090 * recursively. Avoid hanging then (something is probably locked). */
2091 if (recursive)
2092 return;
2093 ++recursive;
2094
2095 /*
2096 * if the window ID and the display is known, we may use X11 calls
2097 */
2098#ifdef FEAT_X11
2099 if (get_x11_windis() == OK)
2100 type = 1;
2101#else
2102# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2103 if (gui.in_use)
2104 type = 1;
2105# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002106#endif
2107
2108 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002109 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002110 * than x11 calls, because the x11 calls don't always work
2111 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112 if ((type || *T_TS != NUL) && title != NULL)
2113 {
2114 if (oldtitle == NULL
2115#ifdef FEAT_GUI
2116 && !gui.in_use
2117#endif
2118 ) /* first call but not in GUI, save title */
2119 (void)get_x11_title(FALSE);
2120
2121 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2122 term_settitle(title);
2123#ifdef FEAT_X11
2124 else
2125# ifdef FEAT_GUI_GTK
2126 if (!gui.in_use) /* don't do this if GTK+ is running */
2127# endif
2128 set_x11_title(title); /* x11 */
2129#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002130#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002131 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2132 else
2133 gui_mch_settitle(title, icon);
2134#endif
2135 did_set_title = TRUE;
2136 }
2137
2138 if ((type || *T_CIS != NUL) && icon != NULL)
2139 {
2140 if (oldicon == NULL
2141#ifdef FEAT_GUI
2142 && !gui.in_use
2143#endif
2144 ) /* first call, save icon */
2145 get_x11_icon(FALSE);
2146
2147 if (*T_CIS != NUL)
2148 {
2149 out_str(T_CIS); /* set icon start */
2150 out_str_nf(icon);
2151 out_str(T_CIE); /* set icon end */
2152 out_flush();
2153 }
2154#ifdef FEAT_X11
2155 else
2156# ifdef FEAT_GUI_GTK
2157 if (!gui.in_use) /* don't do this if GTK+ is running */
2158# endif
2159 set_x11_icon(icon); /* x11 */
2160#endif
2161 did_set_icon = TRUE;
2162 }
2163 --recursive;
2164}
2165
2166/*
2167 * Restore the window/icon title.
2168 * "which" is one of:
2169 * 1 only restore title
2170 * 2 only restore icon
2171 * 3 restore title and icon
2172 */
2173 void
2174mch_restore_title(which)
2175 int which;
2176{
2177 /* only restore the title or icon when it has been set */
2178 mch_settitle(((which & 1) && did_set_title) ?
2179 (oldtitle ? oldtitle : p_titleold) : NULL,
2180 ((which & 2) && did_set_icon) ? oldicon : NULL);
2181}
2182
2183#endif /* FEAT_TITLE */
2184
2185/*
2186 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002187 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002188 */
2189 int
2190vim_is_xterm(name)
2191 char_u *name;
2192{
2193 if (name == NULL)
2194 return FALSE;
2195 return (STRNICMP(name, "xterm", 5) == 0
2196 || STRNICMP(name, "nxterm", 6) == 0
2197 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002198 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002199 || STRNICMP(name, "rxvt", 4) == 0
2200 || STRCMP(name, "builtin_xterm") == 0);
2201}
2202
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002203#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2204/*
2205 * Return TRUE if "name" appears to be that of a terminal
2206 * known to support the xterm-style mouse protocol.
2207 * Relies on term_is_xterm having been set to its correct value.
2208 */
2209 int
2210use_xterm_like_mouse(name)
2211 char_u *name;
2212{
2213 return (name != NULL
2214 && (term_is_xterm || STRNICMP(name, "screen", 6) == 0));
2215}
2216#endif
2217
Bram Moolenaar071d4272004-06-13 20:20:40 +00002218#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2219/*
2220 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2221 * Return 1 for "xterm".
2222 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002223 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002224 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002225 */
2226 int
2227use_xterm_mouse()
2228{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002229 if (ttym_flags == TTYM_SGR)
2230 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002231 if (ttym_flags == TTYM_URXVT)
2232 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002233 if (ttym_flags == TTYM_XTERM2)
2234 return 2;
2235 if (ttym_flags == TTYM_XTERM)
2236 return 1;
2237 return 0;
2238}
2239#endif
2240
2241 int
2242vim_is_iris(name)
2243 char_u *name;
2244{
2245 if (name == NULL)
2246 return FALSE;
2247 return (STRNICMP(name, "iris-ansi", 9) == 0
2248 || STRCMP(name, "builtin_iris-ansi") == 0);
2249}
2250
2251 int
2252vim_is_vt300(name)
2253 char_u *name;
2254{
2255 if (name == NULL)
2256 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002257 /* catch VT100 - VT5xx */
2258 return ((STRNICMP(name, "vt", 2) == 0
2259 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002260 || STRCMP(name, "builtin_vt320") == 0);
2261}
2262
2263/*
2264 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2265 * This should include all windowed terminal emulators.
2266 */
2267 int
2268vim_is_fastterm(name)
2269 char_u *name;
2270{
2271 if (name == NULL)
2272 return FALSE;
2273 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2274 return TRUE;
2275 return ( STRNICMP(name, "hpterm", 6) == 0
2276 || STRNICMP(name, "sun-cmd", 7) == 0
2277 || STRNICMP(name, "screen", 6) == 0
2278 || STRNICMP(name, "dtterm", 6) == 0);
2279}
2280
2281/*
2282 * Insert user name in s[len].
2283 * Return OK if a name found.
2284 */
2285 int
2286mch_get_user_name(s, len)
2287 char_u *s;
2288 int len;
2289{
2290#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002291 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292 return OK;
2293#else
2294 return mch_get_uname(getuid(), s, len);
2295#endif
2296}
2297
2298/*
2299 * Insert user name for "uid" in s[len].
2300 * Return OK if a name found.
2301 */
2302 int
2303mch_get_uname(uid, s, len)
2304 uid_t uid;
2305 char_u *s;
2306 int len;
2307{
2308#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2309 struct passwd *pw;
2310
2311 if ((pw = getpwuid(uid)) != NULL
2312 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2313 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002314 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002315 return OK;
2316 }
2317#endif
2318 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2319 return FAIL; /* a number is not a name */
2320}
2321
2322/*
2323 * Insert host name is s[len].
2324 */
2325
2326#ifdef HAVE_SYS_UTSNAME_H
2327 void
2328mch_get_host_name(s, len)
2329 char_u *s;
2330 int len;
2331{
2332 struct utsname vutsname;
2333
2334 if (uname(&vutsname) < 0)
2335 *s = NUL;
2336 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002337 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002338}
2339#else /* HAVE_SYS_UTSNAME_H */
2340
2341# ifdef HAVE_SYS_SYSTEMINFO_H
2342# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2343# endif
2344
2345 void
2346mch_get_host_name(s, len)
2347 char_u *s;
2348 int len;
2349{
2350# ifdef VAXC
2351 vaxc$gethostname((char *)s, len);
2352# else
2353 gethostname((char *)s, len);
2354# endif
2355 s[len - 1] = NUL; /* make sure it's terminated */
2356}
2357#endif /* HAVE_SYS_UTSNAME_H */
2358
2359/*
2360 * return process ID
2361 */
2362 long
2363mch_get_pid()
2364{
2365 return (long)getpid();
2366}
2367
2368#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2369static char *strerror __ARGS((int));
2370
2371 static char *
2372strerror(err)
2373 int err;
2374{
2375 extern int sys_nerr;
2376 extern char *sys_errlist[];
2377 static char er[20];
2378
2379 if (err > 0 && err < sys_nerr)
2380 return (sys_errlist[err]);
2381 sprintf(er, "Error %d", err);
2382 return er;
2383}
2384#endif
2385
2386/*
2387 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2388 * Return OK for success, FAIL for failure.
2389 */
2390 int
2391mch_dirname(buf, len)
2392 char_u *buf;
2393 int len;
2394{
2395#if defined(USE_GETCWD)
2396 if (getcwd((char *)buf, len) == NULL)
2397 {
2398 STRCPY(buf, strerror(errno));
2399 return FAIL;
2400 }
2401 return OK;
2402#else
2403 return (getwd((char *)buf) != NULL ? OK : FAIL);
2404#endif
2405}
2406
2407#if defined(OS2) || defined(PROTO)
2408/*
2409 * Replace all slashes by backslashes.
2410 * When 'shellslash' set do it the other way around.
2411 */
2412 void
2413slash_adjust(p)
2414 char_u *p;
2415{
2416 while (*p)
2417 {
2418 if (*p == psepcN)
2419 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002420 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002421 }
2422}
2423#endif
2424
2425/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002426 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002427 *
2428 * return FAIL for failure, OK for success
2429 */
2430 int
2431mch_FullName(fname, buf, len, force)
2432 char_u *fname, *buf;
2433 int len;
2434 int force; /* also expand when already absolute path */
2435{
2436 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002437#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002438 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002439#endif
2440#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002441 int fd = -1;
2442 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002443#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002444 char_u olddir[MAXPATHL];
2445 char_u *p;
2446 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002447#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002448 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2449 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002450#endif
2451
Bram Moolenaar38323e42007-03-06 19:22:53 +00002452#ifdef VMS
2453 fname = vms_fixfilename(fname);
2454#endif
2455
Bram Moolenaara2442432007-04-26 14:26:37 +00002456#ifdef __CYGWIN__
2457 /*
2458 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2459 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002460# if CYGWIN_VERSION_DLL_MAJOR >= 1007
2461 cygwin_conv_path(CCP_WIN_A_TO_POSIX, fname, posix_fname, MAXPATHL);
2462# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002463 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002464# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002465 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002466#endif
2467
Bram Moolenaar071d4272004-06-13 20:20:40 +00002468 /* expand it if forced or not an absolute path */
2469 if (force || !mch_isFullName(fname))
2470 {
2471 /*
2472 * If the file name has a path, change to that directory for a moment,
2473 * and then do the getwd() (and get back to where we were).
2474 * This will get the correct path name with "../" things.
2475 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002476#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 only_drive = 0;
2478 if (((p = vim_strrchr(fname, '/')) != NULL)
2479 || ((p = vim_strrchr(fname, '\\')) != NULL)
2480 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002481#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002483#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002484 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002485#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002486 /*
2487 * Use fchdir() if possible, it's said to be faster and more
2488 * reliable. But on SunOS 4 it might not work. Check this by
2489 * doing a fchdir() right now.
2490 */
2491 if (!dont_fchdir)
2492 {
2493 fd = open(".", O_RDONLY | O_EXTRA, 0);
2494 if (fd >= 0 && fchdir(fd) < 0)
2495 {
2496 close(fd);
2497 fd = -1;
2498 dont_fchdir = TRUE; /* don't try again */
2499 }
2500 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002501#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502
2503 /* Only change directory when we are sure we can return to where
2504 * we are now. After doing "su" chdir(".") might not work. */
2505 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002506#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002507 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002508#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002509 (mch_dirname(olddir, MAXPATHL) == FAIL
2510 || mch_chdir((char *)olddir) != 0))
2511 {
2512 p = NULL; /* can't get current dir: don't chdir */
2513 retval = FAIL;
2514 }
2515 else
2516 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002517#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518 /*
2519 * compensate for case where ':' from "D:" was the only
2520 * path separator detected in the file name; the _next_
2521 * character has to be removed, and then restored later.
2522 */
2523 if (only_drive)
2524 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002525#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002526 /* The directory is copied into buf[], to be able to remove
2527 * the file name without changing it (could be a string in
2528 * read-only memory) */
2529 if (p - fname >= len)
2530 retval = FAIL;
2531 else
2532 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002533 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002534 if (mch_chdir((char *)buf))
2535 retval = FAIL;
2536 else
2537 fname = p + 1;
2538 *buf = NUL;
2539 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002540#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541 if (only_drive)
2542 {
2543 p--;
2544 if (retval != FAIL)
2545 fname--;
2546 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002547#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002548 }
2549 }
2550 if (mch_dirname(buf, len) == FAIL)
2551 {
2552 retval = FAIL;
2553 *buf = NUL;
2554 }
2555 if (p != NULL)
2556 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002557#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002558 if (fd >= 0)
2559 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002560 if (p_verbose >= 5)
2561 {
2562 verbose_enter();
2563 MSG("fchdir() to previous dir");
2564 verbose_leave();
2565 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002566 l = fchdir(fd);
2567 close(fd);
2568 }
2569 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002570#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002571 l = mch_chdir((char *)olddir);
2572 if (l != 0)
2573 EMSG(_(e_prev_dir));
2574 }
2575
2576 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002577 if (l >= len - 1)
2578 retval = FAIL; /* no space for trailing "/" */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002579#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002580 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002581 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002582 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002583#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002585
Bram Moolenaar071d4272004-06-13 20:20:40 +00002586 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002587 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002588 return FAIL;
2589
2590 /* Do not append ".", "/dir/." is equal to "/dir". */
2591 if (STRCMP(fname, ".") != 0)
2592 STRCAT(buf, fname);
2593
2594 return OK;
2595}
2596
2597/*
2598 * Return TRUE if "fname" does not depend on the current directory.
2599 */
2600 int
2601mch_isFullName(fname)
2602 char_u *fname;
2603{
2604#ifdef __EMX__
2605 return _fnisabs(fname);
2606#else
2607# ifdef VMS
2608 return ( fname[0] == '/' || fname[0] == '.' ||
2609 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2610 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2611 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2612# else
2613 return (*fname == '/' || *fname == '~');
2614# endif
2615#endif
2616}
2617
Bram Moolenaar24552be2005-12-10 20:17:30 +00002618#if defined(USE_FNAME_CASE) || defined(PROTO)
2619/*
2620 * Set the case of the file name, if it already exists. This will cause the
2621 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002622 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002623 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002624 void
2625fname_case(name, len)
2626 char_u *name;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002627 int len UNUSED; /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002628{
2629 struct stat st;
2630 char_u *slash, *tail;
2631 DIR *dirp;
2632 struct dirent *dp;
2633
2634 if (lstat((char *)name, &st) >= 0)
2635 {
2636 /* Open the directory where the file is located. */
2637 slash = vim_strrchr(name, '/');
2638 if (slash == NULL)
2639 {
2640 dirp = opendir(".");
2641 tail = name;
2642 }
2643 else
2644 {
2645 *slash = NUL;
2646 dirp = opendir((char *)name);
2647 *slash = '/';
2648 tail = slash + 1;
2649 }
2650
2651 if (dirp != NULL)
2652 {
2653 while ((dp = readdir(dirp)) != NULL)
2654 {
2655 /* Only accept names that differ in case and are the same byte
2656 * length. TODO: accept different length name. */
2657 if (STRICMP(tail, dp->d_name) == 0
2658 && STRLEN(tail) == STRLEN(dp->d_name))
2659 {
2660 char_u newname[MAXPATHL + 1];
2661 struct stat st2;
2662
2663 /* Verify the inode is equal. */
2664 vim_strncpy(newname, name, MAXPATHL);
2665 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2666 MAXPATHL - (tail - name));
2667 if (lstat((char *)newname, &st2) >= 0
2668 && st.st_ino == st2.st_ino
2669 && st.st_dev == st2.st_dev)
2670 {
2671 STRCPY(tail, dp->d_name);
2672 break;
2673 }
2674 }
2675 }
2676
2677 closedir(dirp);
2678 }
2679 }
2680}
2681#endif
2682
Bram Moolenaar071d4272004-06-13 20:20:40 +00002683/*
2684 * Get file permissions for 'name'.
2685 * Returns -1 when it doesn't exist.
2686 */
2687 long
2688mch_getperm(name)
2689 char_u *name;
2690{
2691 struct stat statb;
2692
2693 /* Keep the #ifdef outside of stat(), it may be a macro. */
2694#ifdef VMS
2695 if (stat((char *)vms_fixfilename(name), &statb))
2696#else
2697 if (stat((char *)name, &statb))
2698#endif
2699 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002700#ifdef __INTERIX
2701 /* The top bit makes the value negative, which means the file doesn't
2702 * exist. Remove the bit, we don't use it. */
2703 return statb.st_mode & ~S_ADDACE;
2704#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002705 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002706#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002707}
2708
2709/*
2710 * set file permission for 'name' to 'perm'
2711 *
2712 * return FAIL for failure, OK otherwise
2713 */
2714 int
2715mch_setperm(name, perm)
2716 char_u *name;
2717 long perm;
2718{
2719 return (chmod((char *)
2720#ifdef VMS
2721 vms_fixfilename(name),
2722#else
2723 name,
2724#endif
2725 (mode_t)perm) == 0 ? OK : FAIL);
2726}
2727
2728#if defined(HAVE_ACL) || defined(PROTO)
2729# ifdef HAVE_SYS_ACL_H
2730# include <sys/acl.h>
2731# endif
2732# ifdef HAVE_SYS_ACCESS_H
2733# include <sys/access.h>
2734# endif
2735
2736# ifdef HAVE_SOLARIS_ACL
2737typedef struct vim_acl_solaris_T {
2738 int acl_cnt;
2739 aclent_t *acl_entry;
2740} vim_acl_solaris_T;
2741# endif
2742
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002743#if defined(HAVE_SELINUX) || defined(PROTO)
2744/*
2745 * Copy security info from "from_file" to "to_file".
2746 */
2747 void
2748mch_copy_sec(from_file, to_file)
2749 char_u *from_file;
2750 char_u *to_file;
2751{
2752 if (from_file == NULL)
2753 return;
2754
2755 if (selinux_enabled == -1)
2756 selinux_enabled = is_selinux_enabled();
2757
2758 if (selinux_enabled > 0)
2759 {
2760 security_context_t from_context = NULL;
2761 security_context_t to_context = NULL;
2762
2763 if (getfilecon((char *)from_file, &from_context) < 0)
2764 {
2765 /* If the filesystem doesn't support extended attributes,
2766 the original had no special security context and the
2767 target cannot have one either. */
2768 if (errno == EOPNOTSUPP)
2769 return;
2770
2771 MSG_PUTS(_("\nCould not get security context for "));
2772 msg_outtrans(from_file);
2773 msg_putchar('\n');
2774 return;
2775 }
2776 if (getfilecon((char *)to_file, &to_context) < 0)
2777 {
2778 MSG_PUTS(_("\nCould not get security context for "));
2779 msg_outtrans(to_file);
2780 msg_putchar('\n');
2781 freecon (from_context);
2782 return ;
2783 }
2784 if (strcmp(from_context, to_context) != 0)
2785 {
2786 if (setfilecon((char *)to_file, from_context) < 0)
2787 {
2788 MSG_PUTS(_("\nCould not set security context for "));
2789 msg_outtrans(to_file);
2790 msg_putchar('\n');
2791 }
2792 }
2793 freecon(to_context);
2794 freecon(from_context);
2795 }
2796}
2797#endif /* HAVE_SELINUX */
2798
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799/*
2800 * Return a pointer to the ACL of file "fname" in allocated memory.
2801 * Return NULL if the ACL is not available for whatever reason.
2802 */
2803 vim_acl_T
2804mch_get_acl(fname)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002805 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002806{
2807 vim_acl_T ret = NULL;
2808#ifdef HAVE_POSIX_ACL
2809 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2810#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002811#ifdef HAVE_SOLARIS_ZFS_ACL
2812 acl_t *aclent;
2813
2814 if (acl_get((char *)fname, 0, &aclent) < 0)
2815 return NULL;
2816 ret = (vim_acl_T)aclent;
2817#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002818#ifdef HAVE_SOLARIS_ACL
2819 vim_acl_solaris_T *aclent;
2820
2821 aclent = malloc(sizeof(vim_acl_solaris_T));
2822 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2823 {
2824 free(aclent);
2825 return NULL;
2826 }
2827 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2828 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2829 {
2830 free(aclent->acl_entry);
2831 free(aclent);
2832 return NULL;
2833 }
2834 ret = (vim_acl_T)aclent;
2835#else
2836#if defined(HAVE_AIX_ACL)
2837 int aclsize;
2838 struct acl *aclent;
2839
2840 aclsize = sizeof(struct acl);
2841 aclent = malloc(aclsize);
2842 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2843 {
2844 if (errno == ENOSPC)
2845 {
2846 aclsize = aclent->acl_len;
2847 aclent = realloc(aclent, aclsize);
2848 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2849 {
2850 free(aclent);
2851 return NULL;
2852 }
2853 }
2854 else
2855 {
2856 free(aclent);
2857 return NULL;
2858 }
2859 }
2860 ret = (vim_acl_T)aclent;
2861#endif /* HAVE_AIX_ACL */
2862#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002863#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002864#endif /* HAVE_POSIX_ACL */
2865 return ret;
2866}
2867
2868/*
2869 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2870 */
2871 void
2872mch_set_acl(fname, aclent)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002873 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002874 vim_acl_T aclent;
2875{
2876 if (aclent == NULL)
2877 return;
2878#ifdef HAVE_POSIX_ACL
2879 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2880#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002881#ifdef HAVE_SOLARIS_ZFS_ACL
2882 acl_set((char *)fname, (acl_t *)aclent);
2883#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002884#ifdef HAVE_SOLARIS_ACL
2885 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2886 ((vim_acl_solaris_T *)aclent)->acl_entry);
2887#else
2888#ifdef HAVE_AIX_ACL
2889 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2890#endif /* HAVE_AIX_ACL */
2891#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002892#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002893#endif /* HAVE_POSIX_ACL */
2894}
2895
2896 void
2897mch_free_acl(aclent)
2898 vim_acl_T aclent;
2899{
2900 if (aclent == NULL)
2901 return;
2902#ifdef HAVE_POSIX_ACL
2903 acl_free((acl_t)aclent);
2904#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002905#ifdef HAVE_SOLARIS_ZFS_ACL
2906 acl_free((acl_t *)aclent);
2907#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908#ifdef HAVE_SOLARIS_ACL
2909 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2910 free(aclent);
2911#else
2912#ifdef HAVE_AIX_ACL
2913 free(aclent);
2914#endif /* HAVE_AIX_ACL */
2915#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002916#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917#endif /* HAVE_POSIX_ACL */
2918}
2919#endif
2920
2921/*
2922 * Set hidden flag for "name".
2923 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924 void
2925mch_hide(name)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002926 char_u *name UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002927{
2928 /* can't hide a file */
2929}
2930
2931/*
2932 * return TRUE if "name" is a directory
2933 * return FALSE if "name" is not a directory
2934 * return FALSE for error
2935 */
2936 int
2937mch_isdir(name)
2938 char_u *name;
2939{
2940 struct stat statb;
2941
2942 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2943 return FALSE;
2944 if (stat((char *)name, &statb))
2945 return FALSE;
2946#ifdef _POSIX_SOURCE
2947 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2948#else
2949 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2950#endif
2951}
2952
Bram Moolenaar071d4272004-06-13 20:20:40 +00002953static int executable_file __ARGS((char_u *name));
2954
2955/*
2956 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2957 */
2958 static int
2959executable_file(name)
2960 char_u *name;
2961{
2962 struct stat st;
2963
2964 if (stat((char *)name, &st))
2965 return 0;
2966 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2967}
2968
2969/*
2970 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2971 * Return -1 if unknown.
2972 */
2973 int
2974mch_can_exe(name)
2975 char_u *name;
2976{
2977 char_u *buf;
2978 char_u *p, *e;
2979 int retval;
2980
2981 /* If it's an absolute or relative path don't need to use $PATH. */
2982 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2983 || (name[1] == '.' && name[2] == '/'))))
2984 return executable_file(name);
2985
2986 p = (char_u *)getenv("PATH");
2987 if (p == NULL || *p == NUL)
2988 return -1;
2989 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2990 if (buf == NULL)
2991 return -1;
2992
2993 /*
2994 * Walk through all entries in $PATH to check if "name" exists there and
2995 * is an executable file.
2996 */
2997 for (;;)
2998 {
2999 e = (char_u *)strchr((char *)p, ':');
3000 if (e == NULL)
3001 e = p + STRLEN(p);
3002 if (e - p <= 1) /* empty entry means current dir */
3003 STRCPY(buf, "./");
3004 else
3005 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003006 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003007 add_pathsep(buf);
3008 }
3009 STRCAT(buf, name);
3010 retval = executable_file(buf);
3011 if (retval == 1)
3012 break;
3013
3014 if (*e != ':')
3015 break;
3016 p = e + 1;
3017 }
3018
3019 vim_free(buf);
3020 return retval;
3021}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022
3023/*
3024 * Check what "name" is:
3025 * NODE_NORMAL: file or directory (or doesn't exist)
3026 * NODE_WRITABLE: writable device, socket, fifo, etc.
3027 * NODE_OTHER: non-writable things
3028 */
3029 int
3030mch_nodetype(name)
3031 char_u *name;
3032{
3033 struct stat st;
3034
3035 if (stat((char *)name, &st))
3036 return NODE_NORMAL;
3037 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3038 return NODE_NORMAL;
3039#ifndef OS2
3040 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
3041 return NODE_OTHER;
3042#endif
3043 /* Everything else is writable? */
3044 return NODE_WRITABLE;
3045}
3046
3047 void
3048mch_early_init()
3049{
3050#ifdef HAVE_CHECK_STACK_GROWTH
3051 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003052
Bram Moolenaar071d4272004-06-13 20:20:40 +00003053 check_stack_growth((char *)&i);
3054
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003055# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003056 get_stack_limit();
3057# endif
3058
3059#endif
3060
3061 /*
3062 * Setup an alternative stack for signals. Helps to catch signals when
3063 * running out of stack space.
3064 * Use of sigaltstack() is preferred, it's more portable.
3065 * Ignore any errors.
3066 */
3067#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00003068 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003069 init_signal_stack();
3070#endif
3071}
3072
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003073#if defined(EXITFREE) || defined(PROTO)
3074 void
3075mch_free_mem()
3076{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003077# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3078 if (clip_star.owned)
3079 clip_lose_selection(&clip_star);
3080 if (clip_plus.owned)
3081 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003082# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003083# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003084 if (xterm_Shell != (Widget)0)
3085 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003086# ifndef LESSTIF_VERSION
3087 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003088 if (xterm_dpy != NULL)
3089 XtCloseDisplay(xterm_dpy);
3090 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003091 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003092 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003093# ifdef FEAT_X11
3094 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
3095# endif
3096 }
3097# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003098# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003099# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003100 if (x11_display != NULL
3101# ifdef FEAT_XCLIPBOARD
3102 && x11_display != xterm_dpy
3103# endif
3104 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003105 XCloseDisplay(x11_display);
3106# endif
3107# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
3108 vim_free(signal_stack);
3109 signal_stack = NULL;
3110# endif
3111# ifdef FEAT_TITLE
3112 vim_free(oldtitle);
3113 vim_free(oldicon);
3114# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003115}
3116#endif
3117
Bram Moolenaar071d4272004-06-13 20:20:40 +00003118static void exit_scroll __ARGS((void));
3119
3120/*
3121 * Output a newline when exiting.
3122 * Make sure the newline goes to the same stream as the text.
3123 */
3124 static void
3125exit_scroll()
3126{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003127 if (silent_mode)
3128 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003129 if (newline_on_exit || msg_didout)
3130 {
3131 if (msg_use_printf())
3132 {
3133 if (info_message)
3134 mch_msg("\n");
3135 else
3136 mch_errmsg("\r\n");
3137 }
3138 else
3139 out_char('\n');
3140 }
3141 else
3142 {
3143 restore_cterm_colors(); /* get original colors back */
3144 msg_clr_eos_force(); /* clear the rest of the display */
3145 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3146 }
3147}
3148
3149 void
3150mch_exit(r)
3151 int r;
3152{
3153 exiting = TRUE;
3154
3155#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3156 x11_export_final_selection();
3157#endif
3158
3159#ifdef FEAT_GUI
3160 if (!gui.in_use)
3161#endif
3162 {
3163 settmode(TMODE_COOK);
3164#ifdef FEAT_TITLE
3165 mch_restore_title(3); /* restore xterm title and icon name */
3166#endif
3167 /*
3168 * When t_ti is not empty but it doesn't cause swapping terminal
3169 * pages, need to output a newline when msg_didout is set. But when
3170 * t_ti does swap pages it should not go to the shell page. Do this
3171 * before stoptermcap().
3172 */
3173 if (swapping_screen() && !newline_on_exit)
3174 exit_scroll();
3175
3176 /* Stop termcap: May need to check for T_CRV response, which
3177 * requires RAW mode. */
3178 stoptermcap();
3179
3180 /*
3181 * A newline is only required after a message in the alternate screen.
3182 * This is set to TRUE by wait_return().
3183 */
3184 if (!swapping_screen() || newline_on_exit)
3185 exit_scroll();
3186
3187 /* Cursor may have been switched off without calling starttermcap()
3188 * when doing "vim -u vimrc" and vimrc contains ":q". */
3189 if (full_screen)
3190 cursor_on();
3191 }
3192 out_flush();
3193 ml_close_all(TRUE); /* remove all memfiles */
3194 may_core_dump();
3195#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003196 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197 gui_exit(r);
3198#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003199
Bram Moolenaar56718732006-03-15 22:53:57 +00003200#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003201 mac_conv_cleanup();
3202#endif
3203
Bram Moolenaar071d4272004-06-13 20:20:40 +00003204#ifdef __QNX__
3205 /* A core dump won't be created if the signal handler
3206 * doesn't return, so we can't call exit() */
3207 if (deadly_signal != 0)
3208 return;
3209#endif
3210
Bram Moolenaar009b2592004-10-24 19:18:58 +00003211#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003212 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003213#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003214
3215#ifdef EXITFREE
3216 free_all_mem();
3217#endif
3218
Bram Moolenaar071d4272004-06-13 20:20:40 +00003219 exit(r);
3220}
3221
3222 static void
3223may_core_dump()
3224{
3225 if (deadly_signal != 0)
3226 {
3227 signal(deadly_signal, SIG_DFL);
3228 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3229 }
3230}
3231
3232#ifndef VMS
3233
3234 void
3235mch_settmode(tmode)
3236 int tmode;
3237{
3238 static int first = TRUE;
3239
3240 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3241#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3242 /*
3243 * for "new" tty systems
3244 */
3245# ifdef HAVE_TERMIOS_H
3246 static struct termios told;
3247 struct termios tnew;
3248# else
3249 static struct termio told;
3250 struct termio tnew;
3251# endif
3252
3253 if (first)
3254 {
3255 first = FALSE;
3256# if defined(HAVE_TERMIOS_H)
3257 tcgetattr(read_cmd_fd, &told);
3258# else
3259 ioctl(read_cmd_fd, TCGETA, &told);
3260# endif
3261 }
3262
3263 tnew = told;
3264 if (tmode == TMODE_RAW)
3265 {
3266 /*
3267 * ~ICRNL enables typing ^V^M
3268 */
3269 tnew.c_iflag &= ~ICRNL;
3270 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3271# if defined(IEXTEN) && !defined(__MINT__)
3272 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3273 /* but it breaks function keys on MINT */
3274# endif
3275 );
3276# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3277 tnew.c_oflag &= ~ONLCR;
3278# endif
3279 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3280 tnew.c_cc[VTIME] = 0; /* don't wait */
3281 }
3282 else if (tmode == TMODE_SLEEP)
3283 tnew.c_lflag &= ~(ECHO);
3284
3285# if defined(HAVE_TERMIOS_H)
3286 {
3287 int n = 10;
3288
3289 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3290 * few times. */
3291 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3292 && errno == EINTR && n > 0)
3293 --n;
3294 }
3295# else
3296 ioctl(read_cmd_fd, TCSETA, &tnew);
3297# endif
3298
3299#else
3300
3301 /*
3302 * for "old" tty systems
3303 */
3304# ifndef TIOCSETN
3305# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3306# endif
3307 static struct sgttyb ttybold;
3308 struct sgttyb ttybnew;
3309
3310 if (first)
3311 {
3312 first = FALSE;
3313 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3314 }
3315
3316 ttybnew = ttybold;
3317 if (tmode == TMODE_RAW)
3318 {
3319 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3320 ttybnew.sg_flags |= RAW;
3321 }
3322 else if (tmode == TMODE_SLEEP)
3323 ttybnew.sg_flags &= ~(ECHO);
3324 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3325#endif
3326 curr_tmode = tmode;
3327}
3328
3329/*
3330 * Try to get the code for "t_kb" from the stty setting
3331 *
3332 * Even if termcap claims a backspace key, the user's setting *should*
3333 * prevail. stty knows more about reality than termcap does, and if
3334 * somebody's usual erase key is DEL (which, for most BSD users, it will
3335 * be), they're going to get really annoyed if their erase key starts
3336 * doing forward deletes for no reason. (Eric Fischer)
3337 */
3338 void
3339get_stty()
3340{
3341 char_u buf[2];
3342 char_u *p;
3343
3344 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3345#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3346 /* for "new" tty systems */
3347# ifdef HAVE_TERMIOS_H
3348 struct termios keys;
3349# else
3350 struct termio keys;
3351# endif
3352
3353# if defined(HAVE_TERMIOS_H)
3354 if (tcgetattr(read_cmd_fd, &keys) != -1)
3355# else
3356 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3357# endif
3358 {
3359 buf[0] = keys.c_cc[VERASE];
3360 intr_char = keys.c_cc[VINTR];
3361#else
3362 /* for "old" tty systems */
3363 struct sgttyb keys;
3364
3365 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3366 {
3367 buf[0] = keys.sg_erase;
3368 intr_char = keys.sg_kill;
3369#endif
3370 buf[1] = NUL;
3371 add_termcode((char_u *)"kb", buf, FALSE);
3372
3373 /*
3374 * If <BS> and <DEL> are now the same, redefine <DEL>.
3375 */
3376 p = find_termcode((char_u *)"kD");
3377 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3378 do_fixdel(NULL);
3379 }
3380#if 0
3381 } /* to keep cindent happy */
3382#endif
3383}
3384
3385#endif /* VMS */
3386
3387#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3388/*
3389 * Set mouse clicks on or off.
3390 */
3391 void
3392mch_setmouse(on)
3393 int on;
3394{
3395 static int ison = FALSE;
3396 int xterm_mouse_vers;
3397
3398 if (on == ison) /* return quickly if nothing to do */
3399 return;
3400
3401 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003402
3403# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003404 if (ttym_flags == TTYM_URXVT)
3405 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003406 out_str_nf((char_u *)
3407 (on
3408 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3409 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
3410 ison = on;
3411 }
3412# endif
3413
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003414# ifdef FEAT_MOUSE_SGR
3415 if (ttym_flags == TTYM_SGR)
3416 {
3417 out_str_nf((char_u *)
3418 (on
3419 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3420 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
3421 ison = on;
3422 }
3423# endif
3424
Bram Moolenaar071d4272004-06-13 20:20:40 +00003425 if (xterm_mouse_vers > 0)
3426 {
3427 if (on) /* enable mouse events, use mouse tracking if available */
3428 out_str_nf((char_u *)
3429 (xterm_mouse_vers > 1
3430 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3431 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3432 else /* disable mouse events, could probably always send the same */
3433 out_str_nf((char_u *)
3434 (xterm_mouse_vers > 1
3435 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3436 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3437 ison = on;
3438 }
3439
3440# ifdef FEAT_MOUSE_DEC
3441 else if (ttym_flags == TTYM_DEC)
3442 {
3443 if (on) /* enable mouse events */
3444 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3445 else /* disable mouse events */
3446 out_str_nf((char_u *)"\033['z");
3447 ison = on;
3448 }
3449# endif
3450
3451# ifdef FEAT_MOUSE_GPM
3452 else
3453 {
3454 if (on)
3455 {
3456 if (gpm_open())
3457 ison = TRUE;
3458 }
3459 else
3460 {
3461 gpm_close();
3462 ison = FALSE;
3463 }
3464 }
3465# endif
3466
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003467# ifdef FEAT_SYSMOUSE
3468 else
3469 {
3470 if (on)
3471 {
3472 if (sysmouse_open() == OK)
3473 ison = TRUE;
3474 }
3475 else
3476 {
3477 sysmouse_close();
3478 ison = FALSE;
3479 }
3480 }
3481# endif
3482
Bram Moolenaar071d4272004-06-13 20:20:40 +00003483# ifdef FEAT_MOUSE_JSB
3484 else
3485 {
3486 if (on)
3487 {
3488 /* D - Enable Mouse up/down messages
3489 * L - Enable Left Button Reporting
3490 * M - Enable Middle Button Reporting
3491 * R - Enable Right Button Reporting
3492 * K - Enable SHIFT and CTRL key Reporting
3493 * + - Enable Advanced messaging of mouse moves and up/down messages
3494 * Q - Quiet No Ack
3495 * # - Numeric value of mouse pointer required
3496 * 0 = Multiview 2000 cursor, used as standard
3497 * 1 = Windows Arrow
3498 * 2 = Windows I Beam
3499 * 3 = Windows Hour Glass
3500 * 4 = Windows Cross Hair
3501 * 5 = Windows UP Arrow
3502 */
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003503# ifdef JSBTERM_MOUSE_NONADVANCED
3504 /* Disables full feedback of pointer movements */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003505 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3506 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003507# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003508 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3509 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003510# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511 ison = TRUE;
3512 }
3513 else
3514 {
3515 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3516 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3517 ison = FALSE;
3518 }
3519 }
3520# endif
3521# ifdef FEAT_MOUSE_PTERM
3522 else
3523 {
3524 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3525 if (on)
3526 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3527 else
3528 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3529 ison = on;
3530 }
3531# endif
3532}
3533
3534/*
3535 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3536 */
3537 void
3538check_mouse_termcode()
3539{
3540# ifdef FEAT_MOUSE_XTERM
3541 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003542# ifdef FEAT_MOUSE_URXVT
3543 && use_xterm_mouse() != 3
3544# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003545# ifdef FEAT_GUI
3546 && !gui.in_use
3547# endif
3548 )
3549 {
3550 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003551 ? IF_EB("\233M", CSI_STR "M")
3552 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003553 if (*p_mouse != NUL)
3554 {
3555 /* force mouse off and maybe on to send possibly new mouse
3556 * activation sequence to the xterm, with(out) drag tracing. */
3557 mch_setmouse(FALSE);
3558 setmouse();
3559 }
3560 }
3561 else
3562 del_mouse_termcode(KS_MOUSE);
3563# endif
3564
3565# ifdef FEAT_MOUSE_GPM
3566 if (!use_xterm_mouse()
3567# ifdef FEAT_GUI
3568 && !gui.in_use
3569# endif
3570 )
3571 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3572# endif
3573
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003574# ifdef FEAT_SYSMOUSE
3575 if (!use_xterm_mouse()
3576# ifdef FEAT_GUI
3577 && !gui.in_use
3578# endif
3579 )
3580 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3581# endif
3582
Bram Moolenaar071d4272004-06-13 20:20:40 +00003583# ifdef FEAT_MOUSE_JSB
3584 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3585 if (!use_xterm_mouse()
3586# ifdef FEAT_GUI
3587 && !gui.in_use
3588# endif
3589 )
3590 set_mouse_termcode(KS_JSBTERM_MOUSE,
3591 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3592 else
3593 del_mouse_termcode(KS_JSBTERM_MOUSE);
3594# endif
3595
3596# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003597 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003598 * define it in the GUI or when using an xterm. */
3599 if (!use_xterm_mouse()
3600# ifdef FEAT_GUI
3601 && !gui.in_use
3602# endif
3603 )
3604 set_mouse_termcode(KS_NETTERM_MOUSE,
3605 (char_u *)IF_EB("\033}", ESC_STR "}"));
3606 else
3607 del_mouse_termcode(KS_NETTERM_MOUSE);
3608# endif
3609
3610# ifdef FEAT_MOUSE_DEC
3611 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3612 if (!use_xterm_mouse()
3613# ifdef FEAT_GUI
3614 && !gui.in_use
3615# endif
3616 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003617 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3618 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003619 else
3620 del_mouse_termcode(KS_DEC_MOUSE);
3621# endif
3622# ifdef FEAT_MOUSE_PTERM
3623 /* same as the dec mouse */
3624 if (!use_xterm_mouse()
3625# ifdef FEAT_GUI
3626 && !gui.in_use
3627# endif
3628 )
3629 set_mouse_termcode(KS_PTERM_MOUSE,
3630 (char_u *) IF_EB("\033[", ESC_STR "["));
3631 else
3632 del_mouse_termcode(KS_PTERM_MOUSE);
3633# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003634# ifdef FEAT_MOUSE_URXVT
3635 /* same as the dec mouse */
3636 if (use_xterm_mouse() == 3
3637# ifdef FEAT_GUI
3638 && !gui.in_use
3639# endif
3640 )
3641 {
3642 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3643 ? IF_EB("\233", CSI_STR)
3644 : IF_EB("\033[", ESC_STR "[")));
3645
3646 if (*p_mouse != NUL)
3647 {
3648 mch_setmouse(FALSE);
3649 setmouse();
3650 }
3651 }
3652 else
3653 del_mouse_termcode(KS_URXVT_MOUSE);
3654# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003655# ifdef FEAT_MOUSE_SGR
3656 /* same as the dec mouse */
3657 if (use_xterm_mouse() == 4
3658# ifdef FEAT_GUI
3659 && !gui.in_use
3660# endif
3661 )
3662 {
3663 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3664 ? IF_EB("\233<", CSI_STR "<")
3665 : IF_EB("\033[<", ESC_STR "[<")));
3666
3667 if (*p_mouse != NUL)
3668 {
3669 mch_setmouse(FALSE);
3670 setmouse();
3671 }
3672 }
3673 else
3674 del_mouse_termcode(KS_SGR_MOUSE);
3675# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003676}
3677#endif
3678
3679/*
3680 * set screen mode, always fails.
3681 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003682 int
3683mch_screenmode(arg)
Bram Moolenaar78a15312009-05-15 19:33:18 +00003684 char_u *arg UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685{
3686 EMSG(_(e_screenmode));
3687 return FAIL;
3688}
3689
3690#ifndef VMS
3691
3692/*
3693 * Try to get the current window size:
3694 * 1. with an ioctl(), most accurate method
3695 * 2. from the environment variables LINES and COLUMNS
3696 * 3. from the termcap
3697 * 4. keep using the old values
3698 * Return OK when size could be determined, FAIL otherwise.
3699 */
3700 int
3701mch_get_shellsize()
3702{
3703 long rows = 0;
3704 long columns = 0;
3705 char_u *p;
3706
3707 /*
3708 * For OS/2 use _scrsize().
3709 */
3710# ifdef __EMX__
3711 {
3712 int s[2];
3713
3714 _scrsize(s);
3715 columns = s[0];
3716 rows = s[1];
3717 }
3718# endif
3719
3720 /*
3721 * 1. try using an ioctl. It is the most accurate method.
3722 *
3723 * Try using TIOCGWINSZ first, some systems that have it also define
3724 * TIOCGSIZE but don't have a struct ttysize.
3725 */
3726# ifdef TIOCGWINSZ
3727 {
3728 struct winsize ws;
3729 int fd = 1;
3730
3731 /* When stdout is not a tty, use stdin for the ioctl(). */
3732 if (!isatty(fd) && isatty(read_cmd_fd))
3733 fd = read_cmd_fd;
3734 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3735 {
3736 columns = ws.ws_col;
3737 rows = ws.ws_row;
3738 }
3739 }
3740# else /* TIOCGWINSZ */
3741# ifdef TIOCGSIZE
3742 {
3743 struct ttysize ts;
3744 int fd = 1;
3745
3746 /* When stdout is not a tty, use stdin for the ioctl(). */
3747 if (!isatty(fd) && isatty(read_cmd_fd))
3748 fd = read_cmd_fd;
3749 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3750 {
3751 columns = ts.ts_cols;
3752 rows = ts.ts_lines;
3753 }
3754 }
3755# endif /* TIOCGSIZE */
3756# endif /* TIOCGWINSZ */
3757
3758 /*
3759 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003760 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3761 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003762 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003763 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003764 {
3765 if ((p = (char_u *)getenv("LINES")))
3766 rows = atoi((char *)p);
3767 if ((p = (char_u *)getenv("COLUMNS")))
3768 columns = atoi((char *)p);
3769 }
3770
3771#ifdef HAVE_TGETENT
3772 /*
3773 * 3. try reading "co" and "li" entries from termcap
3774 */
3775 if (columns == 0 || rows == 0)
3776 getlinecol(&columns, &rows);
3777#endif
3778
3779 /*
3780 * 4. If everything fails, use the old values
3781 */
3782 if (columns <= 0 || rows <= 0)
3783 return FAIL;
3784
3785 Rows = rows;
3786 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02003787 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003788 return OK;
3789}
3790
3791/*
3792 * Try to set the window size to Rows and Columns.
3793 */
3794 void
3795mch_set_shellsize()
3796{
3797 if (*T_CWS)
3798 {
3799 /*
3800 * NOTE: if you get an error here that term_set_winsize() is
3801 * undefined, check the output of configure. It could probably not
3802 * find a ncurses, termcap or termlib library.
3803 */
3804 term_set_winsize((int)Rows, (int)Columns);
3805 out_flush();
3806 screen_start(); /* don't know where cursor is now */
3807 }
3808}
3809
3810#endif /* VMS */
3811
3812/*
3813 * Rows and/or Columns has changed.
3814 */
3815 void
3816mch_new_shellsize()
3817{
3818 /* Nothing to do. */
3819}
3820
Bram Moolenaar205b8862011-09-07 15:04:31 +02003821/*
3822 * Wait for process "child" to end.
3823 * Return "child" if it exited properly, <= 0 on error.
3824 */
3825 static pid_t
3826wait4pid(child, status)
3827 pid_t child;
3828 waitstatus *status;
3829{
3830 pid_t wait_pid = 0;
3831
3832 while (wait_pid != child)
3833 {
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003834 /* When compiled with Python threads are probably used, in which case
3835 * wait() sometimes hangs for no obvious reason. Use waitpid()
3836 * instead and loop (like the GUI). Also needed for other interfaces,
3837 * they might call system(). */
3838# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02003839 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003840# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02003841 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003842# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02003843 if (wait_pid == 0)
3844 {
Bram Moolenaar75676462013-01-30 14:55:42 +01003845 /* Wait for 10 msec before trying again. */
Bram Moolenaar205b8862011-09-07 15:04:31 +02003846 mch_delay(10L, TRUE);
3847 continue;
3848 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02003849 if (wait_pid <= 0
3850# ifdef ECHILD
3851 && errno == ECHILD
3852# endif
3853 )
3854 break;
3855 }
3856 return wait_pid;
3857}
3858
Bram Moolenaar071d4272004-06-13 20:20:40 +00003859 int
3860mch_call_shell(cmd, options)
3861 char_u *cmd;
3862 int options; /* SHELL_*, see vim.h */
3863{
3864#ifdef VMS
3865 char *ifn = NULL;
3866 char *ofn = NULL;
3867#endif
3868 int tmode = cur_tmode;
3869#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3870 int x;
3871# ifndef __EMX__
3872 char_u *newcmd; /* only needed for unix */
3873# else
3874 /*
3875 * Set the preferred shell in the EMXSHELL environment variable (but
3876 * only if it is different from what is already in the environment).
3877 * Emx then takes care of whether to use "/c" or "-c" in an
3878 * intelligent way. Simply pass the whole thing to emx's system() call.
3879 * Emx also starts an interactive shell if system() is passed an empty
3880 * string.
3881 */
3882 char_u *p, *old;
3883
3884 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3885 {
3886 /* should check HAVE_SETENV, but I know we don't have it. */
3887 p = alloc(10 + strlen(p_sh));
3888 if (p)
3889 {
3890 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3891 putenv((char *)p); /* don't free the pointer! */
3892 }
3893 }
3894# endif
3895
3896 out_flush();
3897
3898 if (options & SHELL_COOKED)
3899 settmode(TMODE_COOK); /* set to normal mode */
3900
Bram Moolenaar62b42182010-09-21 22:09:37 +02003901# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01003902 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02003903 loose_clipboard();
3904# endif
3905
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906# ifdef __EMX__
3907 if (cmd == NULL)
3908 x = system(""); /* this starts an interactive shell in emx */
3909 else
3910 x = system((char *)cmd);
3911 /* system() returns -1 when error occurs in starting shell */
3912 if (x == -1 && !emsg_silent)
3913 {
3914 MSG_PUTS(_("\nCannot execute shell "));
3915 msg_outtrans(p_sh);
3916 msg_putchar('\n');
3917 }
3918# else /* not __EMX__ */
3919 if (cmd == NULL)
3920 x = system((char *)p_sh);
3921 else
3922 {
3923# ifdef VMS
3924 if (ofn = strchr((char *)cmd, '>'))
3925 *ofn++ = '\0';
3926 if (ifn = strchr((char *)cmd, '<'))
3927 {
3928 char *p;
3929
3930 *ifn++ = '\0';
3931 p = strchr(ifn,' '); /* chop off any trailing spaces */
3932 if (p)
3933 *p = '\0';
3934 }
3935 if (ofn)
3936 x = vms_sys((char *)cmd, ofn, ifn);
3937 else
3938 x = system((char *)cmd);
3939# else
3940 newcmd = lalloc(STRLEN(p_sh)
3941 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3942 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3943 if (newcmd == NULL)
3944 x = 0;
3945 else
3946 {
3947 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3948 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3949 (char *)p_shcf,
3950 (char *)cmd);
3951 x = system((char *)newcmd);
3952 vim_free(newcmd);
3953 }
3954# endif
3955 }
3956# ifdef VMS
3957 x = vms_sys_status(x);
3958# endif
3959 if (emsg_silent)
3960 ;
3961 else if (x == 127)
3962 MSG_PUTS(_("\nCannot execute shell sh\n"));
3963# endif /* __EMX__ */
3964 else if (x && !(options & SHELL_SILENT))
3965 {
3966 MSG_PUTS(_("\nshell returned "));
3967 msg_outnum((long)x);
3968 msg_putchar('\n');
3969 }
3970
3971 if (tmode == TMODE_RAW)
3972 settmode(TMODE_RAW); /* set to raw mode */
3973# ifdef FEAT_TITLE
3974 resettitle();
3975# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01003976# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3977 restore_clipboard();
3978# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003979 return x;
3980
3981#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3982
Bram Moolenaardf177f62005-02-22 08:39:57 +00003983# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3984 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003985
3986 char_u *newcmd = NULL;
3987 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003988 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003989 pid_t wait_pid = 0;
3990# ifdef HAVE_UNION_WAIT
3991 union wait status;
3992# else
3993 int status = -1;
3994# endif
3995 int retval = -1;
3996 char **argv = NULL;
3997 int argc;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02003998 char_u *p_shcf_copy = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003999 int i;
4000 char_u *p;
4001 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004003# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004 int pty_slave_fd = -1;
4005 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004006# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004007 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004008 int fd_fromshell[2];
4009 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004010# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004011 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004012# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013 static char envbuf_Rows[20];
4014 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004015# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004016 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004017
Bram Moolenaar62b42182010-09-21 22:09:37 +02004018 newcmd = vim_strsave(p_sh);
4019 if (newcmd == NULL) /* out of memory */
4020 goto error;
4021
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022 out_flush();
4023 if (options & SHELL_COOKED)
4024 settmode(TMODE_COOK); /* set to normal mode */
4025
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004026 /*
4027 * Do this loop twice:
4028 * 1: find number of arguments
4029 * 2: separate them and build argv[]
4030 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004031 for (i = 0; i < 2; ++i)
4032 {
4033 p = newcmd;
4034 inquote = FALSE;
4035 argc = 0;
4036 for (;;)
4037 {
4038 if (i == 1)
4039 argv[argc] = (char *)p;
4040 ++argc;
4041 while (*p && (inquote || (*p != ' ' && *p != TAB)))
4042 {
4043 if (*p == '"')
4044 inquote = !inquote;
4045 ++p;
4046 }
4047 if (*p == NUL)
4048 break;
4049 if (i == 1)
4050 *p++ = NUL;
4051 p = skipwhite(p);
4052 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00004053 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054 {
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004055 /*
4056 * Account for possible multiple args in p_shcf.
4057 */
4058 p = p_shcf;
4059 for (;;)
4060 {
4061 p = skiptowhite(p);
4062 if (*p == NUL)
4063 break;
4064 ++argc;
4065 p = skipwhite(p);
4066 }
4067
Bram Moolenaar071d4272004-06-13 20:20:40 +00004068 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
4069 if (argv == NULL) /* out of memory */
4070 goto error;
4071 }
4072 }
4073 if (cmd != NULL)
4074 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004075 char_u *s;
4076
Bram Moolenaar071d4272004-06-13 20:20:40 +00004077 if (extra_shell_arg != NULL)
4078 argv[argc++] = (char *)extra_shell_arg;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004079
4080 /* Break 'shellcmdflag' into white separated parts. This doesn't
4081 * handle quoted strings, they are very unlikely to appear. */
4082 p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
4083 if (p_shcf_copy == NULL) /* out of memory */
4084 goto error;
4085 s = p_shcf_copy;
4086 p = p_shcf;
4087 while (*p != NUL)
4088 {
4089 argv[argc++] = (char *)s;
4090 while (*p && *p != ' ' && *p != TAB)
4091 *s++ = *p++;
4092 *s++ = NUL;
4093 p = skipwhite(p);
4094 }
4095
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096 argv[argc++] = (char *)cmd;
4097 }
4098 argv[argc] = NULL;
4099
Bram Moolenaar071d4272004-06-13 20:20:40 +00004100 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004101 * For the GUI, when writing the output into the buffer and when reading
4102 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4103 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004105 if ((options & (SHELL_READ|SHELL_WRITE))
4106# ifdef FEAT_GUI
4107 || (gui.in_use && show_shell_mess)
4108# endif
4109 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004110 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004111# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 /*
4113 * Try to open a master pty.
4114 * If this works, open the slave pty.
4115 * If the slave can't be opened, close the master pty.
4116 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004117 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118 {
4119 pty_master_fd = OpenPTY(&tty_name); /* open pty */
Bram Moolenaare70172e2011-08-04 19:36:52 +02004120 if (pty_master_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004121 {
Bram Moolenaare70172e2011-08-04 19:36:52 +02004122 /* Leaving out O_NOCTTY may lead to waitpid() always returning
4123 * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4124 * adding O_NOCTTY always works when defined. */
4125#ifdef O_NOCTTY
4126 pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4127#else
4128 pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4129#endif
4130 if (pty_slave_fd < 0)
4131 {
4132 close(pty_master_fd);
4133 pty_master_fd = -1;
4134 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135 }
4136 }
4137 /*
4138 * If not opening a pty or it didn't work, try using pipes.
4139 */
4140 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004141# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004142 {
4143 pipe_error = (pipe(fd_toshell) < 0);
4144 if (!pipe_error) /* pipe create OK */
4145 {
4146 pipe_error = (pipe(fd_fromshell) < 0);
4147 if (pipe_error) /* pipe create failed */
4148 {
4149 close(fd_toshell[0]);
4150 close(fd_toshell[1]);
4151 }
4152 }
4153 if (pipe_error)
4154 {
4155 MSG_PUTS(_("\nCannot create pipes\n"));
4156 out_flush();
4157 }
4158 }
4159 }
4160
4161 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162 {
4163# ifdef __BEOS__
4164 beos_cleanup_read_thread();
4165# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004166
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167 if ((pid = fork()) == -1) /* maybe we should use vfork() */
4168 {
4169 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004170 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004171# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004172 || (gui.in_use && show_shell_mess)
4173# endif
4174 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004176# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177 if (pty_master_fd >= 0) /* close the pseudo tty */
4178 {
4179 close(pty_master_fd);
4180 close(pty_slave_fd);
4181 }
4182 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004183# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184 {
4185 close(fd_toshell[0]);
4186 close(fd_toshell[1]);
4187 close(fd_fromshell[0]);
4188 close(fd_fromshell[1]);
4189 }
4190 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004191 }
4192 else if (pid == 0) /* child */
4193 {
4194 reset_signals(); /* handle signals normally */
4195
4196 if (!show_shell_mess || (options & SHELL_EXPAND))
4197 {
4198 int fd;
4199
4200 /*
4201 * Don't want to show any message from the shell. Can't just
4202 * close stdout and stderr though, because some systems will
4203 * break if you try to write to them after that, so we must
4204 * use dup() to replace them with something else -- webb
4205 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4206 * waiting for input.
4207 */
4208 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4209 fclose(stdin);
4210 fclose(stdout);
4211 fclose(stderr);
4212
4213 /*
4214 * If any of these open()'s and dup()'s fail, we just continue
4215 * anyway. It's not fatal, and on most systems it will make
4216 * no difference at all. On a few it will cause the execvp()
4217 * to exit with a non-zero status even when the completion
4218 * could be done, which is nothing too serious. If the open()
4219 * or dup() failed we'd just do the same thing ourselves
4220 * anyway -- webb
4221 */
4222 if (fd >= 0)
4223 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004224 ignored = dup(fd); /* To replace stdin (fd 0) */
4225 ignored = dup(fd); /* To replace stdout (fd 1) */
4226 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004227
4228 /* Don't need this now that we've duplicated it */
4229 close(fd);
4230 }
4231 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004232 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004234 || gui.in_use
4235# endif
4236 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004237 {
4238
Bram Moolenaardf177f62005-02-22 08:39:57 +00004239# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004240 /* Create our own process group, so that the child and all its
4241 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004242 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004243 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004244 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004245 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004246# if defined(SIGHUP)
4247 /* When doing "!xterm&" and 'shell' is bash: the shell
4248 * will exit and send SIGHUP to all processes in its
4249 * group, killing the just started process. Ignore SIGHUP
4250 * to avoid that. (suggested by Simon Schubert)
4251 */
4252 signal(SIGHUP, SIG_IGN);
4253# endif
4254 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004255# endif
4256# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004257 if (pty_slave_fd >= 0)
4258 {
4259 /* push stream discipline modules */
4260 if (options & SHELL_COOKED)
4261 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004263 /* Try to become controlling tty (probably doesn't work,
4264 * unless run by root) */
4265 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004266# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004267 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004268# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004269 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004270# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271 setenv("TERM", "dumb", 1);
4272 sprintf((char *)envbuf, "%ld", Rows);
4273 setenv("ROWS", (char *)envbuf, 1);
4274 sprintf((char *)envbuf, "%ld", Rows);
4275 setenv("LINES", (char *)envbuf, 1);
4276 sprintf((char *)envbuf, "%ld", Columns);
4277 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004278# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004279 /*
4280 * Putenv does not copy the string, it has to remain valid.
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004281 * Use a static array to avoid losing allocated memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004282 */
4283 putenv("TERM=dumb");
4284 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
4285 putenv(envbuf_Rows);
4286 sprintf(envbuf_Rows, "LINES=%ld", Rows);
4287 putenv(envbuf_Rows);
4288 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
4289 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004290# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004291
Bram Moolenaara5792f52005-11-23 21:25:05 +00004292 /*
4293 * stderr is only redirected when using the GUI, so that a
4294 * program like gpg can still access the terminal to get a
4295 * passphrase using stderr.
4296 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004297# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004298 if (pty_master_fd >= 0)
4299 {
4300 close(pty_master_fd); /* close master side of pty */
4301
4302 /* set up stdin/stdout/stderr for the child */
4303 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004304 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004305 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004306 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004307 if (gui.in_use)
4308 {
4309 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004310 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004311 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004312
4313 close(pty_slave_fd); /* has been dupped, close it now */
4314 }
4315 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004316# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004317 {
4318 /* set up stdin for the child */
4319 close(fd_toshell[1]);
4320 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004321 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004322 close(fd_toshell[0]);
4323
4324 /* set up stdout for the child */
4325 close(fd_fromshell[0]);
4326 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004327 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328 close(fd_fromshell[1]);
4329
Bram Moolenaara5792f52005-11-23 21:25:05 +00004330# ifdef FEAT_GUI
4331 if (gui.in_use)
4332 {
4333 /* set up stderr for the child */
4334 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004335 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004336 }
4337# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004338 }
4339 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004340
Bram Moolenaar071d4272004-06-13 20:20:40 +00004341 /*
4342 * There is no type cast for the argv, because the type may be
4343 * different on different machines. This may cause a warning
4344 * message with strict compilers, don't worry about it.
4345 * Call _exit() instead of exit() to avoid closing the connection
4346 * to the X server (esp. with GTK, which uses atexit()).
4347 */
4348 execvp(argv[0], argv);
4349 _exit(EXEC_FAILED); /* exec failed, return failure code */
4350 }
4351 else /* parent */
4352 {
4353 /*
4354 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004355 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004356 */
4357 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004358 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359
4360 /*
4361 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004362 * This is also used to pipe stdin/stdout to/from the external
4363 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004364 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004365 if ((options & (SHELL_READ|SHELL_WRITE))
4366# ifdef FEAT_GUI
4367 || (gui.in_use && show_shell_mess)
4368# endif
4369 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004370 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004371# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004372 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004373# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004375# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004376 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4377 int ta_len = 0; /* valid bytes in ta_buf[] */
4378 int len;
4379 int p_more_save;
4380 int old_State;
4381 int c;
4382 int toshell_fd;
4383 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004384 garray_T ga;
4385 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004386# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4387 struct timeval start_tv;
4388# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004389
Bram Moolenaardf177f62005-02-22 08:39:57 +00004390# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004391 if (pty_master_fd >= 0)
4392 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004393 fromshell_fd = pty_master_fd;
4394 toshell_fd = dup(pty_master_fd);
4395 }
4396 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004397# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004398 {
4399 close(fd_toshell[0]);
4400 close(fd_fromshell[1]);
4401 toshell_fd = fd_toshell[1];
4402 fromshell_fd = fd_fromshell[0];
4403 }
4404
4405 /*
4406 * Write to the child if there are typed characters.
4407 * Read from the child if there are characters available.
4408 * Repeat the reading a few times if more characters are
4409 * available. Need to check for typed keys now and then, but
4410 * not too often (delays when no chars are available).
4411 * This loop is quit if no characters can be read from the pty
4412 * (WaitForChar detected special condition), or there are no
4413 * characters available and the child has exited.
4414 * Only check if the child has exited when there is no more
4415 * output. The child may exit before all the output has
4416 * been printed.
4417 *
4418 * Currently this busy loops!
4419 * This can probably dead-lock when the write blocks!
4420 */
4421 p_more_save = p_more;
4422 p_more = FALSE;
4423 old_State = State;
4424 State = EXTERNCMD; /* don't redraw at window resize */
4425
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004426 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004427 {
4428 /* Fork a process that will write the lines to the
4429 * external program. */
4430 if ((wpid = fork()) == -1)
4431 {
4432 MSG_PUTS(_("\nCannot fork\n"));
4433 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004434 else if (wpid == 0) /* child */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004435 {
4436 linenr_T lnum = curbuf->b_op_start.lnum;
4437 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004438 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004439 size_t l;
4440
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004441 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004442 for (;;)
4443 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004444 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004445 if (l == 0)
4446 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004447 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004448 /* NL -> NUL translation */
4449 len = write(toshell_fd, "", (size_t)1);
4450 else
4451 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004452 char_u *s = vim_strchr(lp + written, NL);
4453
Bram Moolenaar89d40322006-08-29 15:30:07 +00004454 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004455 s == NULL ? l
4456 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004457 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004458 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004459 {
4460 /* Finished a line, add a NL, unless this line
4461 * should not have one. */
4462 if (lnum != curbuf->b_op_end.lnum
4463 || !curbuf->b_p_bin
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004464 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004465 && (lnum !=
4466 curbuf->b_ml.ml_line_count
4467 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004468 ignored = write(toshell_fd, "\n",
4469 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004470 ++lnum;
4471 if (lnum > curbuf->b_op_end.lnum)
4472 {
4473 /* finished all the lines, close pipe */
4474 close(toshell_fd);
4475 toshell_fd = -1;
4476 break;
4477 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004478 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004479 written = 0;
4480 }
4481 else if (len > 0)
4482 written += len;
4483 }
4484 _exit(0);
4485 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004486 else /* parent */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004487 {
4488 close(toshell_fd);
4489 toshell_fd = -1;
4490 }
4491 }
4492
4493 if (options & SHELL_READ)
4494 ga_init2(&ga, 1, BUFLEN);
4495
4496 noread_cnt = 0;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004497# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4498 gettimeofday(&start_tv, NULL);
4499# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004500 for (;;)
4501 {
4502 /*
4503 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004504 * if there are any.
4505 * Don't do this if we are expanding wild cards (would eat
4506 * typeahead).
4507 * Don't do this when filtering and terminal is in cooked
4508 * mode, the shell command will handle the I/O. Avoids
4509 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004510 * Don't get characters when the child has already
4511 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004512 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004513 * while (noread_cnt > 4), avoids that ":r !ls" eats
4514 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004515 */
4516 len = 0;
4517 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004518 && ((options &
4519 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4520 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004521# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004522 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004523# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004524 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004525 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004526 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004527 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004528 if (ta_len == 0)
4529 {
4530 /* Get extra characters when we don't have any.
4531 * Reset the counter and timer. */
4532 noread_cnt = 0;
4533# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4534 gettimeofday(&start_tv, NULL);
4535# endif
4536 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4537 }
4538 if (ta_len > 0 || len > 0)
4539 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540 /*
4541 * For pipes:
4542 * Check for CTRL-C: send interrupt signal to child.
4543 * Check for CTRL-D: EOF, close pipe to child.
4544 */
4545 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4546 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004547# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004548 /*
4549 * Send SIGINT to the child's group or all
4550 * processes in our group.
4551 */
4552 if (ta_buf[ta_len] == Ctrl_C
4553 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004554 {
4555# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004557# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004560 if (wpid > 0)
4561 kill(wpid, SIGINT);
4562 }
4563# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004564 if (pty_master_fd < 0 && toshell_fd >= 0
4565 && ta_buf[ta_len] == Ctrl_D)
4566 {
4567 close(toshell_fd);
4568 toshell_fd = -1;
4569 }
4570 }
4571
4572 /* replace K_BS by <BS> and K_DEL by <DEL> */
4573 for (i = ta_len; i < ta_len + len; ++i)
4574 {
4575 if (ta_buf[i] == CSI && len - i > 2)
4576 {
4577 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4578 if (c == K_DEL || c == K_KDEL || c == K_BS)
4579 {
4580 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4581 (size_t)(len - i - 2));
4582 if (c == K_DEL || c == K_KDEL)
4583 ta_buf[i] = DEL;
4584 else
4585 ta_buf[i] = Ctrl_H;
4586 len -= 2;
4587 }
4588 }
4589 else if (ta_buf[i] == '\r')
4590 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004591# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00004593 i += (*mb_ptr2len_len)(ta_buf + i,
4594 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004595# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004596 }
4597
4598 /*
4599 * For pipes: echo the typed characters.
4600 * For a pty this does not seem to work.
4601 */
4602 if (pty_master_fd < 0)
4603 {
4604 for (i = ta_len; i < ta_len + len; ++i)
4605 {
4606 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4607 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004608# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004609 else if (has_mbyte)
4610 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004611 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612
4613 msg_outtrans_len(ta_buf + i, l);
4614 i += l - 1;
4615 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004616# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 else
4618 msg_outtrans_len(ta_buf + i, 1);
4619 }
4620 windgoto(msg_row, msg_col);
4621 out_flush();
4622 }
4623
4624 ta_len += len;
4625
4626 /*
4627 * Write the characters to the child, unless EOF has
4628 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004629 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004630 * When writing buffer lines, drop the typed
4631 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004632 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004633 if (options & SHELL_WRITE)
4634 ta_len = 0;
4635 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636 {
4637 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4638 if (len > 0)
4639 {
4640 ta_len -= len;
4641 mch_memmove(ta_buf, ta_buf + len, ta_len);
4642 }
4643 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004644 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004645 }
4646
Bram Moolenaardf177f62005-02-22 08:39:57 +00004647 if (got_int)
4648 {
4649 /* CTRL-C sends a signal to the child, we ignore it
4650 * ourselves */
4651# ifdef HAVE_SETSID
4652 kill(-pid, SIGINT);
4653# else
4654 kill(0, SIGINT);
4655# endif
4656 if (wpid > 0)
4657 kill(wpid, SIGINT);
4658 got_int = FALSE;
4659 }
4660
Bram Moolenaar071d4272004-06-13 20:20:40 +00004661 /*
4662 * Check if the child has any characters to be printed.
4663 * Read them and write them to our window. Repeat this as
4664 * long as there is something to do, avoid the 10ms wait
4665 * for mch_inchar(), or sending typeahead characters to
4666 * the external process.
4667 * TODO: This should handle escape sequences, compatible
4668 * to some terminal (vt52?).
4669 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004670 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004671 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4672 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004673 len = read_eintr(fromshell_fd, buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004674# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004675 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004676# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004677 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004678# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004679 );
4680 if (len <= 0) /* end of file or error */
4681 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004682
4683 noread_cnt = 0;
4684 if (options & SHELL_READ)
4685 {
4686 /* Do NUL -> NL translation, append NL separated
4687 * lines to the current buffer. */
4688 for (i = 0; i < len; ++i)
4689 {
4690 if (buffer[i] == NL)
4691 append_ga_line(&ga);
4692 else if (buffer[i] == NUL)
4693 ga_append(&ga, NL);
4694 else
4695 ga_append(&ga, buffer[i]);
4696 }
4697 }
4698# ifdef FEAT_MBYTE
4699 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004700 {
4701 int l;
4702
Bram Moolenaardf177f62005-02-22 08:39:57 +00004703 len += buffer_off;
4704 buffer[len] = NUL;
4705
Bram Moolenaar071d4272004-06-13 20:20:40 +00004706 /* Check if the last character in buffer[] is
4707 * incomplete, keep these bytes for the next
4708 * round. */
4709 for (p = buffer; p < buffer + len; p += l)
4710 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004711 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004712 if (l == 0)
4713 l = 1; /* NUL byte? */
4714 else if (MB_BYTE2LEN(*p) != l)
4715 break;
4716 }
4717 if (p == buffer) /* no complete character */
4718 {
4719 /* avoid getting stuck at an illegal byte */
4720 if (len >= 12)
4721 ++p;
4722 else
4723 {
4724 buffer_off = len;
4725 continue;
4726 }
4727 }
4728 c = *p;
4729 *p = NUL;
4730 msg_puts(buffer);
4731 if (p < buffer + len)
4732 {
4733 *p = c;
4734 buffer_off = (buffer + len) - p;
4735 mch_memmove(buffer, p, buffer_off);
4736 continue;
4737 }
4738 buffer_off = 0;
4739 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004740# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004741 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742 {
4743 buffer[len] = NUL;
4744 msg_puts(buffer);
4745 }
4746
4747 windgoto(msg_row, msg_col);
4748 cursor_on();
4749 out_flush();
4750 if (got_int)
4751 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004752
4753# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4754 {
4755 struct timeval now_tv;
4756 long msec;
4757
4758 /* Avoid that we keep looping here without
4759 * checking for a CTRL-C for a long time. Don't
4760 * break out too often to avoid losing typeahead. */
4761 gettimeofday(&now_tv, NULL);
4762 msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
4763 + (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
4764 if (msec > 2000)
4765 {
4766 noread_cnt = 5;
4767 break;
4768 }
4769 }
4770# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004771 }
4772
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004773 /* If we already detected the child has finished break the
4774 * loop now. */
4775 if (wait_pid == pid)
4776 break;
4777
Bram Moolenaar071d4272004-06-13 20:20:40 +00004778 /*
4779 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004780 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004781 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004782# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004783 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004784# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004785 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004786# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004787 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4788 || (wait_pid == pid && WIFEXITED(status)))
4789 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004790 /* Don't break the loop yet, try reading more
4791 * characters from "fromshell_fd" first. When using
4792 * pipes there might still be something to read and
4793 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004794 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004796 else
4797 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004798
Bram Moolenaar95a51352013-03-21 22:53:50 +01004799# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004800 /* Handle any X events, e.g. serving the clipboard. */
4801 clip_update();
4802# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004803 }
4804finished:
4805 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004806 if (options & SHELL_READ)
4807 {
4808 if (ga.ga_len > 0)
4809 {
4810 append_ga_line(&ga);
4811 /* remember that the NL was missing */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004812 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004813 }
4814 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004815 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004816 ga_clear(&ga);
4817 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004818
Bram Moolenaar071d4272004-06-13 20:20:40 +00004819 /*
4820 * Give all typeahead that wasn't used back to ui_inchar().
4821 */
4822 if (ta_len)
4823 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004824 State = old_State;
4825 if (toshell_fd >= 0)
4826 close(toshell_fd);
4827 close(fromshell_fd);
4828 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01004829# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004830 else
4831 {
4832 /*
4833 * Similar to the loop above, but only handle X events, no
4834 * I/O.
4835 */
4836 for (;;)
4837 {
4838 if (got_int)
4839 {
4840 /* CTRL-C sends a signal to the child, we ignore it
4841 * ourselves */
4842# ifdef HAVE_SETSID
4843 kill(-pid, SIGINT);
4844# else
4845 kill(0, SIGINT);
4846# endif
4847 got_int = FALSE;
4848 }
4849# ifdef __NeXT__
4850 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4851# else
4852 wait_pid = waitpid(pid, &status, WNOHANG);
4853# endif
4854 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4855 || (wait_pid == pid && WIFEXITED(status)))
4856 {
4857 wait_pid = pid;
4858 break;
4859 }
4860
4861 /* Handle any X events, e.g. serving the clipboard. */
4862 clip_update();
4863
4864 mch_delay(10L, TRUE);
4865 }
4866 }
4867# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004868
4869 /*
4870 * Wait until our child has exited.
4871 * Ignore wait() returning pids of other children and returning
4872 * because of some signal like SIGWINCH.
4873 * Don't wait if wait_pid was already set above, indicating the
4874 * child already exited.
4875 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02004876 if (wait_pid != pid)
4877 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004878
Bram Moolenaar624891f2010-10-13 16:22:09 +02004879# ifdef FEAT_GUI
4880 /* Close slave side of pty. Only do this after the child has
4881 * exited, otherwise the child may hang when it tries to write on
4882 * the pty. */
4883 if (pty_master_fd >= 0)
4884 close(pty_slave_fd);
4885# endif
4886
Bram Moolenaardf177f62005-02-22 08:39:57 +00004887 /* Make sure the child that writes to the external program is
4888 * dead. */
4889 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004890 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004891 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02004892 wait4pid(wpid, NULL);
4893 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004894
Bram Moolenaar071d4272004-06-13 20:20:40 +00004895 /*
4896 * Set to raw mode right now, otherwise a CTRL-C after
4897 * catch_signals() will kill Vim.
4898 */
4899 if (tmode == TMODE_RAW)
4900 settmode(TMODE_RAW);
4901 did_settmode = TRUE;
4902 set_signals();
4903
4904 if (WIFEXITED(status))
4905 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004906 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004907 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01004908 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004909 {
4910 if (retval == EXEC_FAILED)
4911 {
4912 MSG_PUTS(_("\nCannot execute shell "));
4913 msg_outtrans(p_sh);
4914 msg_putchar('\n');
4915 }
4916 else if (!(options & SHELL_SILENT))
4917 {
4918 MSG_PUTS(_("\nshell returned "));
4919 msg_outnum((long)retval);
4920 msg_putchar('\n');
4921 }
4922 }
4923 }
4924 else
4925 MSG_PUTS(_("\nCommand terminated\n"));
4926 }
4927 }
4928 vim_free(argv);
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004929 vim_free(p_shcf_copy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004930
4931error:
4932 if (!did_settmode)
4933 if (tmode == TMODE_RAW)
4934 settmode(TMODE_RAW); /* set to raw mode */
4935# ifdef FEAT_TITLE
4936 resettitle();
4937# endif
4938 vim_free(newcmd);
4939
4940 return retval;
4941
4942#endif /* USE_SYSTEM */
4943}
4944
4945/*
4946 * Check for CTRL-C typed by reading all available characters.
4947 * In cooked mode we should get SIGINT, no need to check.
4948 */
4949 void
4950mch_breakcheck()
4951{
4952 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4953 fill_input_buf(FALSE);
4954}
4955
4956/*
4957 * Wait "msec" msec until a character is available from the keyboard or from
4958 * inbuf[]. msec == -1 will block forever.
4959 * When a GUI is being used, this will never get called -- webb
4960 */
4961 static int
4962WaitForChar(msec)
4963 long msec;
4964{
4965#ifdef FEAT_MOUSE_GPM
4966 int gpm_process_wanted;
4967#endif
4968#ifdef FEAT_XCLIPBOARD
4969 int rest;
4970#endif
4971 int avail;
4972
4973 if (input_available()) /* something in inbuf[] */
4974 return 1;
4975
4976#if defined(FEAT_MOUSE_DEC)
4977 /* May need to query the mouse position. */
4978 if (WantQueryMouse)
4979 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004980 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004981 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4982 }
4983#endif
4984
4985 /*
4986 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4987 * events. This is a bit complicated, because they might both be defined.
4988 */
4989#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4990# ifdef FEAT_XCLIPBOARD
4991 rest = 0;
4992 if (do_xterm_trace())
4993 rest = msec;
4994# endif
4995 do
4996 {
4997# ifdef FEAT_XCLIPBOARD
4998 if (rest != 0)
4999 {
5000 msec = XT_TRACE_DELAY;
5001 if (rest >= 0 && rest < XT_TRACE_DELAY)
5002 msec = rest;
5003 if (rest >= 0)
5004 rest -= msec;
5005 }
5006# endif
5007# ifdef FEAT_MOUSE_GPM
5008 gpm_process_wanted = 0;
5009 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
5010# else
5011 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
5012# endif
5013 if (!avail)
5014 {
5015 if (input_available())
5016 return 1;
5017# ifdef FEAT_XCLIPBOARD
5018 if (rest == 0 || !do_xterm_trace())
5019# endif
5020 break;
5021 }
5022 }
5023 while (FALSE
5024# ifdef FEAT_MOUSE_GPM
5025 || (gpm_process_wanted && mch_gpm_process() == 0)
5026# endif
5027# ifdef FEAT_XCLIPBOARD
5028 || (!avail && rest != 0)
5029# endif
5030 );
5031
5032#else
5033 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
5034#endif
5035 return avail;
5036}
5037
5038/*
5039 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005040 * "msec" == 0 will check for characters once.
5041 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005042 * When a GUI is being used, this will not be used for input -- webb
5043 * Returns also, when a request from Sniff is waiting -- toni.
5044 * Or when a Linux GPM mouse event is waiting.
5045 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005046#if defined(__BEOS__)
5047 int
5048#else
5049 static int
5050#endif
5051RealWaitForChar(fd, msec, check_for_gpm)
5052 int fd;
5053 long msec;
Bram Moolenaar78a15312009-05-15 19:33:18 +00005054 int *check_for_gpm UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005055{
5056 int ret;
Bram Moolenaar67c53842010-05-22 18:28:27 +02005057#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02005058 int nb_fd = netbeans_filedesc();
Bram Moolenaar67c53842010-05-22 18:28:27 +02005059#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005060#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005061 static int busy = FALSE;
5062
5063 /* May retry getting characters after an event was handled. */
5064# define MAY_LOOP
5065
5066# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5067 /* Remember at what time we started, so that we know how much longer we
5068 * should wait after being interrupted. */
5069# define USE_START_TV
5070 struct timeval start_tv;
5071
5072 if (msec > 0 && (
5073# ifdef FEAT_XCLIPBOARD
5074 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005075# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005076 ||
5077# endif
5078# endif
5079# ifdef USE_XSMP
5080 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005081# ifdef FEAT_MZSCHEME
5082 ||
5083# endif
5084# endif
5085# ifdef FEAT_MZSCHEME
5086 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005087# endif
5088 ))
5089 gettimeofday(&start_tv, NULL);
5090# endif
5091
5092 /* Handle being called recursively. This may happen for the session
5093 * manager stuff, it may save the file, which does a breakcheck. */
5094 if (busy)
5095 return 0;
5096#endif
5097
5098#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00005099 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005100#endif
5101 {
5102#ifdef MAY_LOOP
5103 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005104# ifdef FEAT_MZSCHEME
5105 int mzquantum_used = FALSE;
5106# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005107#endif
5108#ifndef HAVE_SELECT
Bram Moolenaar67c53842010-05-22 18:28:27 +02005109 struct pollfd fds[6];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005110 int nfd;
5111# ifdef FEAT_XCLIPBOARD
5112 int xterm_idx = -1;
5113# endif
5114# ifdef FEAT_MOUSE_GPM
5115 int gpm_idx = -1;
5116# endif
5117# ifdef USE_XSMP
5118 int xsmp_idx = -1;
5119# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005120# ifdef FEAT_NETBEANS_INTG
5121 int nb_idx = -1;
5122# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005123 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005124
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005125# ifdef FEAT_MZSCHEME
5126 mzvim_check_threads();
5127 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5128 {
5129 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
5130 mzquantum_used = TRUE;
5131 }
5132# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005133 fds[0].fd = fd;
5134 fds[0].events = POLLIN;
5135 nfd = 1;
5136
5137# ifdef FEAT_SNIFF
5138# define SNIFF_IDX 1
5139 if (want_sniff_request)
5140 {
5141 fds[SNIFF_IDX].fd = fd_from_sniff;
5142 fds[SNIFF_IDX].events = POLLIN;
5143 nfd++;
5144 }
5145# endif
5146# ifdef FEAT_XCLIPBOARD
5147 if (xterm_Shell != (Widget)0)
5148 {
5149 xterm_idx = nfd;
5150 fds[nfd].fd = ConnectionNumber(xterm_dpy);
5151 fds[nfd].events = POLLIN;
5152 nfd++;
5153 }
5154# endif
5155# ifdef FEAT_MOUSE_GPM
5156 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5157 {
5158 gpm_idx = nfd;
5159 fds[nfd].fd = gpm_fd;
5160 fds[nfd].events = POLLIN;
5161 nfd++;
5162 }
5163# endif
5164# ifdef USE_XSMP
5165 if (xsmp_icefd != -1)
5166 {
5167 xsmp_idx = nfd;
5168 fds[nfd].fd = xsmp_icefd;
5169 fds[nfd].events = POLLIN;
5170 nfd++;
5171 }
5172# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005173#ifdef FEAT_NETBEANS_INTG
5174 if (nb_fd != -1)
5175 {
5176 nb_idx = nfd;
5177 fds[nfd].fd = nb_fd;
5178 fds[nfd].events = POLLIN;
5179 nfd++;
5180 }
5181#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005182
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005183 ret = poll(fds, nfd, towait);
5184# ifdef FEAT_MZSCHEME
5185 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005186 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005187 finished = FALSE;
5188# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005189
5190# ifdef FEAT_SNIFF
5191 if (ret < 0)
5192 sniff_disconnect(1);
5193 else if (want_sniff_request)
5194 {
5195 if (fds[SNIFF_IDX].revents & POLLHUP)
5196 sniff_disconnect(1);
5197 if (fds[SNIFF_IDX].revents & POLLIN)
5198 sniff_request_waiting = 1;
5199 }
5200# endif
5201# ifdef FEAT_XCLIPBOARD
5202 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
5203 {
5204 xterm_update(); /* Maybe we should hand out clipboard */
5205 if (--ret == 0 && !input_available())
5206 /* Try again */
5207 finished = FALSE;
5208 }
5209# endif
5210# ifdef FEAT_MOUSE_GPM
5211 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
5212 {
5213 *check_for_gpm = 1;
5214 }
5215# endif
5216# ifdef USE_XSMP
5217 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
5218 {
5219 if (fds[xsmp_idx].revents & POLLIN)
5220 {
5221 busy = TRUE;
5222 xsmp_handle_requests();
5223 busy = FALSE;
5224 }
5225 else if (fds[xsmp_idx].revents & POLLHUP)
5226 {
5227 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005228 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005229 xsmp_close();
5230 }
5231 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005232 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005233 }
5234# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005235#ifdef FEAT_NETBEANS_INTG
5236 if (ret > 0 && nb_idx != -1 && fds[nb_idx].revents & POLLIN)
5237 {
5238 netbeans_read();
5239 --ret;
5240 }
5241#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005242
5243
5244#else /* HAVE_SELECT */
5245
5246 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005247 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005248 fd_set rfds, efds;
5249 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005250 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005251
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005252# ifdef FEAT_MZSCHEME
5253 mzvim_check_threads();
5254 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5255 {
5256 towait = p_mzq; /* don't wait longer than 'mzquantum' */
5257 mzquantum_used = TRUE;
5258 }
5259# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005260# ifdef __EMX__
5261 /* don't check for incoming chars if not in raw mode, because select()
5262 * always returns TRUE then (in some version of emx.dll) */
5263 if (curr_tmode != TMODE_RAW)
5264 return 0;
5265# endif
5266
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005267 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005268 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005269 tv.tv_sec = towait / 1000;
5270 tv.tv_usec = (towait % 1000) * (1000000/1000);
5271 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005272 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005273 else
5274 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005275
5276 /*
5277 * Select on ready for reading and exceptional condition (end of file).
5278 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005279select_eintr:
5280 FD_ZERO(&rfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005281 FD_ZERO(&efds);
5282 FD_SET(fd, &rfds);
5283# if !defined(__QNX__) && !defined(__CYGWIN32__)
5284 /* For QNX select() always returns 1 if this is set. Why? */
5285 FD_SET(fd, &efds);
5286# endif
5287 maxfd = fd;
5288
5289# ifdef FEAT_SNIFF
5290 if (want_sniff_request)
5291 {
5292 FD_SET(fd_from_sniff, &rfds);
5293 FD_SET(fd_from_sniff, &efds);
5294 if (maxfd < fd_from_sniff)
5295 maxfd = fd_from_sniff;
5296 }
5297# endif
5298# ifdef FEAT_XCLIPBOARD
5299 if (xterm_Shell != (Widget)0)
5300 {
5301 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
5302 if (maxfd < ConnectionNumber(xterm_dpy))
5303 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02005304
5305 /* An event may have already been read but not handled. In
5306 * particulary, XFlush may cause this. */
5307 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005308 }
5309# endif
5310# ifdef FEAT_MOUSE_GPM
5311 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5312 {
5313 FD_SET(gpm_fd, &rfds);
5314 FD_SET(gpm_fd, &efds);
5315 if (maxfd < gpm_fd)
5316 maxfd = gpm_fd;
5317 }
5318# endif
5319# ifdef USE_XSMP
5320 if (xsmp_icefd != -1)
5321 {
5322 FD_SET(xsmp_icefd, &rfds);
5323 FD_SET(xsmp_icefd, &efds);
5324 if (maxfd < xsmp_icefd)
5325 maxfd = xsmp_icefd;
5326 }
5327# endif
Bram Moolenaardd82d692012-08-15 17:26:57 +02005328# ifdef FEAT_NETBEANS_INTG
Bram Moolenaar67c53842010-05-22 18:28:27 +02005329 if (nb_fd != -1)
5330 {
5331 FD_SET(nb_fd, &rfds);
5332 if (maxfd < nb_fd)
5333 maxfd = nb_fd;
5334 }
Bram Moolenaardd82d692012-08-15 17:26:57 +02005335# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005336
5337# ifdef OLD_VMS
5338 /* Old VMS as v6.2 and older have broken select(). It waits more than
5339 * required. Should not be used */
5340 ret = 0;
5341# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005342 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
5343# endif
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005344# ifdef EINTR
5345 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005346 {
5347 /* Check whether window has been resized, EINTR may be caused by
5348 * SIGWINCH. */
5349 if (do_resize)
5350 handle_resize();
5351
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005352 /* Interrupted by a signal, need to try again. We ignore msec
5353 * here, because we do want to check even after a timeout if
5354 * characters are available. Needed for reading output of an
5355 * external command after the process has finished. */
5356 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005357 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005358# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00005359# ifdef __TANDEM
5360 if (ret == -1 && errno == ENOTSUP)
5361 {
5362 FD_ZERO(&rfds);
5363 FD_ZERO(&efds);
5364 ret = 0;
5365 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005366# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005367# ifdef FEAT_MZSCHEME
5368 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005369 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005370 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005371# endif
5372
5373# ifdef FEAT_SNIFF
5374 if (ret < 0 )
5375 sniff_disconnect(1);
5376 else if (ret > 0 && want_sniff_request)
5377 {
5378 if (FD_ISSET(fd_from_sniff, &efds))
5379 sniff_disconnect(1);
5380 if (FD_ISSET(fd_from_sniff, &rfds))
5381 sniff_request_waiting = 1;
5382 }
5383# endif
5384# ifdef FEAT_XCLIPBOARD
5385 if (ret > 0 && xterm_Shell != (Widget)0
5386 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
5387 {
5388 xterm_update(); /* Maybe we should hand out clipboard */
5389 /* continue looping when we only got the X event and the input
5390 * buffer is empty */
5391 if (--ret == 0 && !input_available())
5392 {
5393 /* Try again */
5394 finished = FALSE;
5395 }
5396 }
5397# endif
5398# ifdef FEAT_MOUSE_GPM
5399 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
5400 {
5401 if (FD_ISSET(gpm_fd, &efds))
5402 gpm_close();
5403 else if (FD_ISSET(gpm_fd, &rfds))
5404 *check_for_gpm = 1;
5405 }
5406# endif
5407# ifdef USE_XSMP
5408 if (ret > 0 && xsmp_icefd != -1)
5409 {
5410 if (FD_ISSET(xsmp_icefd, &efds))
5411 {
5412 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005413 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005414 xsmp_close();
5415 if (--ret == 0)
5416 finished = FALSE; /* keep going if event was only one */
5417 }
5418 else if (FD_ISSET(xsmp_icefd, &rfds))
5419 {
5420 busy = TRUE;
5421 xsmp_handle_requests();
5422 busy = FALSE;
5423 if (--ret == 0)
5424 finished = FALSE; /* keep going if event was only one */
5425 }
5426 }
5427# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005428#ifdef FEAT_NETBEANS_INTG
5429 if (ret > 0 && nb_fd != -1 && FD_ISSET(nb_fd, &rfds))
5430 {
5431 netbeans_read();
5432 --ret;
5433 }
5434#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005435
5436#endif /* HAVE_SELECT */
5437
5438#ifdef MAY_LOOP
5439 if (finished || msec == 0)
5440 break;
5441
5442 /* We're going to loop around again, find out for how long */
5443 if (msec > 0)
5444 {
5445# ifdef USE_START_TV
5446 struct timeval mtv;
5447
5448 /* Compute remaining wait time. */
5449 gettimeofday(&mtv, NULL);
5450 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
5451 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
5452# else
5453 /* Guess we got interrupted halfway. */
5454 msec = msec / 2;
5455# endif
5456 if (msec <= 0)
5457 break; /* waited long enough */
5458 }
5459#endif
5460 }
5461
5462 return (ret > 0);
5463}
5464
5465#ifndef VMS
5466
5467#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00005468/*
Bram Moolenaar02743632005-07-25 20:42:36 +00005469 * Expand a path into all matching files and/or directories. Handles "*",
5470 * "?", "[a-z]", "**", etc.
5471 * "path" has backslashes before chars that are not to be expanded.
5472 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005473 */
5474 int
5475mch_expandpath(gap, path, flags)
5476 garray_T *gap;
5477 char_u *path;
5478 int flags; /* EW_* flags */
5479{
Bram Moolenaar02743632005-07-25 20:42:36 +00005480 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005481}
5482#endif
5483
5484/*
5485 * mch_expand_wildcards() - this code does wild-card pattern matching using
5486 * the shell
5487 *
5488 * return OK for success, FAIL for error (you may lose some memory) and put
5489 * an error message in *file.
5490 *
5491 * num_pat is number of input patterns
5492 * pat is array of pointers to input patterns
5493 * num_file is pointer to number of matched file names
5494 * file is pointer to array of pointers to matched file names
5495 */
5496
5497#ifndef SEEK_SET
5498# define SEEK_SET 0
5499#endif
5500#ifndef SEEK_END
5501# define SEEK_END 2
5502#endif
5503
Bram Moolenaar5555acc2006-04-07 21:33:12 +00005504#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00005505
Bram Moolenaar071d4272004-06-13 20:20:40 +00005506 int
5507mch_expand_wildcards(num_pat, pat, num_file, file, flags)
5508 int num_pat;
5509 char_u **pat;
5510 int *num_file;
5511 char_u ***file;
5512 int flags; /* EW_* flags */
5513{
5514 int i;
5515 size_t len;
5516 char_u *p;
5517 int dir;
5518#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00005519 /*
5520 * This is the OS/2 implementation.
5521 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005522# define EXPL_ALLOC_INC 16
5523 char_u **expl_files;
5524 size_t files_alloced, files_free;
5525 char_u *buf;
5526 int has_wildcard;
5527
5528 *num_file = 0; /* default: no files found */
5529 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
5530 files_free = EXPL_ALLOC_INC; /* how much space is not used */
5531 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
5532 if (*file == NULL)
5533 return FAIL;
5534
5535 for (; num_pat > 0; num_pat--, pat++)
5536 {
5537 expl_files = NULL;
5538 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
5539 /* expand environment var or home dir */
5540 buf = expand_env_save(*pat);
5541 else
5542 buf = vim_strsave(*pat);
5543 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005544 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005545 if (has_wildcard) /* yes, so expand them */
5546 expl_files = (char_u **)_fnexplode(buf);
5547
5548 /*
5549 * return value of buf if no wildcards left,
5550 * OR if no match AND EW_NOTFOUND is set.
5551 */
5552 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
5553 || (expl_files == NULL && (flags & EW_NOTFOUND)))
5554 { /* simply save the current contents of *buf */
5555 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
5556 if (expl_files != NULL)
5557 {
5558 expl_files[0] = vim_strsave(buf);
5559 expl_files[1] = NULL;
5560 }
5561 }
5562 vim_free(buf);
5563
5564 /*
5565 * Count number of names resulting from expansion,
5566 * At the same time add a backslash to the end of names that happen to
5567 * be directories, and replace slashes with backslashes.
5568 */
5569 if (expl_files)
5570 {
5571 for (i = 0; (p = expl_files[i]) != NULL; i++)
5572 {
5573 dir = mch_isdir(p);
5574 /* If we don't want dirs and this is one, skip it */
5575 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5576 continue;
5577
Bram Moolenaara2031822006-03-07 22:29:51 +00005578 /* Skip files that are not executable if we check for that. */
5579 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
5580 continue;
5581
Bram Moolenaar071d4272004-06-13 20:20:40 +00005582 if (--files_free == 0)
5583 {
5584 /* need more room in table of pointers */
5585 files_alloced += EXPL_ALLOC_INC;
5586 *file = (char_u **)vim_realloc(*file,
5587 sizeof(char_u **) * files_alloced);
5588 if (*file == NULL)
5589 {
5590 EMSG(_(e_outofmem));
5591 *num_file = 0;
5592 return FAIL;
5593 }
5594 files_free = EXPL_ALLOC_INC;
5595 }
5596 slash_adjust(p);
5597 if (dir)
5598 {
5599 /* For a directory we add a '/', unless it's already
5600 * there. */
5601 len = STRLEN(p);
5602 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5603 {
5604 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005605 if (!after_pathsep((*file)[*num_file],
5606 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005607 {
5608 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005609 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005610 }
5611 }
5612 }
5613 else
5614 {
5615 (*file)[*num_file] = vim_strsave(p);
5616 }
5617
5618 /*
5619 * Error message already given by either alloc or vim_strsave.
5620 * Should return FAIL, but returning OK works also.
5621 */
5622 if ((*file)[*num_file] == NULL)
5623 break;
5624 (*num_file)++;
5625 }
5626 _fnexplodefree((char **)expl_files);
5627 }
5628 }
5629 return OK;
5630
5631#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005632 /*
5633 * This is the non-OS/2 implementation (really Unix).
5634 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005635 int j;
5636 char_u *tempname;
5637 char_u *command;
5638 FILE *fd;
5639 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005640#define STYLE_ECHO 0 /* use "echo", the default */
5641#define STYLE_GLOB 1 /* use "glob", for csh */
5642#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5643#define STYLE_PRINT 3 /* use "print -N", for zsh */
5644#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5645 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005646 int shell_style = STYLE_ECHO;
5647 int check_spaces;
5648 static int did_find_nul = FALSE;
5649 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005650 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005651 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005652
5653 *num_file = 0; /* default: no files found */
5654 *file = NULL;
5655
5656 /*
5657 * If there are no wildcards, just copy the names to allocated memory.
5658 * Saves a lot of time, because we don't have to start a new shell.
5659 */
5660 if (!have_wildcard(num_pat, pat))
5661 return save_patterns(num_pat, pat, num_file, file);
5662
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005663# ifdef HAVE_SANDBOX
5664 /* Don't allow any shell command in the sandbox. */
5665 if (sandbox != 0 && check_secure())
5666 return FAIL;
5667# endif
5668
Bram Moolenaar071d4272004-06-13 20:20:40 +00005669 /*
5670 * Don't allow the use of backticks in secure and restricted mode.
5671 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005672 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005673 for (i = 0; i < num_pat; ++i)
5674 if (vim_strchr(pat[i], '`') != NULL
5675 && (check_restricted() || check_secure()))
5676 return FAIL;
5677
5678 /*
5679 * get a name for the temp file
5680 */
5681 if ((tempname = vim_tempname('o')) == NULL)
5682 {
5683 EMSG(_(e_notmp));
5684 return FAIL;
5685 }
5686
5687 /*
5688 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005689 * file.
5690 * STYLE_BT: NL separated
5691 * If expanding `cmd` execute it directly.
5692 * STYLE_GLOB: NUL separated
5693 * If we use *csh, "glob" will work better than "echo".
5694 * STYLE_PRINT: NL or NUL separated
5695 * If we use *zsh, "print -N" will work better than "glob".
5696 * STYLE_VIMGLOB: NL separated
5697 * If we use *sh*, we define "vimglob()".
5698 * STYLE_ECHO: space separated.
5699 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005700 */
5701 if (num_pat == 1 && *pat[0] == '`'
5702 && (len = STRLEN(pat[0])) > 2
5703 && *(pat[0] + len - 1) == '`')
5704 shell_style = STYLE_BT;
5705 else if ((len = STRLEN(p_sh)) >= 3)
5706 {
5707 if (STRCMP(p_sh + len - 3, "csh") == 0)
5708 shell_style = STYLE_GLOB;
5709 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5710 shell_style = STYLE_PRINT;
5711 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005712 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5713 "sh") != NULL)
5714 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005715
Bram Moolenaarc7247912008-01-13 12:54:11 +00005716 /* Compute the length of the command. We need 2 extra bytes: for the
5717 * optional '&' and for the NUL.
5718 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005719 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005720 if (shell_style == STYLE_VIMGLOB)
5721 len += STRLEN(sh_vimglob_func);
5722
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005723 for (i = 0; i < num_pat; ++i)
5724 {
5725 /* Count the length of the patterns in the same way as they are put in
5726 * "command" below. */
5727#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005728 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005729#else
5730 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005731 for (j = 0; pat[i][j] != NUL; ++j)
5732 {
5733 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5734 ++len; /* may add a backslash */
5735 ++len;
5736 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005737#endif
5738 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005739 command = alloc(len);
5740 if (command == NULL)
5741 {
5742 /* out of memory */
5743 vim_free(tempname);
5744 return FAIL;
5745 }
5746
5747 /*
5748 * Build the shell command:
5749 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5750 * recognizes this).
5751 * - Add the shell command to print the expanded names.
5752 * - Add the temp file name.
5753 * - Add the file name patterns.
5754 */
5755 if (shell_style == STYLE_BT)
5756 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005757 /* change `command; command& ` to (command; command ) */
5758 STRCPY(command, "(");
5759 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005760 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005761 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005762 while (p > command && vim_iswhite(*p))
5763 --p;
5764 if (*p == '&') /* remove trailing '&' */
5765 {
5766 ampersent = TRUE;
5767 *p = ' ';
5768 }
5769 STRCAT(command, ">");
5770 }
5771 else
5772 {
5773 if (flags & EW_NOTFOUND)
5774 STRCPY(command, "set nonomatch; ");
5775 else
5776 STRCPY(command, "unset nonomatch; ");
5777 if (shell_style == STYLE_GLOB)
5778 STRCAT(command, "glob >");
5779 else if (shell_style == STYLE_PRINT)
5780 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005781 else if (shell_style == STYLE_VIMGLOB)
5782 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005783 else
5784 STRCAT(command, "echo >");
5785 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005786
Bram Moolenaar071d4272004-06-13 20:20:40 +00005787 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005788
Bram Moolenaar071d4272004-06-13 20:20:40 +00005789 if (shell_style != STYLE_BT)
5790 for (i = 0; i < num_pat; ++i)
5791 {
5792 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005793 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005794 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005795#ifdef USE_SYSTEM
5796 STRCAT(command, " \"");
5797 STRCAT(command, pat[i]);
5798 STRCAT(command, "\"");
5799#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005800 int intick = FALSE;
5801
Bram Moolenaar071d4272004-06-13 20:20:40 +00005802 p = command + STRLEN(command);
5803 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005804 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005805 {
5806 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005807 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005808 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5809 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005810 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005811 * backslash inside backticks, before a special character
5812 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005813 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005814 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5815 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005816 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005817 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005818 }
5819 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005820 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005821 /* Put a backslash before a special character, but not
5822 * when inside ``. */
5823 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005824
5825 /* Copy one character. */
5826 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005827 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005828 *p = NUL;
5829#endif
5830 }
5831 if (flags & EW_SILENT)
5832 show_shell_mess = FALSE;
5833 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00005834 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005835
5836 /*
5837 * Using zsh -G: If a pattern has no matches, it is just deleted from
5838 * the argument list, otherwise zsh gives an error message and doesn't
5839 * expand any other pattern.
5840 */
5841 if (shell_style == STYLE_PRINT)
5842 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5843
5844 /*
5845 * If we use -f then shell variables set in .cshrc won't get expanded.
5846 * vi can do it, so we will too, but it is only necessary if there is a "$"
5847 * in one of the patterns, otherwise we can still use the fast option.
5848 */
5849 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5850 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5851
5852 /*
5853 * execute the shell command
5854 */
5855 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5856
5857 /* When running in the background, give it some time to create the temp
5858 * file, but don't wait for it to finish. */
5859 if (ampersent)
5860 mch_delay(10L, TRUE);
5861
5862 extra_shell_arg = NULL; /* cleanup */
5863 show_shell_mess = TRUE;
5864 vim_free(command);
5865
Bram Moolenaarc7247912008-01-13 12:54:11 +00005866 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005867 {
5868 mch_remove(tempname);
5869 vim_free(tempname);
5870 /*
5871 * With interactive completion, the error message is not printed.
5872 * However with USE_SYSTEM, I don't know how to turn off error messages
5873 * from the shell, so screen may still get messed up -- webb.
5874 */
5875#ifndef USE_SYSTEM
5876 if (!(flags & EW_SILENT))
5877#endif
5878 {
5879 redraw_later_clear(); /* probably messed up screen */
5880 msg_putchar('\n'); /* clear bottom line quickly */
5881 cmdline_row = Rows - 1; /* continue on last line */
5882#ifdef USE_SYSTEM
5883 if (!(flags & EW_SILENT))
5884#endif
5885 {
5886 MSG(_(e_wildexpand));
5887 msg_start(); /* don't overwrite this message */
5888 }
5889 }
5890 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5891 * EW_NOTFOUND is given */
5892 if (shell_style == STYLE_BT)
5893 return FAIL;
5894 goto notfound;
5895 }
5896
5897 /*
5898 * read the names from the file into memory
5899 */
5900 fd = fopen((char *)tempname, READBIN);
5901 if (fd == NULL)
5902 {
5903 /* Something went wrong, perhaps a file name with a special char. */
5904 if (!(flags & EW_SILENT))
5905 {
5906 MSG(_(e_wildexpand));
5907 msg_start(); /* don't overwrite this message */
5908 }
5909 vim_free(tempname);
5910 goto notfound;
5911 }
5912 fseek(fd, 0L, SEEK_END);
5913 len = ftell(fd); /* get size of temp file */
5914 fseek(fd, 0L, SEEK_SET);
5915 buffer = alloc(len + 1);
5916 if (buffer == NULL)
5917 {
5918 /* out of memory */
5919 mch_remove(tempname);
5920 vim_free(tempname);
5921 fclose(fd);
5922 return FAIL;
5923 }
5924 i = fread((char *)buffer, 1, len, fd);
5925 fclose(fd);
5926 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00005927 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005928 {
5929 /* unexpected read error */
5930 EMSG2(_(e_notread), tempname);
5931 vim_free(tempname);
5932 vim_free(buffer);
5933 return FAIL;
5934 }
5935 vim_free(tempname);
5936
Bram Moolenaarc7247912008-01-13 12:54:11 +00005937# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005938 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5939 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02005940 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005941 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5942 *p++ = buffer[i];
5943 len = p - buffer;
5944# endif
5945
5946
5947 /* file names are separated with Space */
5948 if (shell_style == STYLE_ECHO)
5949 {
5950 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5951 p = buffer;
5952 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5953 {
5954 while (*p != ' ' && *p != '\n')
5955 ++p;
5956 p = skipwhite(p); /* skip to next entry */
5957 }
5958 }
5959 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005960 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005961 {
5962 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5963 p = buffer;
5964 for (i = 0; *p != NUL; ++i) /* count number of entries */
5965 {
5966 while (*p != '\n' && *p != NUL)
5967 ++p;
5968 if (*p != NUL)
5969 ++p;
5970 p = skipwhite(p); /* skip leading white space */
5971 }
5972 }
5973 /* file names are separated with NUL */
5974 else
5975 {
5976 /*
5977 * Some versions of zsh use spaces instead of NULs to separate
5978 * results. Only do this when there is no NUL before the end of the
5979 * buffer, otherwise we would never be able to use file names with
5980 * embedded spaces when zsh does use NULs.
5981 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5982 * don't check for spaces again.
5983 */
5984 check_spaces = FALSE;
5985 if (shell_style == STYLE_PRINT && !did_find_nul)
5986 {
5987 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02005988 buffer[len] = NUL;
Bram Moolenaar78a15312009-05-15 19:33:18 +00005989 if (len && (int)STRLEN(buffer) < (int)len - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005990 did_find_nul = TRUE;
5991 else
5992 check_spaces = TRUE;
5993 }
5994
5995 /*
5996 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5997 * already is one, for STYLE_GLOB it needs to be added.
5998 */
5999 if (len && buffer[len - 1] == NUL)
6000 --len;
6001 else
6002 buffer[len] = NUL;
6003 i = 0;
6004 for (p = buffer; p < buffer + len; ++p)
6005 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
6006 {
6007 ++i;
6008 *p = NUL;
6009 }
6010 if (len)
6011 ++i; /* count last entry */
6012 }
6013 if (i == 0)
6014 {
6015 /*
6016 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6017 * /bin/sh will happily expand it to nothing rather than returning an
6018 * error; and hey, it's good to check anyway -- webb.
6019 */
6020 vim_free(buffer);
6021 goto notfound;
6022 }
6023 *num_file = i;
6024 *file = (char_u **)alloc(sizeof(char_u *) * i);
6025 if (*file == NULL)
6026 {
6027 /* out of memory */
6028 vim_free(buffer);
6029 return FAIL;
6030 }
6031
6032 /*
6033 * Isolate the individual file names.
6034 */
6035 p = buffer;
6036 for (i = 0; i < *num_file; ++i)
6037 {
6038 (*file)[i] = p;
6039 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006040 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6041 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006042 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006043 while (!(shell_style == STYLE_ECHO && *p == ' ')
6044 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006045 ++p;
6046 if (p == buffer + len) /* last entry */
6047 *p = NUL;
6048 else
6049 {
6050 *p++ = NUL;
6051 p = skipwhite(p); /* skip to next entry */
6052 }
6053 }
6054 else /* NUL separates */
6055 {
6056 while (*p && p < buffer + len) /* skip entry */
6057 ++p;
6058 ++p; /* skip NUL */
6059 }
6060 }
6061
6062 /*
6063 * Move the file names to allocated memory.
6064 */
6065 for (j = 0, i = 0; i < *num_file; ++i)
6066 {
6067 /* Require the files to exist. Helps when using /bin/sh */
6068 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6069 continue;
6070
6071 /* check if this entry should be included */
6072 dir = (mch_isdir((*file)[i]));
6073 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6074 continue;
6075
Bram Moolenaara2031822006-03-07 22:29:51 +00006076 /* Skip files that are not executable if we check for that. */
6077 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
6078 continue;
6079
Bram Moolenaar071d4272004-06-13 20:20:40 +00006080 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
6081 if (p)
6082 {
6083 STRCPY(p, (*file)[i]);
6084 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00006085 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006086 (*file)[j++] = p;
6087 }
6088 }
6089 vim_free(buffer);
6090 *num_file = j;
6091
6092 if (*num_file == 0) /* rejected all entries */
6093 {
6094 vim_free(*file);
6095 *file = NULL;
6096 goto notfound;
6097 }
6098
6099 return OK;
6100
6101notfound:
6102 if (flags & EW_NOTFOUND)
6103 return save_patterns(num_pat, pat, num_file, file);
6104 return FAIL;
6105
6106#endif /* __EMX__ */
6107}
6108
6109#endif /* VMS */
6110
6111#ifndef __EMX__
6112 static int
6113save_patterns(num_pat, pat, num_file, file)
6114 int num_pat;
6115 char_u **pat;
6116 int *num_file;
6117 char_u ***file;
6118{
6119 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006120 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006121
6122 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
6123 if (*file == NULL)
6124 return FAIL;
6125 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006126 {
6127 s = vim_strsave(pat[i]);
6128 if (s != NULL)
6129 /* Be compatible with expand_filename(): halve the number of
6130 * backslashes. */
6131 backslash_halve(s);
6132 (*file)[i] = s;
6133 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006134 *num_file = num_pat;
6135 return OK;
6136}
6137#endif
6138
Bram Moolenaar071d4272004-06-13 20:20:40 +00006139/*
6140 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
6141 * expand.
6142 */
6143 int
6144mch_has_exp_wildcard(p)
6145 char_u *p;
6146{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006147 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006148 {
6149#ifndef OS2
6150 if (*p == '\\' && p[1] != NUL)
6151 ++p;
6152 else
6153#endif
6154 if (vim_strchr((char_u *)
6155#ifdef VMS
6156 "*?%"
6157#else
6158# ifdef OS2
6159 "*?"
6160# else
6161 "*?[{'"
6162# endif
6163#endif
6164 , *p) != NULL)
6165 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006166 }
6167 return FALSE;
6168}
6169
6170/*
6171 * Return TRUE if the string "p" contains a wildcard.
6172 * Don't recognize '~' at the end as a wildcard.
6173 */
6174 int
6175mch_has_wildcard(p)
6176 char_u *p;
6177{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006178 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006179 {
6180#ifndef OS2
6181 if (*p == '\\' && p[1] != NUL)
6182 ++p;
6183 else
6184#endif
6185 if (vim_strchr((char_u *)
6186#ifdef VMS
6187 "*?%$"
6188#else
6189# ifdef OS2
6190# ifdef VIM_BACKTICK
6191 "*?$`"
6192# else
6193 "*?$"
6194# endif
6195# else
6196 "*?[{`'$"
6197# endif
6198#endif
6199 , *p) != NULL
6200 || (*p == '~' && p[1] != NUL))
6201 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006202 }
6203 return FALSE;
6204}
6205
6206#ifndef __EMX__
6207 static int
6208have_wildcard(num, file)
6209 int num;
6210 char_u **file;
6211{
6212 int i;
6213
6214 for (i = 0; i < num; i++)
6215 if (mch_has_wildcard(file[i]))
6216 return 1;
6217 return 0;
6218}
6219
6220 static int
6221have_dollars(num, file)
6222 int num;
6223 char_u **file;
6224{
6225 int i;
6226
6227 for (i = 0; i < num; i++)
6228 if (vim_strchr(file[i], '$') != NULL)
6229 return TRUE;
6230 return FALSE;
6231}
6232#endif /* ifndef __EMX__ */
6233
6234#ifndef HAVE_RENAME
6235/*
6236 * Scaled-down version of rename(), which is missing in Xenix.
6237 * This version can only move regular files and will fail if the
6238 * destination exists.
6239 */
6240 int
6241mch_rename(src, dest)
6242 const char *src, *dest;
6243{
6244 struct stat st;
6245
6246 if (stat(dest, &st) >= 0) /* fail if destination exists */
6247 return -1;
6248 if (link(src, dest) != 0) /* link file to new name */
6249 return -1;
6250 if (mch_remove(src) == 0) /* delete link to old name */
6251 return 0;
6252 return -1;
6253}
6254#endif /* !HAVE_RENAME */
6255
6256#ifdef FEAT_MOUSE_GPM
6257/*
6258 * Initializes connection with gpm (if it isn't already opened)
6259 * Return 1 if succeeded (or connection already opened), 0 if failed
6260 */
6261 static int
6262gpm_open()
6263{
6264 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
6265
6266 if (!gpm_flag)
6267 {
6268 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
6269 gpm_connect.defaultMask = ~GPM_HARD;
6270 /* Default handling for mouse move*/
6271 gpm_connect.minMod = 0; /* Handle any modifier keys */
6272 gpm_connect.maxMod = 0xffff;
6273 if (Gpm_Open(&gpm_connect, 0) > 0)
6274 {
6275 /* gpm library tries to handling TSTP causes
6276 * problems. Anyways, we close connection to Gpm whenever
6277 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006278 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00006279 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006280# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00006281 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006282# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006283 return 1; /* succeed */
6284 }
6285 if (gpm_fd == -2)
6286 Gpm_Close(); /* We don't want to talk to xterm via gpm */
6287 return 0;
6288 }
6289 return 1; /* already open */
6290}
6291
6292/*
6293 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00006294 */
6295 static void
6296gpm_close()
6297{
6298 if (gpm_flag && gpm_fd >= 0) /* if Open */
6299 Gpm_Close();
6300}
6301
6302/* Reads gpm event and adds special keys to input buf. Returns length of
6303 * generated key sequence.
6304 * This function is made after gui_send_mouse_event
6305 */
6306 static int
6307mch_gpm_process()
6308{
6309 int button;
6310 static Gpm_Event gpm_event;
6311 char_u string[6];
6312 int_u vim_modifiers;
6313 int row,col;
6314 unsigned char buttons_mask;
6315 unsigned char gpm_modifiers;
6316 static unsigned char old_buttons = 0;
6317
6318 Gpm_GetEvent(&gpm_event);
6319
6320#ifdef FEAT_GUI
6321 /* Don't put events in the input queue now. */
6322 if (hold_gui_events)
6323 return 0;
6324#endif
6325
6326 row = gpm_event.y - 1;
6327 col = gpm_event.x - 1;
6328
6329 string[0] = ESC; /* Our termcode */
6330 string[1] = 'M';
6331 string[2] = 'G';
6332 switch (GPM_BARE_EVENTS(gpm_event.type))
6333 {
6334 case GPM_DRAG:
6335 string[3] = MOUSE_DRAG;
6336 break;
6337 case GPM_DOWN:
6338 buttons_mask = gpm_event.buttons & ~old_buttons;
6339 old_buttons = gpm_event.buttons;
6340 switch (buttons_mask)
6341 {
6342 case GPM_B_LEFT:
6343 button = MOUSE_LEFT;
6344 break;
6345 case GPM_B_MIDDLE:
6346 button = MOUSE_MIDDLE;
6347 break;
6348 case GPM_B_RIGHT:
6349 button = MOUSE_RIGHT;
6350 break;
6351 default:
6352 return 0;
6353 /*Don't know what to do. Can more than one button be
6354 * reported in one event? */
6355 }
6356 string[3] = (char_u)(button | 0x20);
6357 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
6358 break;
6359 case GPM_UP:
6360 string[3] = MOUSE_RELEASE;
6361 old_buttons &= ~gpm_event.buttons;
6362 break;
6363 default:
6364 return 0;
6365 }
6366 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
6367 gpm_modifiers = gpm_event.modifiers;
6368 vim_modifiers = 0x0;
6369 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
6370 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
6371 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
6372 */
6373 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
6374 vim_modifiers |= MOUSE_SHIFT;
6375
6376 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
6377 vim_modifiers |= MOUSE_CTRL;
6378 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
6379 vim_modifiers |= MOUSE_ALT;
6380 string[3] |= vim_modifiers;
6381 string[4] = (char_u)(col + ' ' + 1);
6382 string[5] = (char_u)(row + ' ' + 1);
6383 add_to_input_buf(string, 6);
6384 return 6;
6385}
6386#endif /* FEAT_MOUSE_GPM */
6387
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006388#ifdef FEAT_SYSMOUSE
6389/*
6390 * Initialize connection with sysmouse.
6391 * Let virtual console inform us with SIGUSR2 for pending sysmouse
6392 * output, any sysmouse output than will be processed via sig_sysmouse().
6393 * Return OK if succeeded, FAIL if failed.
6394 */
6395 static int
6396sysmouse_open()
6397{
6398 struct mouse_info mouse;
6399
6400 mouse.operation = MOUSE_MODE;
6401 mouse.u.mode.mode = 0;
6402 mouse.u.mode.signal = SIGUSR2;
6403 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
6404 {
6405 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
6406 mouse.operation = MOUSE_SHOW;
6407 ioctl(1, CONS_MOUSECTL, &mouse);
6408 return OK;
6409 }
6410 return FAIL;
6411}
6412
6413/*
6414 * Stop processing SIGUSR2 signals, and also make sure that
6415 * virtual console do not send us any sysmouse related signal.
6416 */
6417 static void
6418sysmouse_close()
6419{
6420 struct mouse_info mouse;
6421
6422 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
6423 mouse.operation = MOUSE_MODE;
6424 mouse.u.mode.mode = 0;
6425 mouse.u.mode.signal = 0;
6426 ioctl(1, CONS_MOUSECTL, &mouse);
6427}
6428
6429/*
6430 * Gets info from sysmouse and adds special keys to input buf.
6431 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006432 static RETSIGTYPE
6433sig_sysmouse SIGDEFARG(sigarg)
6434{
6435 struct mouse_info mouse;
6436 struct video_info video;
6437 char_u string[6];
6438 int row, col;
6439 int button;
6440 int buttons;
6441 static int oldbuttons = 0;
6442
6443#ifdef FEAT_GUI
6444 /* Don't put events in the input queue now. */
6445 if (hold_gui_events)
6446 return;
6447#endif
6448
6449 mouse.operation = MOUSE_GETINFO;
6450 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
6451 && ioctl(1, FBIO_MODEINFO, &video) != -1
6452 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
6453 && video.vi_cheight > 0 && video.vi_cwidth > 0)
6454 {
6455 row = mouse.u.data.y / video.vi_cheight;
6456 col = mouse.u.data.x / video.vi_cwidth;
6457 buttons = mouse.u.data.buttons;
6458 string[0] = ESC; /* Our termcode */
6459 string[1] = 'M';
6460 string[2] = 'S';
6461 if (oldbuttons == buttons && buttons != 0)
6462 {
6463 button = MOUSE_DRAG;
6464 }
6465 else
6466 {
6467 switch (buttons)
6468 {
6469 case 0:
6470 button = MOUSE_RELEASE;
6471 break;
6472 case 1:
6473 button = MOUSE_LEFT;
6474 break;
6475 case 2:
6476 button = MOUSE_MIDDLE;
6477 break;
6478 case 4:
6479 button = MOUSE_RIGHT;
6480 break;
6481 default:
6482 return;
6483 }
6484 oldbuttons = buttons;
6485 }
6486 string[3] = (char_u)(button);
6487 string[4] = (char_u)(col + ' ' + 1);
6488 string[5] = (char_u)(row + ' ' + 1);
6489 add_to_input_buf(string, 6);
6490 }
6491 return;
6492}
6493#endif /* FEAT_SYSMOUSE */
6494
Bram Moolenaar071d4272004-06-13 20:20:40 +00006495#if defined(FEAT_LIBCALL) || defined(PROTO)
6496typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
6497typedef char_u * (*INTPROCSTR)__ARGS((int));
6498typedef int (*STRPROCINT)__ARGS((char_u *));
6499typedef int (*INTPROCINT)__ARGS((int));
6500
6501/*
6502 * Call a DLL routine which takes either a string or int param
6503 * and returns an allocated string.
6504 */
6505 int
6506mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
6507 char_u *libname;
6508 char_u *funcname;
6509 char_u *argstring; /* NULL when using a argint */
6510 int argint;
6511 char_u **string_result;/* NULL when using number_result */
6512 int *number_result;
6513{
6514# if defined(USE_DLOPEN)
6515 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006516 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006517# else
6518 shl_t hinstLib;
6519# endif
6520 STRPROCSTR ProcAdd;
6521 INTPROCSTR ProcAddI;
6522 char_u *retval_str = NULL;
6523 int retval_int = 0;
6524 int success = FALSE;
6525
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006526 /*
6527 * Get a handle to the DLL module.
6528 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006529# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006530 /* First clear any error, it's not cleared by the dlopen() call. */
6531 (void)dlerror();
6532
Bram Moolenaar071d4272004-06-13 20:20:40 +00006533 hinstLib = dlopen((char *)libname, RTLD_LAZY
6534# ifdef RTLD_LOCAL
6535 | RTLD_LOCAL
6536# endif
6537 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006538 if (hinstLib == NULL)
6539 {
6540 /* "dlerr" must be used before dlclose() */
6541 dlerr = (char *)dlerror();
6542 if (dlerr != NULL)
6543 EMSG2(_("dlerror = \"%s\""), dlerr);
6544 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006545# else
6546 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
6547# endif
6548
6549 /* If the handle is valid, try to get the function address. */
6550 if (hinstLib != NULL)
6551 {
6552# ifdef HAVE_SETJMP_H
6553 /*
6554 * Catch a crash when calling the library function. For example when
6555 * using a number where a string pointer is expected.
6556 */
6557 mch_startjmp();
6558 if (SETJMP(lc_jump_env) != 0)
6559 {
6560 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006561# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006562 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006563# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006564 mch_didjmp();
6565 }
6566 else
6567# endif
6568 {
6569 retval_str = NULL;
6570 retval_int = 0;
6571
6572 if (argstring != NULL)
6573 {
6574# if defined(USE_DLOPEN)
6575 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006576 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006577# else
6578 if (shl_findsym(&hinstLib, (const char *)funcname,
6579 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
6580 ProcAdd = NULL;
6581# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006582 if ((success = (ProcAdd != NULL
6583# if defined(USE_DLOPEN)
6584 && dlerr == NULL
6585# endif
6586 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006587 {
6588 if (string_result == NULL)
6589 retval_int = ((STRPROCINT)ProcAdd)(argstring);
6590 else
6591 retval_str = (ProcAdd)(argstring);
6592 }
6593 }
6594 else
6595 {
6596# if defined(USE_DLOPEN)
6597 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006598 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006599# else
6600 if (shl_findsym(&hinstLib, (const char *)funcname,
6601 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
6602 ProcAddI = NULL;
6603# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006604 if ((success = (ProcAddI != NULL
6605# if defined(USE_DLOPEN)
6606 && dlerr == NULL
6607# endif
6608 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006609 {
6610 if (string_result == NULL)
6611 retval_int = ((INTPROCINT)ProcAddI)(argint);
6612 else
6613 retval_str = (ProcAddI)(argint);
6614 }
6615 }
6616
6617 /* Save the string before we free the library. */
6618 /* Assume that a "1" or "-1" result is an illegal pointer. */
6619 if (string_result == NULL)
6620 *number_result = retval_int;
6621 else if (retval_str != NULL
6622 && retval_str != (char_u *)1
6623 && retval_str != (char_u *)-1)
6624 *string_result = vim_strsave(retval_str);
6625 }
6626
6627# ifdef HAVE_SETJMP_H
6628 mch_endjmp();
6629# ifdef SIGHASARG
6630 if (lc_signal != 0)
6631 {
6632 int i;
6633
6634 /* try to find the name of this signal */
6635 for (i = 0; signal_info[i].sig != -1; i++)
6636 if (lc_signal == signal_info[i].sig)
6637 break;
6638 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6639 }
6640# endif
6641# endif
6642
Bram Moolenaar071d4272004-06-13 20:20:40 +00006643# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006644 /* "dlerr" must be used before dlclose() */
6645 if (dlerr != NULL)
6646 EMSG2(_("dlerror = \"%s\""), dlerr);
6647
6648 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006649 (void)dlclose(hinstLib);
6650# else
6651 (void)shl_unload(hinstLib);
6652# endif
6653 }
6654
6655 if (!success)
6656 {
6657 EMSG2(_(e_libcall), funcname);
6658 return FAIL;
6659 }
6660
6661 return OK;
6662}
6663#endif
6664
6665#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6666static int xterm_trace = -1; /* default: disabled */
6667static int xterm_button;
6668
6669/*
6670 * Setup a dummy window for X selections in a terminal.
6671 */
6672 void
6673setup_term_clip()
6674{
6675 int z = 0;
6676 char *strp = "";
6677 Widget AppShell;
6678
6679 if (!x_connect_to_server())
6680 return;
6681
6682 open_app_context();
6683 if (app_context != NULL && xterm_Shell == (Widget)0)
6684 {
6685 int (*oldhandler)();
6686#if defined(HAVE_SETJMP_H)
6687 int (*oldIOhandler)();
6688#endif
6689# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6690 struct timeval start_tv;
6691
6692 if (p_verbose > 0)
6693 gettimeofday(&start_tv, NULL);
6694# endif
6695
6696 /* Ignore X errors while opening the display */
6697 oldhandler = XSetErrorHandler(x_error_check);
6698
6699#if defined(HAVE_SETJMP_H)
6700 /* Ignore X IO errors while opening the display */
6701 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6702 mch_startjmp();
6703 if (SETJMP(lc_jump_env) != 0)
6704 {
6705 mch_didjmp();
6706 xterm_dpy = NULL;
6707 }
6708 else
6709#endif
6710 {
6711 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6712 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6713#if defined(HAVE_SETJMP_H)
6714 mch_endjmp();
6715#endif
6716 }
6717
6718#if defined(HAVE_SETJMP_H)
6719 /* Now handle X IO errors normally. */
6720 (void)XSetIOErrorHandler(oldIOhandler);
6721#endif
6722 /* Now handle X errors normally. */
6723 (void)XSetErrorHandler(oldhandler);
6724
6725 if (xterm_dpy == NULL)
6726 {
6727 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006728 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006729 return;
6730 }
6731
6732 /* Catch terminating error of the X server connection. */
6733 (void)XSetIOErrorHandler(x_IOerror_handler);
6734
6735# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6736 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006737 {
6738 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006739 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006740 verbose_leave();
6741 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006742# endif
6743
6744 /* Create a Shell to make converters work. */
6745 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6746 applicationShellWidgetClass, xterm_dpy,
6747 NULL);
6748 if (AppShell == (Widget)0)
6749 return;
6750 xterm_Shell = XtVaCreatePopupShell("VIM",
6751 topLevelShellWidgetClass, AppShell,
6752 XtNmappedWhenManaged, 0,
6753 XtNwidth, 1,
6754 XtNheight, 1,
6755 NULL);
6756 if (xterm_Shell == (Widget)0)
6757 return;
6758
6759 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02006760 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006761 if (x11_display == NULL)
6762 x11_display = xterm_dpy;
6763
6764 XtRealizeWidget(xterm_Shell);
6765 XSync(xterm_dpy, False);
6766 xterm_update();
6767 }
6768 if (xterm_Shell != (Widget)0)
6769 {
6770 clip_init(TRUE);
6771 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6772 x11_window = (Window)atol(strp);
6773 /* Check if $WINDOWID is valid. */
6774 if (test_x11_window(xterm_dpy) == FAIL)
6775 x11_window = 0;
6776 if (x11_window != 0)
6777 xterm_trace = 0;
6778 }
6779}
6780
6781 void
6782start_xterm_trace(button)
6783 int button;
6784{
6785 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6786 return;
6787 xterm_trace = 1;
6788 xterm_button = button;
6789 do_xterm_trace();
6790}
6791
6792
6793 void
6794stop_xterm_trace()
6795{
6796 if (xterm_trace < 0)
6797 return;
6798 xterm_trace = 0;
6799}
6800
6801/*
6802 * Query the xterm pointer and generate mouse termcodes if necessary
6803 * return TRUE if dragging is active, else FALSE
6804 */
6805 static int
6806do_xterm_trace()
6807{
6808 Window root, child;
6809 int root_x, root_y;
6810 int win_x, win_y;
6811 int row, col;
6812 int_u mask_return;
6813 char_u buf[50];
6814 char_u *strp;
6815 long got_hints;
6816 static char_u *mouse_code;
6817 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6818 static int prev_row = 0, prev_col = 0;
6819 static XSizeHints xterm_hints;
6820
6821 if (xterm_trace <= 0)
6822 return FALSE;
6823
6824 if (xterm_trace == 1)
6825 {
6826 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006827 * have changed recently. */
6828 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6829 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006830 || xterm_hints.width_inc <= 1
6831 || xterm_hints.height_inc <= 1)
6832 {
6833 xterm_trace = -1; /* Not enough data -- disable tracing */
6834 return FALSE;
6835 }
6836
6837 /* Rely on the same mouse code for the duration of this */
6838 mouse_code = find_termcode(mouse_name);
6839 prev_row = mouse_row;
6840 prev_row = mouse_col;
6841 xterm_trace = 2;
6842
6843 /* Find the offset of the chars, there might be a scrollbar on the
6844 * left of the window and/or a menu on the top (eterm etc.) */
6845 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6846 &win_x, &win_y, &mask_return);
6847 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6848 - (xterm_hints.height_inc / 2);
6849 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6850 xterm_hints.y = 2;
6851 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6852 - (xterm_hints.width_inc / 2);
6853 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6854 xterm_hints.x = 2;
6855 return TRUE;
6856 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006857 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006858 {
6859 xterm_trace = 0;
6860 return FALSE;
6861 }
6862
6863 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6864 &win_x, &win_y, &mask_return);
6865
6866 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6867 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6868 if (row == prev_row && col == prev_col)
6869 return TRUE;
6870
6871 STRCPY(buf, mouse_code);
6872 strp = buf + STRLEN(buf);
6873 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6874 *strp++ = (char_u)(col + ' ' + 1);
6875 *strp++ = (char_u)(row + ' ' + 1);
6876 *strp = 0;
6877 add_to_input_buf(buf, STRLEN(buf));
6878
6879 prev_row = row;
6880 prev_col = col;
6881 return TRUE;
6882}
6883
6884# if defined(FEAT_GUI) || defined(PROTO)
6885/*
6886 * Destroy the display, window and app_context. Required for GTK.
6887 */
6888 void
6889clear_xterm_clip()
6890{
6891 if (xterm_Shell != (Widget)0)
6892 {
6893 XtDestroyWidget(xterm_Shell);
6894 xterm_Shell = (Widget)0;
6895 }
6896 if (xterm_dpy != NULL)
6897 {
Bram Moolenaare8208012008-06-20 09:59:25 +00006898# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006899 /* Lesstif and Solaris crash here, lose some memory */
6900 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00006901# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006902 if (x11_display == xterm_dpy)
6903 x11_display = NULL;
6904 xterm_dpy = NULL;
6905 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006906# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006907 if (app_context != (XtAppContext)NULL)
6908 {
6909 /* Lesstif and Solaris crash here, lose some memory */
6910 XtDestroyApplicationContext(app_context);
6911 app_context = (XtAppContext)NULL;
6912 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006913# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006914}
6915# endif
6916
6917/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01006918 * Catch up with GUI or X events.
6919 */
6920 static void
6921clip_update()
6922{
6923# ifdef FEAT_GUI
6924 if (gui.in_use)
6925 gui_mch_update();
6926 else
6927# endif
6928 if (xterm_Shell != (Widget)0)
6929 xterm_update();
6930}
6931
6932/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006933 * Catch up with any queued X events. This may put keyboard input into the
6934 * input buffer, call resize call-backs, trigger timers etc. If there is
6935 * nothing in the X event queue (& no timers pending), then we return
6936 * immediately.
6937 */
6938 static void
6939xterm_update()
6940{
6941 XEvent event;
6942
6943 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6944 {
6945 XtAppNextEvent(app_context, &event);
6946#ifdef FEAT_CLIENTSERVER
6947 {
6948 XPropertyEvent *e = (XPropertyEvent *)&event;
6949
6950 if (e->type == PropertyNotify && e->window == commWindow
6951 && e->atom == commProperty && e->state == PropertyNewValue)
6952 serverEventProc(xterm_dpy, &event);
6953 }
6954#endif
6955 XtDispatchEvent(&event);
6956 }
6957}
6958
6959 int
6960clip_xterm_own_selection(cbd)
6961 VimClipboard *cbd;
6962{
6963 if (xterm_Shell != (Widget)0)
6964 return clip_x11_own_selection(xterm_Shell, cbd);
6965 return FAIL;
6966}
6967
6968 void
6969clip_xterm_lose_selection(cbd)
6970 VimClipboard *cbd;
6971{
6972 if (xterm_Shell != (Widget)0)
6973 clip_x11_lose_selection(xterm_Shell, cbd);
6974}
6975
6976 void
6977clip_xterm_request_selection(cbd)
6978 VimClipboard *cbd;
6979{
6980 if (xterm_Shell != (Widget)0)
6981 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6982}
6983
6984 void
6985clip_xterm_set_selection(cbd)
6986 VimClipboard *cbd;
6987{
6988 clip_x11_set_selection(cbd);
6989}
6990#endif
6991
6992
6993#if defined(USE_XSMP) || defined(PROTO)
6994/*
6995 * Code for X Session Management Protocol.
6996 */
6997static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6998static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6999static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
7000static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
7001static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
7002
7003
7004# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7005static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
7006
7007/*
7008 * This is our chance to ask the user if they want to save,
7009 * or abort the logout
7010 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007011 static void
7012xsmp_handle_interaction(smc_conn, client_data)
7013 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007014 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007015{
7016 cmdmod_T save_cmdmod;
7017 int cancel_shutdown = False;
7018
7019 save_cmdmod = cmdmod;
7020 cmdmod.confirm = TRUE;
7021 if (check_changed_any(FALSE))
7022 /* Mustn't logout */
7023 cancel_shutdown = True;
7024 cmdmod = save_cmdmod;
7025 setcursor(); /* position cursor */
7026 out_flush();
7027
7028 /* Done interaction */
7029 SmcInteractDone(smc_conn, cancel_shutdown);
7030
7031 /* Finish off
7032 * Only end save-yourself here if we're not cancelling shutdown;
7033 * we'll get a cancelled callback later in which we'll end it.
7034 * Hopefully get around glitchy SMs (like GNOME-1)
7035 */
7036 if (!cancel_shutdown)
7037 {
7038 xsmp.save_yourself = False;
7039 SmcSaveYourselfDone(smc_conn, True);
7040 }
7041}
7042# endif
7043
7044/*
7045 * Callback that starts save-yourself.
7046 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007047 static void
7048xsmp_handle_save_yourself(smc_conn, client_data, save_type,
7049 shutdown, interact_style, fast)
7050 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007051 SmPointer client_data UNUSED;
7052 int save_type UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007053 Bool shutdown;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007054 int interact_style UNUSED;
7055 Bool fast UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007056{
7057 /* Handle already being in saveyourself */
7058 if (xsmp.save_yourself)
7059 SmcSaveYourselfDone(smc_conn, True);
7060 xsmp.save_yourself = True;
7061 xsmp.shutdown = shutdown;
7062
7063 /* First up, preserve all files */
7064 out_flush();
7065 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
7066
7067 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007068 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007069
7070# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7071 /* Now see if we can ask about unsaved files */
7072 if (shutdown && !fast && gui.in_use)
7073 /* Need to interact with user, but need SM's permission */
7074 SmcInteractRequest(smc_conn, SmDialogError,
7075 xsmp_handle_interaction, client_data);
7076 else
7077# endif
7078 {
7079 /* Can stop the cycle here */
7080 SmcSaveYourselfDone(smc_conn, True);
7081 xsmp.save_yourself = False;
7082 }
7083}
7084
7085
7086/*
7087 * Callback to warn us of imminent death.
7088 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007089 static void
7090xsmp_die(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007091 SmcConn smc_conn UNUSED;
7092 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007093{
7094 xsmp_close();
7095
7096 /* quit quickly leaving swapfiles for modified buffers behind */
7097 getout_preserve_modified(0);
7098}
7099
7100
7101/*
7102 * Callback to tell us that save-yourself has completed.
7103 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007104 static void
7105xsmp_save_complete(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007106 SmcConn smc_conn UNUSED;
7107 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007108{
7109 xsmp.save_yourself = False;
7110}
7111
7112
7113/*
7114 * Callback to tell us that an instigated shutdown was cancelled
7115 * (maybe even by us)
7116 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007117 static void
7118xsmp_shutdown_cancelled(smc_conn, client_data)
7119 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007120 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007121{
7122 if (xsmp.save_yourself)
7123 SmcSaveYourselfDone(smc_conn, True);
7124 xsmp.save_yourself = False;
7125 xsmp.shutdown = False;
7126}
7127
7128
7129/*
7130 * Callback to tell us that a new ICE connection has been established.
7131 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007132 static void
7133xsmp_ice_connection(iceConn, clientData, opening, watchData)
7134 IceConn iceConn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007135 IcePointer clientData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007136 Bool opening;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007137 IcePointer *watchData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007138{
7139 /* Intercept creation of ICE connection fd */
7140 if (opening)
7141 {
7142 xsmp_icefd = IceConnectionNumber(iceConn);
7143 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7144 }
7145}
7146
7147
7148/* Handle any ICE processing that's required; return FAIL if SM lost */
7149 int
7150xsmp_handle_requests()
7151{
7152 Bool rep;
7153
7154 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7155 == IceProcessMessagesIOError)
7156 {
7157 /* Lost ICE */
7158 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007159 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007160 xsmp_close();
7161 return FAIL;
7162 }
7163 else
7164 return OK;
7165}
7166
7167static int dummy;
7168
7169/* Set up X Session Management Protocol */
7170 void
7171xsmp_init(void)
7172{
7173 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007174 SmcCallbacks smcallbacks;
7175#if 0
7176 SmPropValue smname;
7177 SmProp smnameprop;
7178 SmProp *smprops[1];
7179#endif
7180
7181 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007182 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007183
7184 xsmp.save_yourself = xsmp.shutdown = False;
7185
7186 /* Set up SM callbacks - must have all, even if they're not used */
7187 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
7188 smcallbacks.save_yourself.client_data = NULL;
7189 smcallbacks.die.callback = xsmp_die;
7190 smcallbacks.die.client_data = NULL;
7191 smcallbacks.save_complete.callback = xsmp_save_complete;
7192 smcallbacks.save_complete.client_data = NULL;
7193 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
7194 smcallbacks.shutdown_cancelled.client_data = NULL;
7195
7196 /* Set up a watch on ICE connection creations. The "dummy" argument is
7197 * apparently required for FreeBSD (we get a BUS error when using NULL). */
7198 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
7199 {
7200 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007201 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007202 return;
7203 }
7204
7205 /* Create an SM connection */
7206 xsmp.smcconn = SmcOpenConnection(
7207 NULL,
7208 NULL,
7209 SmProtoMajor,
7210 SmProtoMinor,
7211 SmcSaveYourselfProcMask | SmcDieProcMask
7212 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
7213 &smcallbacks,
7214 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00007215 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007216 sizeof(errorstring),
7217 errorstring);
7218 if (xsmp.smcconn == NULL)
7219 {
7220 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00007221
Bram Moolenaar071d4272004-06-13 20:20:40 +00007222 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007223 {
7224 vim_snprintf(errorreport, sizeof(errorreport),
7225 _("XSMP SmcOpenConnection failed: %s"), errorstring);
7226 verb_msg((char_u *)errorreport);
7227 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007228 return;
7229 }
7230 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
7231
7232#if 0
7233 /* ID ourselves */
7234 smname.value = "vim";
7235 smname.length = 3;
7236 smnameprop.name = "SmProgram";
7237 smnameprop.type = "SmARRAY8";
7238 smnameprop.num_vals = 1;
7239 smnameprop.vals = &smname;
7240
7241 smprops[0] = &smnameprop;
7242 SmcSetProperties(xsmp.smcconn, 1, smprops);
7243#endif
7244}
7245
7246
7247/* Shut down XSMP comms. */
7248 void
7249xsmp_close()
7250{
7251 if (xsmp_icefd != -1)
7252 {
7253 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00007254 if (xsmp.clientid != NULL)
7255 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00007256 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007257 xsmp_icefd = -1;
7258 }
7259}
7260#endif /* USE_XSMP */
7261
7262
7263#ifdef EBCDIC
7264/* Translate character to its CTRL- value */
7265char CtrlTable[] =
7266{
7267/* 00 - 5E */
7268 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7269 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7270 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7274/* ^ */ 0x1E,
7275/* - */ 0x1F,
7276/* 61 - 6C */
7277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7278/* _ */ 0x1F,
7279/* 6E - 80 */
7280 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7281/* a */ 0x01,
7282/* b */ 0x02,
7283/* c */ 0x03,
7284/* d */ 0x37,
7285/* e */ 0x2D,
7286/* f */ 0x2E,
7287/* g */ 0x2F,
7288/* h */ 0x16,
7289/* i */ 0x05,
7290/* 8A - 90 */
7291 0, 0, 0, 0, 0, 0, 0,
7292/* j */ 0x15,
7293/* k */ 0x0B,
7294/* l */ 0x0C,
7295/* m */ 0x0D,
7296/* n */ 0x0E,
7297/* o */ 0x0F,
7298/* p */ 0x10,
7299/* q */ 0x11,
7300/* r */ 0x12,
7301/* 9A - A1 */
7302 0, 0, 0, 0, 0, 0, 0, 0,
7303/* s */ 0x13,
7304/* t */ 0x3C,
7305/* u */ 0x3D,
7306/* v */ 0x32,
7307/* w */ 0x26,
7308/* x */ 0x18,
7309/* y */ 0x19,
7310/* z */ 0x3F,
7311/* AA - AC */
7312 0, 0, 0,
7313/* [ */ 0x27,
7314/* AE - BC */
7315 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7316/* ] */ 0x1D,
7317/* BE - C0 */ 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/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
7328/* J */ 0x15,
7329/* K */ 0x0B,
7330/* L */ 0x0C,
7331/* M */ 0x0D,
7332/* N */ 0x0E,
7333/* O */ 0x0F,
7334/* P */ 0x10,
7335/* Q */ 0x11,
7336/* R */ 0x12,
7337/* DA - DF */ 0, 0, 0, 0, 0, 0,
7338/* \ */ 0x1C,
7339/* E1 */ 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/* EA - FF*/ 0, 0, 0, 0, 0, 0,
7349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7350};
7351
7352char MetaCharTable[]=
7353{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7354 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
7355 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
7356 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
7357 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
7358};
7359
7360
7361/* TODO: Use characters NOT numbers!!! */
7362char CtrlCharTable[]=
7363{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7364 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
7365 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
7366 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
7367 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
7368};
7369
7370
7371#endif