blob: 9459aa1cf4b15e16da9775a691a7a683eb1ecca0 [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.
960 * It tries to preserve any swap file and exit properly.
961 * (partly from Elvis).
962 */
963 static RETSIGTYPE
964deathtrap SIGDEFARG(sigarg)
965{
966 static int entered = 0; /* count the number of times we got here.
967 Note: when memory has been corrupted
968 this may get an arbitrary value! */
969#ifdef SIGHASARG
970 int i;
971#endif
972
973#if defined(HAVE_SETJMP_H)
974 /*
975 * Catch a crash in protected code.
976 * Restores the environment saved in lc_jump_env, which looks like
977 * SETJMP() returns 1.
978 */
979 if (lc_active)
980 {
981# if defined(SIGHASARG)
982 lc_signal = sigarg;
983# endif
984 lc_active = FALSE; /* don't jump again */
985 LONGJMP(lc_jump_env, 1);
986 /* NOTREACHED */
987 }
988#endif
989
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000990#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000991# ifdef SIGQUIT
992 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
993 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
994 * pressing CTRL-\, but we don't want Vim to exit then. */
995 if (in_mch_delay && sigarg == SIGQUIT)
996 SIGRETURN;
997# endif
998
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000999 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
1000 * here. This avoids that a non-reentrant function is interrupted, e.g.,
1001 * free(). Calling free() again may then cause a crash. */
1002 if (entered == 0
1003 && (0
1004# ifdef SIGHUP
1005 || sigarg == SIGHUP
1006# endif
1007# ifdef SIGQUIT
1008 || sigarg == SIGQUIT
1009# endif
1010# ifdef SIGTERM
1011 || sigarg == SIGTERM
1012# endif
1013# ifdef SIGPWR
1014 || sigarg == SIGPWR
1015# endif
1016# ifdef SIGUSR1
1017 || sigarg == SIGUSR1
1018# endif
1019# ifdef SIGUSR2
1020 || sigarg == SIGUSR2
1021# endif
1022 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001023 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001024 SIGRETURN;
1025#endif
1026
Bram Moolenaar071d4272004-06-13 20:20:40 +00001027 /* Remember how often we have been called. */
1028 ++entered;
1029
1030#ifdef FEAT_EVAL
1031 /* Set the v:dying variable. */
1032 set_vim_var_nr(VV_DYING, (long)entered);
1033#endif
1034
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001035#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036 /* Since we are now using the signal stack, need to reset the stack
1037 * limit. Otherwise using a regexp will fail. */
1038 get_stack_limit();
1039#endif
1040
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001041#if 0
1042 /* This is for opening gdb the moment Vim crashes.
1043 * You need to manually adjust the file name and Vim executable name.
1044 * Suggested by SungHyun Nam. */
1045 {
1046# define VI_GDB_FILE "/tmp/vimgdb"
1047# define VIM_NAME "/usr/bin/vim"
1048 FILE *fp = fopen(VI_GDB_FILE, "w");
1049 if (fp)
1050 {
1051 fprintf(fp,
1052 "file %s\n"
1053 "attach %d\n"
1054 "set height 1000\n"
1055 "bt full\n"
1056 , VIM_NAME, getpid());
1057 fclose(fp);
1058 system("xterm -e gdb -x "VI_GDB_FILE);
1059 unlink(VI_GDB_FILE);
1060 }
1061 }
1062#endif
1063
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064#ifdef SIGHASARG
1065 /* try to find the name of this signal */
1066 for (i = 0; signal_info[i].sig != -1; i++)
1067 if (sigarg == signal_info[i].sig)
1068 break;
1069 deadly_signal = sigarg;
1070#endif
1071
1072 full_screen = FALSE; /* don't write message to the GUI, it might be
1073 * part of the problem... */
1074 /*
1075 * If something goes wrong after entering here, we may get here again.
1076 * When this happens, give a message and try to exit nicely (resetting the
1077 * terminal mode, etc.)
1078 * When this happens twice, just exit, don't even try to give a message,
1079 * stack may be corrupt or something weird.
1080 * When this still happens again (or memory was corrupted in such a way
1081 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1082 */
1083 if (entered >= 3)
1084 {
1085 reset_signals(); /* don't catch any signals anymore */
1086 may_core_dump();
1087 if (entered >= 4)
1088 _exit(8);
1089 exit(7);
1090 }
1091 if (entered == 2)
1092 {
1093 OUT_STR(_("Vim: Double signal, exiting\n"));
1094 out_flush();
1095 getout(1);
1096 }
1097
1098#ifdef SIGHASARG
1099 sprintf((char *)IObuff, _("Vim: Caught deadly signal %s\n"),
1100 signal_info[i].name);
1101#else
1102 sprintf((char *)IObuff, _("Vim: Caught deadly signal\n"));
1103#endif
1104 preserve_exit(); /* preserve files and exit */
1105
Bram Moolenaar009b2592004-10-24 19:18:58 +00001106#ifdef NBDEBUG
1107 reset_signals();
1108 may_core_dump();
1109 abort();
1110#endif
1111
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112 SIGRETURN;
1113}
1114
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001115#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001116/*
1117 * On Solaris with multi-threading, suspending might not work immediately.
1118 * Catch the SIGCONT signal, which will be used as an indication whether the
1119 * suspending has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001120 *
1121 * On Linux, signal is not always handled immediately either.
1122 * See https://bugs.launchpad.net/bugs/291373
1123 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001124 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001125 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001126static volatile int sigcont_received;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001127static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1128
1129/*
1130 * signal handler for SIGCONT
1131 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001132 static RETSIGTYPE
1133sigcont_handler SIGDEFARG(sigarg)
1134{
1135 sigcont_received = TRUE;
1136 SIGRETURN;
1137}
1138#endif
1139
Bram Moolenaar62b42182010-09-21 22:09:37 +02001140# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1141static void loose_clipboard __ARGS((void));
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001142# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001143static void save_clipboard __ARGS((void));
1144static void restore_clipboard __ARGS((void));
1145
1146static void *clip_star_save = NULL;
1147static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001148# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001149
1150/*
1151 * Called when Vim is going to sleep or execute a shell command.
1152 * We can't respond to requests for the X selections. Lose them, otherwise
1153 * other applications will hang. But first copy the text to cut buffer 0.
1154 */
1155 static void
1156loose_clipboard()
1157{
1158 if (clip_star.owned || clip_plus.owned)
1159 {
1160 x11_export_final_selection();
1161 if (clip_star.owned)
1162 clip_lose_selection(&clip_star);
1163 if (clip_plus.owned)
1164 clip_lose_selection(&clip_plus);
1165 if (x11_display != NULL)
1166 XFlush(x11_display);
1167 }
1168}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001169
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001170# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001171/*
1172 * Save clipboard text to restore later.
1173 */
1174 static void
1175save_clipboard()
1176{
1177 if (clip_star.owned)
1178 clip_star_save = get_register('*', TRUE);
1179 if (clip_plus.owned)
1180 clip_plus_save = get_register('+', TRUE);
1181}
1182
1183/*
1184 * Restore clipboard text if no one own the X selection.
1185 */
1186 static void
1187restore_clipboard()
1188{
1189 if (clip_star_save != NULL)
1190 {
1191 if (!clip_gen_owner_exists(&clip_star))
1192 put_register('*', clip_star_save);
1193 else
1194 free_register(clip_star_save);
1195 clip_star_save = NULL;
1196 }
1197 if (clip_plus_save != NULL)
1198 {
1199 if (!clip_gen_owner_exists(&clip_plus))
1200 put_register('+', clip_plus_save);
1201 else
1202 free_register(clip_plus_save);
1203 clip_plus_save = NULL;
1204 }
1205}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001206# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001207#endif
1208
Bram Moolenaar071d4272004-06-13 20:20:40 +00001209/*
1210 * If the machine has job control, use it to suspend the program,
1211 * otherwise fake it by starting a new shell.
1212 */
1213 void
1214mch_suspend()
1215{
1216 /* BeOS does have SIGTSTP, but it doesn't work. */
1217#if defined(SIGTSTP) && !defined(__BEOS__)
1218 out_flush(); /* needed to make cursor visible on some systems */
1219 settmode(TMODE_COOK);
1220 out_flush(); /* needed to disable mouse on some systems */
1221
1222# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001223 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001224# endif
1225
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001226# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001227 sigcont_received = FALSE;
1228# endif
1229 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001230# if defined(_REENTRANT) && defined(SIGCONT)
1231 /*
1232 * Wait for the SIGCONT signal to be handled. It generally happens
1233 * immediately, but somehow not all the time. Do not call pause()
1234 * because there would be race condition which would hang Vim if
1235 * signal happened in between the test of sigcont_received and the
1236 * call to pause(). If signal is not yet received, call sleep(0)
1237 * to just yield CPU. Signal should then be received. If somehow
1238 * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
1239 * further if signal is not received after 1+2+3+4 ms (not expected
1240 * to happen).
1241 */
1242 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001243 long wait_time;
1244 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001245 /* Loop is not entered most of the time */
Bram Moolenaar262735e2009-07-14 10:20:22 +00001246 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001247 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001248# endif
1249
1250# ifdef FEAT_TITLE
1251 /*
1252 * Set oldtitle to NULL, so the current title is obtained again.
1253 */
1254 vim_free(oldtitle);
1255 oldtitle = NULL;
1256# endif
1257 settmode(TMODE_RAW);
1258 need_check_timestamps = TRUE;
1259 did_check_timestamps = FALSE;
1260#else
1261 suspend_shell();
1262#endif
1263}
1264
1265 void
1266mch_init()
1267{
1268 Columns = 80;
1269 Rows = 24;
1270
1271 out_flush();
1272 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001273
Bram Moolenaar56718732006-03-15 22:53:57 +00001274#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001275 mac_conv_init();
1276#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001277#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1278 win_clip_init();
1279#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001280}
1281
1282 static void
1283set_signals()
1284{
1285#if defined(SIGWINCH)
1286 /*
1287 * WINDOW CHANGE signal is handled with sig_winch().
1288 */
1289 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1290#endif
1291
1292 /*
1293 * We want the STOP signal to work, to make mch_suspend() work.
1294 * For "rvim" the STOP signal is ignored.
1295 */
1296#ifdef SIGTSTP
1297 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1298#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001299#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001300 signal(SIGCONT, sigcont_handler);
1301#endif
1302
1303 /*
1304 * We want to ignore breaking of PIPEs.
1305 */
1306#ifdef SIGPIPE
1307 signal(SIGPIPE, SIG_IGN);
1308#endif
1309
Bram Moolenaar071d4272004-06-13 20:20:40 +00001310#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001311 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001312#endif
1313
1314 /*
1315 * Ignore alarm signals (Perl's alarm() generates it).
1316 */
1317#ifdef SIGALRM
1318 signal(SIGALRM, SIG_IGN);
1319#endif
1320
1321 /*
1322 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1323 * work will be lost.
1324 */
1325#ifdef SIGPWR
1326 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1327#endif
1328
1329 /*
1330 * Arrange for other signals to gracefully shutdown Vim.
1331 */
1332 catch_signals(deathtrap, SIG_ERR);
1333
1334#if defined(FEAT_GUI) && defined(SIGHUP)
1335 /*
1336 * When the GUI is running, ignore the hangup signal.
1337 */
1338 if (gui.in_use)
1339 signal(SIGHUP, SIG_IGN);
1340#endif
1341}
1342
Bram Moolenaardf177f62005-02-22 08:39:57 +00001343#if defined(SIGINT) || defined(PROTO)
1344/*
1345 * Catch CTRL-C (only works while in Cooked mode).
1346 */
1347 static void
1348catch_int_signal()
1349{
1350 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1351}
1352#endif
1353
Bram Moolenaar071d4272004-06-13 20:20:40 +00001354 void
1355reset_signals()
1356{
1357 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001358#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001359 /* SIGCONT isn't in the list, because its default action is ignore */
1360 signal(SIGCONT, SIG_DFL);
1361#endif
1362}
1363
1364 static void
1365catch_signals(func_deadly, func_other)
1366 RETSIGTYPE (*func_deadly)();
1367 RETSIGTYPE (*func_other)();
1368{
1369 int i;
1370
1371 for (i = 0; signal_info[i].sig != -1; i++)
1372 if (signal_info[i].deadly)
1373 {
1374#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1375 struct sigaction sa;
1376
1377 /* Setup to use the alternate stack for the signal function. */
1378 sa.sa_handler = func_deadly;
1379 sigemptyset(&sa.sa_mask);
1380# if defined(__linux__) && defined(_REENTRANT)
1381 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1382 * thread handling in combination with using the alternate stack:
1383 * pthread library functions try to use the stack pointer to
1384 * identify the current thread, causing a SEGV signal, which
1385 * recursively calls deathtrap() and hangs. */
1386 sa.sa_flags = 0;
1387# else
1388 sa.sa_flags = SA_ONSTACK;
1389# endif
1390 sigaction(signal_info[i].sig, &sa, NULL);
1391#else
1392# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1393 struct sigvec sv;
1394
1395 /* Setup to use the alternate stack for the signal function. */
1396 sv.sv_handler = func_deadly;
1397 sv.sv_mask = 0;
1398 sv.sv_flags = SV_ONSTACK;
1399 sigvec(signal_info[i].sig, &sv, NULL);
1400# else
1401 signal(signal_info[i].sig, func_deadly);
1402# endif
1403#endif
1404 }
1405 else if (func_other != SIG_ERR)
1406 signal(signal_info[i].sig, func_other);
1407}
1408
1409/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001410 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001411 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1412 * return TRUE
1413 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1414 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001415 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001416 * Returns TRUE when Vim should exit.
1417 */
1418 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001419vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001420 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001421{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001422 static int got_signal = 0;
1423 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001424
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001425 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001426 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001427 case SIGNAL_BLOCK: blocked = TRUE;
1428 break;
1429
1430 case SIGNAL_UNBLOCK: blocked = FALSE;
1431 if (got_signal != 0)
1432 {
1433 kill(getpid(), got_signal);
1434 got_signal = 0;
1435 }
1436 break;
1437
1438 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001439 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001440 got_signal = sig;
1441#ifdef SIGPWR
1442 if (sig != SIGPWR)
1443#endif
1444 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001445 break;
1446 }
1447 return FALSE;
1448}
1449
1450/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001451 * Check_win checks whether we have an interactive stdout.
1452 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001453 int
1454mch_check_win(argc, argv)
Bram Moolenaar78a15312009-05-15 19:33:18 +00001455 int argc UNUSED;
1456 char **argv UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001457{
1458#ifdef OS2
1459 /*
1460 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1461 * name, mostly it's just "vim" and found in the path, which is unusable.
1462 */
1463 if (mch_isFullName(argv[0]))
1464 exe_name = vim_strsave((char_u *)argv[0]);
1465#endif
1466 if (isatty(1))
1467 return OK;
1468 return FAIL;
1469}
1470
1471/*
1472 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1473 */
1474 int
1475mch_input_isatty()
1476{
1477 if (isatty(read_cmd_fd))
1478 return TRUE;
1479 return FALSE;
1480}
1481
1482#ifdef FEAT_X11
1483
1484# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1485 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1486
1487static void xopen_message __ARGS((struct timeval *tvp));
1488
1489/*
1490 * Give a message about the elapsed time for opening the X window.
1491 */
1492 static void
1493xopen_message(tvp)
1494 struct timeval *tvp; /* must contain start time */
1495{
1496 struct timeval end_tv;
1497
1498 /* Compute elapsed time. */
1499 gettimeofday(&end_tv, NULL);
1500 smsg((char_u *)_("Opening the X display took %ld msec"),
1501 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001502 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001503}
1504# endif
1505#endif
1506
1507#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1508/*
1509 * A few functions shared by X11 title and clipboard code.
1510 */
1511static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1512static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1513static int x_connect_to_server __ARGS((void));
1514static int test_x11_window __ARGS((Display *dpy));
1515
1516static int got_x_error = FALSE;
1517
1518/*
1519 * X Error handler, otherwise X just exits! (very rude) -- webb
1520 */
1521 static int
1522x_error_handler(dpy, error_event)
1523 Display *dpy;
1524 XErrorEvent *error_event;
1525{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001526 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001527 STRCAT(IObuff, _("\nVim: Got X error\n"));
1528
1529 /* We cannot print a message and continue, because no X calls are allowed
1530 * here (causes my system to hang). Silently continuing might be an
1531 * alternative... */
1532 preserve_exit(); /* preserve files and exit */
1533
1534 return 0; /* NOTREACHED */
1535}
1536
1537/*
1538 * Another X Error handler, just used to check for errors.
1539 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001540 static int
1541x_error_check(dpy, error_event)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001542 Display *dpy UNUSED;
1543 XErrorEvent *error_event UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001544{
1545 got_x_error = TRUE;
1546 return 0;
1547}
1548
1549#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1550# if defined(HAVE_SETJMP_H)
1551/*
1552 * An X IO Error handler, used to catch error while opening the display.
1553 */
1554static int x_IOerror_check __ARGS((Display *dpy));
1555
Bram Moolenaar071d4272004-06-13 20:20:40 +00001556 static int
1557x_IOerror_check(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001558 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001559{
1560 /* This function should not return, it causes exit(). Longjump instead. */
1561 LONGJMP(lc_jump_env, 1);
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001562# ifdef VMS
1563 return 0; /* avoid the compiler complains about missing return value */
1564# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001565}
1566# endif
1567
1568/*
1569 * An X IO Error handler, used to catch terminal errors.
1570 */
1571static int x_IOerror_handler __ARGS((Display *dpy));
1572
Bram Moolenaar071d4272004-06-13 20:20:40 +00001573 static int
1574x_IOerror_handler(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001575 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001576{
1577 xterm_dpy = NULL;
1578 x11_window = 0;
1579 x11_display = NULL;
1580 xterm_Shell = (Widget)0;
1581
1582 /* This function should not return, it causes exit(). Longjump instead. */
1583 LONGJMP(x_jump_env, 1);
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001584# ifdef VMS
1585 return 0; /* avoid the compiler complains about missing return value */
1586# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001587}
1588#endif
1589
1590/*
1591 * Return TRUE when connection to the X server is desired.
1592 */
1593 static int
1594x_connect_to_server()
1595{
1596 regmatch_T regmatch;
1597
1598#if defined(FEAT_CLIENTSERVER)
1599 if (x_force_connect)
1600 return TRUE;
1601#endif
1602 if (x_no_connect)
1603 return FALSE;
1604
1605 /* Check for a match with "exclude:" from 'clipboard'. */
1606 if (clip_exclude_prog != NULL)
1607 {
1608 regmatch.rm_ic = FALSE; /* Don't ignore case */
1609 regmatch.regprog = clip_exclude_prog;
1610 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1611 return FALSE;
1612 }
1613 return TRUE;
1614}
1615
1616/*
1617 * Test if "dpy" and x11_window are valid by getting the window title.
1618 * I don't actually want it yet, so there may be a simpler call to use, but
1619 * this will cause the error handler x_error_check() to be called if anything
1620 * is wrong, such as the window pointer being invalid (as can happen when the
1621 * user changes his DISPLAY, but not his WINDOWID) -- webb
1622 */
1623 static int
1624test_x11_window(dpy)
1625 Display *dpy;
1626{
1627 int (*old_handler)();
1628 XTextProperty text_prop;
1629
1630 old_handler = XSetErrorHandler(x_error_check);
1631 got_x_error = FALSE;
1632 if (XGetWMName(dpy, x11_window, &text_prop))
1633 XFree((void *)text_prop.value);
1634 XSync(dpy, False);
1635 (void)XSetErrorHandler(old_handler);
1636
1637 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001638 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639
1640 return (got_x_error ? FAIL : OK);
1641}
1642#endif
1643
1644#ifdef FEAT_TITLE
1645
1646#ifdef FEAT_X11
1647
1648static int get_x11_thing __ARGS((int get_title, int test_only));
1649
1650/*
1651 * try to get x11 window and display
1652 *
1653 * return FAIL for failure, OK otherwise
1654 */
1655 static int
1656get_x11_windis()
1657{
1658 char *winid;
1659 static int result = -1;
1660#define XD_NONE 0 /* x11_display not set here */
1661#define XD_HERE 1 /* x11_display opened here */
1662#define XD_GUI 2 /* x11_display used from gui.dpy */
1663#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1664 static int x11_display_from = XD_NONE;
1665 static int did_set_error_handler = FALSE;
1666
1667 if (!did_set_error_handler)
1668 {
1669 /* X just exits if it finds an error otherwise! */
1670 (void)XSetErrorHandler(x_error_handler);
1671 did_set_error_handler = TRUE;
1672 }
1673
Bram Moolenaar9372a112005-12-06 19:59:18 +00001674#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675 if (gui.in_use)
1676 {
1677 /*
1678 * If the X11 display was opened here before, for the window where Vim
1679 * was started, close that one now to avoid a memory leak.
1680 */
1681 if (x11_display_from == XD_HERE && x11_display != NULL)
1682 {
1683 XCloseDisplay(x11_display);
1684 x11_display_from = XD_NONE;
1685 }
1686 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1687 {
1688 x11_display_from = XD_GUI;
1689 return OK;
1690 }
1691 x11_display = NULL;
1692 return FAIL;
1693 }
1694 else if (x11_display_from == XD_GUI)
1695 {
1696 /* GUI must have stopped somehow, clear x11_display */
1697 x11_window = 0;
1698 x11_display = NULL;
1699 x11_display_from = XD_NONE;
1700 }
1701#endif
1702
1703 /* When started with the "-X" argument, don't try connecting. */
1704 if (!x_connect_to_server())
1705 return FAIL;
1706
1707 /*
1708 * If WINDOWID not set, should try another method to find out
1709 * what the current window number is. The only code I know for
1710 * this is very complicated.
1711 * We assume that zero is invalid for WINDOWID.
1712 */
1713 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1714 x11_window = (Window)atol(winid);
1715
1716#ifdef FEAT_XCLIPBOARD
1717 if (xterm_dpy != NULL && x11_window != 0)
1718 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001719 /* We may have checked it already, but Gnome terminal can move us to
1720 * another window, so we need to check every time. */
1721 if (x11_display_from != XD_XTERM)
1722 {
1723 /*
1724 * If the X11 display was opened here before, for the window where
1725 * Vim was started, close that one now to avoid a memory leak.
1726 */
1727 if (x11_display_from == XD_HERE && x11_display != NULL)
1728 XCloseDisplay(x11_display);
1729 x11_display = xterm_dpy;
1730 x11_display_from = XD_XTERM;
1731 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001732 if (test_x11_window(x11_display) == FAIL)
1733 {
1734 /* probably bad $WINDOWID */
1735 x11_window = 0;
1736 x11_display = NULL;
1737 x11_display_from = XD_NONE;
1738 return FAIL;
1739 }
1740 return OK;
1741 }
1742#endif
1743
1744 if (x11_window == 0 || x11_display == NULL)
1745 result = -1;
1746
1747 if (result != -1) /* Have already been here and set this */
1748 return result; /* Don't do all these X calls again */
1749
1750 if (x11_window != 0 && x11_display == NULL)
1751 {
1752#ifdef SET_SIG_ALARM
1753 RETSIGTYPE (*sig_save)();
1754#endif
1755#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1756 struct timeval start_tv;
1757
1758 if (p_verbose > 0)
1759 gettimeofday(&start_tv, NULL);
1760#endif
1761
1762#ifdef SET_SIG_ALARM
1763 /*
1764 * Opening the Display may hang if the DISPLAY setting is wrong, or
1765 * the network connection is bad. Set an alarm timer to get out.
1766 */
1767 sig_alarm_called = FALSE;
1768 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1769 (RETSIGTYPE (*)())sig_alarm);
1770 alarm(2);
1771#endif
1772 x11_display = XOpenDisplay(NULL);
1773
1774#ifdef SET_SIG_ALARM
1775 alarm(0);
1776 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1777 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001778 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001779#endif
1780 if (x11_display != NULL)
1781 {
1782# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1783 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001784 {
1785 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001786 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001787 verbose_leave();
1788 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001789# endif
1790 if (test_x11_window(x11_display) == FAIL)
1791 {
1792 /* Maybe window id is bad */
1793 x11_window = 0;
1794 XCloseDisplay(x11_display);
1795 x11_display = NULL;
1796 }
1797 else
1798 x11_display_from = XD_HERE;
1799 }
1800 }
1801 if (x11_window == 0 || x11_display == NULL)
1802 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001803
1804# ifdef FEAT_EVAL
1805 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1806# endif
1807
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808 return (result = OK);
1809}
1810
1811/*
1812 * Determine original x11 Window Title
1813 */
1814 static int
1815get_x11_title(test_only)
1816 int test_only;
1817{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001818 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819}
1820
1821/*
1822 * Determine original x11 Window icon
1823 */
1824 static int
1825get_x11_icon(test_only)
1826 int test_only;
1827{
1828 int retval = FALSE;
1829
1830 retval = get_x11_thing(FALSE, test_only);
1831
1832 /* could not get old icon, use terminal name */
1833 if (oldicon == NULL && !test_only)
1834 {
1835 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001836 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001837 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001838 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839 }
1840
1841 return retval;
1842}
1843
1844 static int
1845get_x11_thing(get_title, test_only)
1846 int get_title; /* get title string */
1847 int test_only;
1848{
1849 XTextProperty text_prop;
1850 int retval = FALSE;
1851 Status status;
1852
1853 if (get_x11_windis() == OK)
1854 {
1855 /* Get window/icon name if any */
1856 if (get_title)
1857 status = XGetWMName(x11_display, x11_window, &text_prop);
1858 else
1859 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1860
1861 /*
1862 * If terminal is xterm, then x11_window may be a child window of the
1863 * outer xterm window that actually contains the window/icon name, so
1864 * keep traversing up the tree until a window with a title/icon is
1865 * found.
1866 */
1867 /* Previously this was only done for xterm and alikes. I don't see a
1868 * reason why it would fail for other terminal emulators.
1869 * if (term_is_xterm) */
1870 {
1871 Window root;
1872 Window parent;
1873 Window win = x11_window;
1874 Window *children;
1875 unsigned int num_children;
1876
1877 while (!status || text_prop.value == NULL)
1878 {
1879 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1880 &num_children))
1881 break;
1882 if (children)
1883 XFree((void *)children);
1884 if (parent == root || parent == 0)
1885 break;
1886
1887 win = parent;
1888 if (get_title)
1889 status = XGetWMName(x11_display, win, &text_prop);
1890 else
1891 status = XGetWMIconName(x11_display, win, &text_prop);
1892 }
1893 }
1894 if (status && text_prop.value != NULL)
1895 {
1896 retval = TRUE;
1897 if (!test_only)
1898 {
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001899#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
1900 if (text_prop.encoding == XA_STRING
1901# ifdef FEAT_MBYTE
1902 && !has_mbyte
1903# endif
1904 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001905 {
1906#endif
1907 if (get_title)
1908 oldtitle = vim_strsave((char_u *)text_prop.value);
1909 else
1910 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001911#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001912 }
1913 else
1914 {
1915 char **cl;
1916 Status transform_status;
1917 int n = 0;
1918
1919 transform_status = XmbTextPropertyToTextList(x11_display,
1920 &text_prop,
1921 &cl, &n);
1922 if (transform_status >= Success && n > 0 && cl[0])
1923 {
1924 if (get_title)
1925 oldtitle = vim_strsave((char_u *) cl[0]);
1926 else
1927 oldicon = vim_strsave((char_u *) cl[0]);
1928 XFreeStringList(cl);
1929 }
1930 else
1931 {
1932 if (get_title)
1933 oldtitle = vim_strsave((char_u *)text_prop.value);
1934 else
1935 oldicon = vim_strsave((char_u *)text_prop.value);
1936 }
1937 }
1938#endif
1939 }
1940 XFree((void *)text_prop.value);
1941 }
1942 }
1943 return retval;
1944}
1945
1946/* Are Xutf8 functions available? Avoid error from old compilers. */
1947#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1948# if X_HAVE_UTF8_STRING
1949# define USE_UTF8_STRING
1950# endif
1951#endif
1952
1953/*
1954 * Set x11 Window Title
1955 *
1956 * get_x11_windis() must be called before this and have returned OK
1957 */
1958 static void
1959set_x11_title(title)
1960 char_u *title;
1961{
1962 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1963 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1964 * supported everywhere and STRING doesn't work for multi-byte titles.
1965 */
1966#ifdef USE_UTF8_STRING
1967 if (enc_utf8)
1968 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1969 NULL, NULL, 0, NULL, NULL, NULL);
1970 else
1971#endif
1972 {
1973#if XtSpecificationRelease >= 4
1974# ifdef FEAT_XFONTSET
1975 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1976 NULL, NULL, 0, NULL, NULL, NULL);
1977# else
1978 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001979 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001980
1981 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001982 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001983 XSetWMProperties(x11_display, x11_window, &text_prop,
1984 NULL, NULL, 0, NULL, NULL, NULL);
1985# endif
1986#else
1987 XStoreName(x11_display, x11_window, (char *)title);
1988#endif
1989 }
1990 XFlush(x11_display);
1991}
1992
1993/*
1994 * Set x11 Window icon
1995 *
1996 * get_x11_windis() must be called before this and have returned OK
1997 */
1998 static void
1999set_x11_icon(icon)
2000 char_u *icon;
2001{
2002 /* See above for comments about using X*SetWMProperties(). */
2003#ifdef USE_UTF8_STRING
2004 if (enc_utf8)
2005 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2006 NULL, 0, NULL, NULL, NULL);
2007 else
2008#endif
2009 {
2010#if XtSpecificationRelease >= 4
2011# ifdef FEAT_XFONTSET
2012 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2013 NULL, 0, NULL, NULL, NULL);
2014# else
2015 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002016 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002017
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002018 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002019 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2020 NULL, 0, NULL, NULL, NULL);
2021# endif
2022#else
2023 XSetIconName(x11_display, x11_window, (char *)icon);
2024#endif
2025 }
2026 XFlush(x11_display);
2027}
2028
2029#else /* FEAT_X11 */
2030
Bram Moolenaar071d4272004-06-13 20:20:40 +00002031 static int
2032get_x11_title(test_only)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002033 int test_only UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002034{
2035 return FALSE;
2036}
2037
2038 static int
2039get_x11_icon(test_only)
2040 int test_only;
2041{
2042 if (!test_only)
2043 {
2044 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002045 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002046 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002047 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002048 }
2049 return FALSE;
2050}
2051
2052#endif /* FEAT_X11 */
2053
2054 int
2055mch_can_restore_title()
2056{
2057 return get_x11_title(TRUE);
2058}
2059
2060 int
2061mch_can_restore_icon()
2062{
2063 return get_x11_icon(TRUE);
2064}
2065
2066/*
2067 * Set the window title and icon.
2068 */
2069 void
2070mch_settitle(title, icon)
2071 char_u *title;
2072 char_u *icon;
2073{
2074 int type = 0;
2075 static int recursive = 0;
2076
2077 if (T_NAME == NULL) /* no terminal name (yet) */
2078 return;
2079 if (title == NULL && icon == NULL) /* nothing to do */
2080 return;
2081
2082 /* When one of the X11 functions causes a deadly signal, we get here again
2083 * recursively. Avoid hanging then (something is probably locked). */
2084 if (recursive)
2085 return;
2086 ++recursive;
2087
2088 /*
2089 * if the window ID and the display is known, we may use X11 calls
2090 */
2091#ifdef FEAT_X11
2092 if (get_x11_windis() == OK)
2093 type = 1;
2094#else
2095# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2096 if (gui.in_use)
2097 type = 1;
2098# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002099#endif
2100
2101 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002102 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 * than x11 calls, because the x11 calls don't always work
2104 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002105 if ((type || *T_TS != NUL) && title != NULL)
2106 {
2107 if (oldtitle == NULL
2108#ifdef FEAT_GUI
2109 && !gui.in_use
2110#endif
2111 ) /* first call but not in GUI, save title */
2112 (void)get_x11_title(FALSE);
2113
2114 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2115 term_settitle(title);
2116#ifdef FEAT_X11
2117 else
2118# ifdef FEAT_GUI_GTK
2119 if (!gui.in_use) /* don't do this if GTK+ is running */
2120# endif
2121 set_x11_title(title); /* x11 */
2122#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002123#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002124 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2125 else
2126 gui_mch_settitle(title, icon);
2127#endif
2128 did_set_title = TRUE;
2129 }
2130
2131 if ((type || *T_CIS != NUL) && icon != NULL)
2132 {
2133 if (oldicon == NULL
2134#ifdef FEAT_GUI
2135 && !gui.in_use
2136#endif
2137 ) /* first call, save icon */
2138 get_x11_icon(FALSE);
2139
2140 if (*T_CIS != NUL)
2141 {
2142 out_str(T_CIS); /* set icon start */
2143 out_str_nf(icon);
2144 out_str(T_CIE); /* set icon end */
2145 out_flush();
2146 }
2147#ifdef FEAT_X11
2148 else
2149# ifdef FEAT_GUI_GTK
2150 if (!gui.in_use) /* don't do this if GTK+ is running */
2151# endif
2152 set_x11_icon(icon); /* x11 */
2153#endif
2154 did_set_icon = TRUE;
2155 }
2156 --recursive;
2157}
2158
2159/*
2160 * Restore the window/icon title.
2161 * "which" is one of:
2162 * 1 only restore title
2163 * 2 only restore icon
2164 * 3 restore title and icon
2165 */
2166 void
2167mch_restore_title(which)
2168 int which;
2169{
2170 /* only restore the title or icon when it has been set */
2171 mch_settitle(((which & 1) && did_set_title) ?
2172 (oldtitle ? oldtitle : p_titleold) : NULL,
2173 ((which & 2) && did_set_icon) ? oldicon : NULL);
2174}
2175
2176#endif /* FEAT_TITLE */
2177
2178/*
2179 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002180 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002181 */
2182 int
2183vim_is_xterm(name)
2184 char_u *name;
2185{
2186 if (name == NULL)
2187 return FALSE;
2188 return (STRNICMP(name, "xterm", 5) == 0
2189 || STRNICMP(name, "nxterm", 6) == 0
2190 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002191 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002192 || STRNICMP(name, "rxvt", 4) == 0
2193 || STRCMP(name, "builtin_xterm") == 0);
2194}
2195
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002196#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2197/*
2198 * Return TRUE if "name" appears to be that of a terminal
2199 * known to support the xterm-style mouse protocol.
2200 * Relies on term_is_xterm having been set to its correct value.
2201 */
2202 int
2203use_xterm_like_mouse(name)
2204 char_u *name;
2205{
2206 return (name != NULL
2207 && (term_is_xterm || STRNICMP(name, "screen", 6) == 0));
2208}
2209#endif
2210
Bram Moolenaar071d4272004-06-13 20:20:40 +00002211#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2212/*
2213 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2214 * Return 1 for "xterm".
2215 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002216 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002217 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002218 */
2219 int
2220use_xterm_mouse()
2221{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002222 if (ttym_flags == TTYM_SGR)
2223 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002224 if (ttym_flags == TTYM_URXVT)
2225 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226 if (ttym_flags == TTYM_XTERM2)
2227 return 2;
2228 if (ttym_flags == TTYM_XTERM)
2229 return 1;
2230 return 0;
2231}
2232#endif
2233
2234 int
2235vim_is_iris(name)
2236 char_u *name;
2237{
2238 if (name == NULL)
2239 return FALSE;
2240 return (STRNICMP(name, "iris-ansi", 9) == 0
2241 || STRCMP(name, "builtin_iris-ansi") == 0);
2242}
2243
2244 int
2245vim_is_vt300(name)
2246 char_u *name;
2247{
2248 if (name == NULL)
2249 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002250 /* catch VT100 - VT5xx */
2251 return ((STRNICMP(name, "vt", 2) == 0
2252 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002253 || STRCMP(name, "builtin_vt320") == 0);
2254}
2255
2256/*
2257 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2258 * This should include all windowed terminal emulators.
2259 */
2260 int
2261vim_is_fastterm(name)
2262 char_u *name;
2263{
2264 if (name == NULL)
2265 return FALSE;
2266 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2267 return TRUE;
2268 return ( STRNICMP(name, "hpterm", 6) == 0
2269 || STRNICMP(name, "sun-cmd", 7) == 0
2270 || STRNICMP(name, "screen", 6) == 0
2271 || STRNICMP(name, "dtterm", 6) == 0);
2272}
2273
2274/*
2275 * Insert user name in s[len].
2276 * Return OK if a name found.
2277 */
2278 int
2279mch_get_user_name(s, len)
2280 char_u *s;
2281 int len;
2282{
2283#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002284 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285 return OK;
2286#else
2287 return mch_get_uname(getuid(), s, len);
2288#endif
2289}
2290
2291/*
2292 * Insert user name for "uid" in s[len].
2293 * Return OK if a name found.
2294 */
2295 int
2296mch_get_uname(uid, s, len)
2297 uid_t uid;
2298 char_u *s;
2299 int len;
2300{
2301#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2302 struct passwd *pw;
2303
2304 if ((pw = getpwuid(uid)) != NULL
2305 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2306 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002307 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308 return OK;
2309 }
2310#endif
2311 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2312 return FAIL; /* a number is not a name */
2313}
2314
2315/*
2316 * Insert host name is s[len].
2317 */
2318
2319#ifdef HAVE_SYS_UTSNAME_H
2320 void
2321mch_get_host_name(s, len)
2322 char_u *s;
2323 int len;
2324{
2325 struct utsname vutsname;
2326
2327 if (uname(&vutsname) < 0)
2328 *s = NUL;
2329 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002330 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331}
2332#else /* HAVE_SYS_UTSNAME_H */
2333
2334# ifdef HAVE_SYS_SYSTEMINFO_H
2335# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2336# endif
2337
2338 void
2339mch_get_host_name(s, len)
2340 char_u *s;
2341 int len;
2342{
2343# ifdef VAXC
2344 vaxc$gethostname((char *)s, len);
2345# else
2346 gethostname((char *)s, len);
2347# endif
2348 s[len - 1] = NUL; /* make sure it's terminated */
2349}
2350#endif /* HAVE_SYS_UTSNAME_H */
2351
2352/*
2353 * return process ID
2354 */
2355 long
2356mch_get_pid()
2357{
2358 return (long)getpid();
2359}
2360
2361#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2362static char *strerror __ARGS((int));
2363
2364 static char *
2365strerror(err)
2366 int err;
2367{
2368 extern int sys_nerr;
2369 extern char *sys_errlist[];
2370 static char er[20];
2371
2372 if (err > 0 && err < sys_nerr)
2373 return (sys_errlist[err]);
2374 sprintf(er, "Error %d", err);
2375 return er;
2376}
2377#endif
2378
2379/*
2380 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2381 * Return OK for success, FAIL for failure.
2382 */
2383 int
2384mch_dirname(buf, len)
2385 char_u *buf;
2386 int len;
2387{
2388#if defined(USE_GETCWD)
2389 if (getcwd((char *)buf, len) == NULL)
2390 {
2391 STRCPY(buf, strerror(errno));
2392 return FAIL;
2393 }
2394 return OK;
2395#else
2396 return (getwd((char *)buf) != NULL ? OK : FAIL);
2397#endif
2398}
2399
2400#if defined(OS2) || defined(PROTO)
2401/*
2402 * Replace all slashes by backslashes.
2403 * When 'shellslash' set do it the other way around.
2404 */
2405 void
2406slash_adjust(p)
2407 char_u *p;
2408{
2409 while (*p)
2410 {
2411 if (*p == psepcN)
2412 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002413 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002414 }
2415}
2416#endif
2417
2418/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002419 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420 *
2421 * return FAIL for failure, OK for success
2422 */
2423 int
2424mch_FullName(fname, buf, len, force)
2425 char_u *fname, *buf;
2426 int len;
2427 int force; /* also expand when already absolute path */
2428{
2429 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002430#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002431 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002432#endif
2433#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434 int fd = -1;
2435 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002436#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437 char_u olddir[MAXPATHL];
2438 char_u *p;
2439 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002440#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002441 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2442 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002443#endif
2444
Bram Moolenaar38323e42007-03-06 19:22:53 +00002445#ifdef VMS
2446 fname = vms_fixfilename(fname);
2447#endif
2448
Bram Moolenaara2442432007-04-26 14:26:37 +00002449#ifdef __CYGWIN__
2450 /*
2451 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2452 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002453# if CYGWIN_VERSION_DLL_MAJOR >= 1007
2454 cygwin_conv_path(CCP_WIN_A_TO_POSIX, fname, posix_fname, MAXPATHL);
2455# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002456 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002457# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002458 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002459#endif
2460
Bram Moolenaar071d4272004-06-13 20:20:40 +00002461 /* expand it if forced or not an absolute path */
2462 if (force || !mch_isFullName(fname))
2463 {
2464 /*
2465 * If the file name has a path, change to that directory for a moment,
2466 * and then do the getwd() (and get back to where we were).
2467 * This will get the correct path name with "../" things.
2468 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002469#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 only_drive = 0;
2471 if (((p = vim_strrchr(fname, '/')) != NULL)
2472 || ((p = vim_strrchr(fname, '\\')) != NULL)
2473 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002474#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002475 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002476#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002478#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479 /*
2480 * Use fchdir() if possible, it's said to be faster and more
2481 * reliable. But on SunOS 4 it might not work. Check this by
2482 * doing a fchdir() right now.
2483 */
2484 if (!dont_fchdir)
2485 {
2486 fd = open(".", O_RDONLY | O_EXTRA, 0);
2487 if (fd >= 0 && fchdir(fd) < 0)
2488 {
2489 close(fd);
2490 fd = -1;
2491 dont_fchdir = TRUE; /* don't try again */
2492 }
2493 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002494#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002495
2496 /* Only change directory when we are sure we can return to where
2497 * we are now. After doing "su" chdir(".") might not work. */
2498 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002499#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002501#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 (mch_dirname(olddir, MAXPATHL) == FAIL
2503 || mch_chdir((char *)olddir) != 0))
2504 {
2505 p = NULL; /* can't get current dir: don't chdir */
2506 retval = FAIL;
2507 }
2508 else
2509 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002510#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002511 /*
2512 * compensate for case where ':' from "D:" was the only
2513 * path separator detected in the file name; the _next_
2514 * character has to be removed, and then restored later.
2515 */
2516 if (only_drive)
2517 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002518#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002519 /* The directory is copied into buf[], to be able to remove
2520 * the file name without changing it (could be a string in
2521 * read-only memory) */
2522 if (p - fname >= len)
2523 retval = FAIL;
2524 else
2525 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002526 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002527 if (mch_chdir((char *)buf))
2528 retval = FAIL;
2529 else
2530 fname = p + 1;
2531 *buf = NUL;
2532 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002533#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002534 if (only_drive)
2535 {
2536 p--;
2537 if (retval != FAIL)
2538 fname--;
2539 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002540#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002541 }
2542 }
2543 if (mch_dirname(buf, len) == FAIL)
2544 {
2545 retval = FAIL;
2546 *buf = NUL;
2547 }
2548 if (p != NULL)
2549 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002550#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002551 if (fd >= 0)
2552 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002553 if (p_verbose >= 5)
2554 {
2555 verbose_enter();
2556 MSG("fchdir() to previous dir");
2557 verbose_leave();
2558 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559 l = fchdir(fd);
2560 close(fd);
2561 }
2562 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002563#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002564 l = mch_chdir((char *)olddir);
2565 if (l != 0)
2566 EMSG(_(e_prev_dir));
2567 }
2568
2569 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002570 if (l >= len - 1)
2571 retval = FAIL; /* no space for trailing "/" */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002572#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002573 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002575 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002576#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002578
Bram Moolenaar071d4272004-06-13 20:20:40 +00002579 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002580 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002581 return FAIL;
2582
2583 /* Do not append ".", "/dir/." is equal to "/dir". */
2584 if (STRCMP(fname, ".") != 0)
2585 STRCAT(buf, fname);
2586
2587 return OK;
2588}
2589
2590/*
2591 * Return TRUE if "fname" does not depend on the current directory.
2592 */
2593 int
2594mch_isFullName(fname)
2595 char_u *fname;
2596{
2597#ifdef __EMX__
2598 return _fnisabs(fname);
2599#else
2600# ifdef VMS
2601 return ( fname[0] == '/' || fname[0] == '.' ||
2602 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2603 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2604 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2605# else
2606 return (*fname == '/' || *fname == '~');
2607# endif
2608#endif
2609}
2610
Bram Moolenaar24552be2005-12-10 20:17:30 +00002611#if defined(USE_FNAME_CASE) || defined(PROTO)
2612/*
2613 * Set the case of the file name, if it already exists. This will cause the
2614 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002615 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002616 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002617 void
2618fname_case(name, len)
2619 char_u *name;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002620 int len UNUSED; /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002621{
2622 struct stat st;
2623 char_u *slash, *tail;
2624 DIR *dirp;
2625 struct dirent *dp;
2626
2627 if (lstat((char *)name, &st) >= 0)
2628 {
2629 /* Open the directory where the file is located. */
2630 slash = vim_strrchr(name, '/');
2631 if (slash == NULL)
2632 {
2633 dirp = opendir(".");
2634 tail = name;
2635 }
2636 else
2637 {
2638 *slash = NUL;
2639 dirp = opendir((char *)name);
2640 *slash = '/';
2641 tail = slash + 1;
2642 }
2643
2644 if (dirp != NULL)
2645 {
2646 while ((dp = readdir(dirp)) != NULL)
2647 {
2648 /* Only accept names that differ in case and are the same byte
2649 * length. TODO: accept different length name. */
2650 if (STRICMP(tail, dp->d_name) == 0
2651 && STRLEN(tail) == STRLEN(dp->d_name))
2652 {
2653 char_u newname[MAXPATHL + 1];
2654 struct stat st2;
2655
2656 /* Verify the inode is equal. */
2657 vim_strncpy(newname, name, MAXPATHL);
2658 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2659 MAXPATHL - (tail - name));
2660 if (lstat((char *)newname, &st2) >= 0
2661 && st.st_ino == st2.st_ino
2662 && st.st_dev == st2.st_dev)
2663 {
2664 STRCPY(tail, dp->d_name);
2665 break;
2666 }
2667 }
2668 }
2669
2670 closedir(dirp);
2671 }
2672 }
2673}
2674#endif
2675
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676/*
2677 * Get file permissions for 'name'.
2678 * Returns -1 when it doesn't exist.
2679 */
2680 long
2681mch_getperm(name)
2682 char_u *name;
2683{
2684 struct stat statb;
2685
2686 /* Keep the #ifdef outside of stat(), it may be a macro. */
2687#ifdef VMS
2688 if (stat((char *)vms_fixfilename(name), &statb))
2689#else
2690 if (stat((char *)name, &statb))
2691#endif
2692 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002693#ifdef __INTERIX
2694 /* The top bit makes the value negative, which means the file doesn't
2695 * exist. Remove the bit, we don't use it. */
2696 return statb.st_mode & ~S_ADDACE;
2697#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002698 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002699#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002700}
2701
2702/*
2703 * set file permission for 'name' to 'perm'
2704 *
2705 * return FAIL for failure, OK otherwise
2706 */
2707 int
2708mch_setperm(name, perm)
2709 char_u *name;
2710 long perm;
2711{
2712 return (chmod((char *)
2713#ifdef VMS
2714 vms_fixfilename(name),
2715#else
2716 name,
2717#endif
2718 (mode_t)perm) == 0 ? OK : FAIL);
2719}
2720
2721#if defined(HAVE_ACL) || defined(PROTO)
2722# ifdef HAVE_SYS_ACL_H
2723# include <sys/acl.h>
2724# endif
2725# ifdef HAVE_SYS_ACCESS_H
2726# include <sys/access.h>
2727# endif
2728
2729# ifdef HAVE_SOLARIS_ACL
2730typedef struct vim_acl_solaris_T {
2731 int acl_cnt;
2732 aclent_t *acl_entry;
2733} vim_acl_solaris_T;
2734# endif
2735
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002736#if defined(HAVE_SELINUX) || defined(PROTO)
2737/*
2738 * Copy security info from "from_file" to "to_file".
2739 */
2740 void
2741mch_copy_sec(from_file, to_file)
2742 char_u *from_file;
2743 char_u *to_file;
2744{
2745 if (from_file == NULL)
2746 return;
2747
2748 if (selinux_enabled == -1)
2749 selinux_enabled = is_selinux_enabled();
2750
2751 if (selinux_enabled > 0)
2752 {
2753 security_context_t from_context = NULL;
2754 security_context_t to_context = NULL;
2755
2756 if (getfilecon((char *)from_file, &from_context) < 0)
2757 {
2758 /* If the filesystem doesn't support extended attributes,
2759 the original had no special security context and the
2760 target cannot have one either. */
2761 if (errno == EOPNOTSUPP)
2762 return;
2763
2764 MSG_PUTS(_("\nCould not get security context for "));
2765 msg_outtrans(from_file);
2766 msg_putchar('\n');
2767 return;
2768 }
2769 if (getfilecon((char *)to_file, &to_context) < 0)
2770 {
2771 MSG_PUTS(_("\nCould not get security context for "));
2772 msg_outtrans(to_file);
2773 msg_putchar('\n');
2774 freecon (from_context);
2775 return ;
2776 }
2777 if (strcmp(from_context, to_context) != 0)
2778 {
2779 if (setfilecon((char *)to_file, from_context) < 0)
2780 {
2781 MSG_PUTS(_("\nCould not set security context for "));
2782 msg_outtrans(to_file);
2783 msg_putchar('\n');
2784 }
2785 }
2786 freecon(to_context);
2787 freecon(from_context);
2788 }
2789}
2790#endif /* HAVE_SELINUX */
2791
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792/*
2793 * Return a pointer to the ACL of file "fname" in allocated memory.
2794 * Return NULL if the ACL is not available for whatever reason.
2795 */
2796 vim_acl_T
2797mch_get_acl(fname)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002798 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799{
2800 vim_acl_T ret = NULL;
2801#ifdef HAVE_POSIX_ACL
2802 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2803#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002804#ifdef HAVE_SOLARIS_ZFS_ACL
2805 acl_t *aclent;
2806
2807 if (acl_get((char *)fname, 0, &aclent) < 0)
2808 return NULL;
2809 ret = (vim_acl_T)aclent;
2810#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811#ifdef HAVE_SOLARIS_ACL
2812 vim_acl_solaris_T *aclent;
2813
2814 aclent = malloc(sizeof(vim_acl_solaris_T));
2815 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2816 {
2817 free(aclent);
2818 return NULL;
2819 }
2820 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2821 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2822 {
2823 free(aclent->acl_entry);
2824 free(aclent);
2825 return NULL;
2826 }
2827 ret = (vim_acl_T)aclent;
2828#else
2829#if defined(HAVE_AIX_ACL)
2830 int aclsize;
2831 struct acl *aclent;
2832
2833 aclsize = sizeof(struct acl);
2834 aclent = malloc(aclsize);
2835 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2836 {
2837 if (errno == ENOSPC)
2838 {
2839 aclsize = aclent->acl_len;
2840 aclent = realloc(aclent, aclsize);
2841 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2842 {
2843 free(aclent);
2844 return NULL;
2845 }
2846 }
2847 else
2848 {
2849 free(aclent);
2850 return NULL;
2851 }
2852 }
2853 ret = (vim_acl_T)aclent;
2854#endif /* HAVE_AIX_ACL */
2855#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002856#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002857#endif /* HAVE_POSIX_ACL */
2858 return ret;
2859}
2860
2861/*
2862 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2863 */
2864 void
2865mch_set_acl(fname, aclent)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002866 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002867 vim_acl_T aclent;
2868{
2869 if (aclent == NULL)
2870 return;
2871#ifdef HAVE_POSIX_ACL
2872 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2873#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002874#ifdef HAVE_SOLARIS_ZFS_ACL
2875 acl_set((char *)fname, (acl_t *)aclent);
2876#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002877#ifdef HAVE_SOLARIS_ACL
2878 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2879 ((vim_acl_solaris_T *)aclent)->acl_entry);
2880#else
2881#ifdef HAVE_AIX_ACL
2882 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2883#endif /* HAVE_AIX_ACL */
2884#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002885#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002886#endif /* HAVE_POSIX_ACL */
2887}
2888
2889 void
2890mch_free_acl(aclent)
2891 vim_acl_T aclent;
2892{
2893 if (aclent == NULL)
2894 return;
2895#ifdef HAVE_POSIX_ACL
2896 acl_free((acl_t)aclent);
2897#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002898#ifdef HAVE_SOLARIS_ZFS_ACL
2899 acl_free((acl_t *)aclent);
2900#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901#ifdef HAVE_SOLARIS_ACL
2902 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2903 free(aclent);
2904#else
2905#ifdef HAVE_AIX_ACL
2906 free(aclent);
2907#endif /* HAVE_AIX_ACL */
2908#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002909#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002910#endif /* HAVE_POSIX_ACL */
2911}
2912#endif
2913
2914/*
2915 * Set hidden flag for "name".
2916 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917 void
2918mch_hide(name)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002919 char_u *name UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002920{
2921 /* can't hide a file */
2922}
2923
2924/*
2925 * return TRUE if "name" is a directory
2926 * return FALSE if "name" is not a directory
2927 * return FALSE for error
2928 */
2929 int
2930mch_isdir(name)
2931 char_u *name;
2932{
2933 struct stat statb;
2934
2935 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2936 return FALSE;
2937 if (stat((char *)name, &statb))
2938 return FALSE;
2939#ifdef _POSIX_SOURCE
2940 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2941#else
2942 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2943#endif
2944}
2945
Bram Moolenaar071d4272004-06-13 20:20:40 +00002946static int executable_file __ARGS((char_u *name));
2947
2948/*
2949 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2950 */
2951 static int
2952executable_file(name)
2953 char_u *name;
2954{
2955 struct stat st;
2956
2957 if (stat((char *)name, &st))
2958 return 0;
2959 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2960}
2961
2962/*
2963 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2964 * Return -1 if unknown.
2965 */
2966 int
2967mch_can_exe(name)
2968 char_u *name;
2969{
2970 char_u *buf;
2971 char_u *p, *e;
2972 int retval;
2973
2974 /* If it's an absolute or relative path don't need to use $PATH. */
2975 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2976 || (name[1] == '.' && name[2] == '/'))))
2977 return executable_file(name);
2978
2979 p = (char_u *)getenv("PATH");
2980 if (p == NULL || *p == NUL)
2981 return -1;
2982 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2983 if (buf == NULL)
2984 return -1;
2985
2986 /*
2987 * Walk through all entries in $PATH to check if "name" exists there and
2988 * is an executable file.
2989 */
2990 for (;;)
2991 {
2992 e = (char_u *)strchr((char *)p, ':');
2993 if (e == NULL)
2994 e = p + STRLEN(p);
2995 if (e - p <= 1) /* empty entry means current dir */
2996 STRCPY(buf, "./");
2997 else
2998 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002999 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 add_pathsep(buf);
3001 }
3002 STRCAT(buf, name);
3003 retval = executable_file(buf);
3004 if (retval == 1)
3005 break;
3006
3007 if (*e != ':')
3008 break;
3009 p = e + 1;
3010 }
3011
3012 vim_free(buf);
3013 return retval;
3014}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015
3016/*
3017 * Check what "name" is:
3018 * NODE_NORMAL: file or directory (or doesn't exist)
3019 * NODE_WRITABLE: writable device, socket, fifo, etc.
3020 * NODE_OTHER: non-writable things
3021 */
3022 int
3023mch_nodetype(name)
3024 char_u *name;
3025{
3026 struct stat st;
3027
3028 if (stat((char *)name, &st))
3029 return NODE_NORMAL;
3030 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3031 return NODE_NORMAL;
3032#ifndef OS2
3033 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
3034 return NODE_OTHER;
3035#endif
3036 /* Everything else is writable? */
3037 return NODE_WRITABLE;
3038}
3039
3040 void
3041mch_early_init()
3042{
3043#ifdef HAVE_CHECK_STACK_GROWTH
3044 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003045
Bram Moolenaar071d4272004-06-13 20:20:40 +00003046 check_stack_growth((char *)&i);
3047
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003048# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003049 get_stack_limit();
3050# endif
3051
3052#endif
3053
3054 /*
3055 * Setup an alternative stack for signals. Helps to catch signals when
3056 * running out of stack space.
3057 * Use of sigaltstack() is preferred, it's more portable.
3058 * Ignore any errors.
3059 */
3060#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00003061 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003062 init_signal_stack();
3063#endif
3064}
3065
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003066#if defined(EXITFREE) || defined(PROTO)
3067 void
3068mch_free_mem()
3069{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003070# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3071 if (clip_star.owned)
3072 clip_lose_selection(&clip_star);
3073 if (clip_plus.owned)
3074 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003075# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003076# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003077 if (xterm_Shell != (Widget)0)
3078 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003079# ifndef LESSTIF_VERSION
3080 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003081 if (xterm_dpy != NULL)
3082 XtCloseDisplay(xterm_dpy);
3083 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003084 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003085 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003086# ifdef FEAT_X11
3087 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
3088# endif
3089 }
3090# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003091# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003092# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003093 if (x11_display != NULL
3094# ifdef FEAT_XCLIPBOARD
3095 && x11_display != xterm_dpy
3096# endif
3097 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003098 XCloseDisplay(x11_display);
3099# endif
3100# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
3101 vim_free(signal_stack);
3102 signal_stack = NULL;
3103# endif
3104# ifdef FEAT_TITLE
3105 vim_free(oldtitle);
3106 vim_free(oldicon);
3107# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003108}
3109#endif
3110
Bram Moolenaar071d4272004-06-13 20:20:40 +00003111static void exit_scroll __ARGS((void));
3112
3113/*
3114 * Output a newline when exiting.
3115 * Make sure the newline goes to the same stream as the text.
3116 */
3117 static void
3118exit_scroll()
3119{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003120 if (silent_mode)
3121 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003122 if (newline_on_exit || msg_didout)
3123 {
3124 if (msg_use_printf())
3125 {
3126 if (info_message)
3127 mch_msg("\n");
3128 else
3129 mch_errmsg("\r\n");
3130 }
3131 else
3132 out_char('\n');
3133 }
3134 else
3135 {
3136 restore_cterm_colors(); /* get original colors back */
3137 msg_clr_eos_force(); /* clear the rest of the display */
3138 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3139 }
3140}
3141
3142 void
3143mch_exit(r)
3144 int r;
3145{
3146 exiting = TRUE;
3147
3148#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3149 x11_export_final_selection();
3150#endif
3151
3152#ifdef FEAT_GUI
3153 if (!gui.in_use)
3154#endif
3155 {
3156 settmode(TMODE_COOK);
3157#ifdef FEAT_TITLE
3158 mch_restore_title(3); /* restore xterm title and icon name */
3159#endif
3160 /*
3161 * When t_ti is not empty but it doesn't cause swapping terminal
3162 * pages, need to output a newline when msg_didout is set. But when
3163 * t_ti does swap pages it should not go to the shell page. Do this
3164 * before stoptermcap().
3165 */
3166 if (swapping_screen() && !newline_on_exit)
3167 exit_scroll();
3168
3169 /* Stop termcap: May need to check for T_CRV response, which
3170 * requires RAW mode. */
3171 stoptermcap();
3172
3173 /*
3174 * A newline is only required after a message in the alternate screen.
3175 * This is set to TRUE by wait_return().
3176 */
3177 if (!swapping_screen() || newline_on_exit)
3178 exit_scroll();
3179
3180 /* Cursor may have been switched off without calling starttermcap()
3181 * when doing "vim -u vimrc" and vimrc contains ":q". */
3182 if (full_screen)
3183 cursor_on();
3184 }
3185 out_flush();
3186 ml_close_all(TRUE); /* remove all memfiles */
3187 may_core_dump();
3188#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003189 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003190 gui_exit(r);
3191#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003192
Bram Moolenaar56718732006-03-15 22:53:57 +00003193#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003194 mac_conv_cleanup();
3195#endif
3196
Bram Moolenaar071d4272004-06-13 20:20:40 +00003197#ifdef __QNX__
3198 /* A core dump won't be created if the signal handler
3199 * doesn't return, so we can't call exit() */
3200 if (deadly_signal != 0)
3201 return;
3202#endif
3203
Bram Moolenaar009b2592004-10-24 19:18:58 +00003204#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003205 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003206#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003207
3208#ifdef EXITFREE
3209 free_all_mem();
3210#endif
3211
Bram Moolenaar071d4272004-06-13 20:20:40 +00003212 exit(r);
3213}
3214
3215 static void
3216may_core_dump()
3217{
3218 if (deadly_signal != 0)
3219 {
3220 signal(deadly_signal, SIG_DFL);
3221 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3222 }
3223}
3224
3225#ifndef VMS
3226
3227 void
3228mch_settmode(tmode)
3229 int tmode;
3230{
3231 static int first = TRUE;
3232
3233 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3234#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3235 /*
3236 * for "new" tty systems
3237 */
3238# ifdef HAVE_TERMIOS_H
3239 static struct termios told;
3240 struct termios tnew;
3241# else
3242 static struct termio told;
3243 struct termio tnew;
3244# endif
3245
3246 if (first)
3247 {
3248 first = FALSE;
3249# if defined(HAVE_TERMIOS_H)
3250 tcgetattr(read_cmd_fd, &told);
3251# else
3252 ioctl(read_cmd_fd, TCGETA, &told);
3253# endif
3254 }
3255
3256 tnew = told;
3257 if (tmode == TMODE_RAW)
3258 {
3259 /*
3260 * ~ICRNL enables typing ^V^M
3261 */
3262 tnew.c_iflag &= ~ICRNL;
3263 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3264# if defined(IEXTEN) && !defined(__MINT__)
3265 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3266 /* but it breaks function keys on MINT */
3267# endif
3268 );
3269# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3270 tnew.c_oflag &= ~ONLCR;
3271# endif
3272 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3273 tnew.c_cc[VTIME] = 0; /* don't wait */
3274 }
3275 else if (tmode == TMODE_SLEEP)
3276 tnew.c_lflag &= ~(ECHO);
3277
3278# if defined(HAVE_TERMIOS_H)
3279 {
3280 int n = 10;
3281
3282 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3283 * few times. */
3284 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3285 && errno == EINTR && n > 0)
3286 --n;
3287 }
3288# else
3289 ioctl(read_cmd_fd, TCSETA, &tnew);
3290# endif
3291
3292#else
3293
3294 /*
3295 * for "old" tty systems
3296 */
3297# ifndef TIOCSETN
3298# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3299# endif
3300 static struct sgttyb ttybold;
3301 struct sgttyb ttybnew;
3302
3303 if (first)
3304 {
3305 first = FALSE;
3306 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3307 }
3308
3309 ttybnew = ttybold;
3310 if (tmode == TMODE_RAW)
3311 {
3312 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3313 ttybnew.sg_flags |= RAW;
3314 }
3315 else if (tmode == TMODE_SLEEP)
3316 ttybnew.sg_flags &= ~(ECHO);
3317 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3318#endif
3319 curr_tmode = tmode;
3320}
3321
3322/*
3323 * Try to get the code for "t_kb" from the stty setting
3324 *
3325 * Even if termcap claims a backspace key, the user's setting *should*
3326 * prevail. stty knows more about reality than termcap does, and if
3327 * somebody's usual erase key is DEL (which, for most BSD users, it will
3328 * be), they're going to get really annoyed if their erase key starts
3329 * doing forward deletes for no reason. (Eric Fischer)
3330 */
3331 void
3332get_stty()
3333{
3334 char_u buf[2];
3335 char_u *p;
3336
3337 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3338#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3339 /* for "new" tty systems */
3340# ifdef HAVE_TERMIOS_H
3341 struct termios keys;
3342# else
3343 struct termio keys;
3344# endif
3345
3346# if defined(HAVE_TERMIOS_H)
3347 if (tcgetattr(read_cmd_fd, &keys) != -1)
3348# else
3349 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3350# endif
3351 {
3352 buf[0] = keys.c_cc[VERASE];
3353 intr_char = keys.c_cc[VINTR];
3354#else
3355 /* for "old" tty systems */
3356 struct sgttyb keys;
3357
3358 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3359 {
3360 buf[0] = keys.sg_erase;
3361 intr_char = keys.sg_kill;
3362#endif
3363 buf[1] = NUL;
3364 add_termcode((char_u *)"kb", buf, FALSE);
3365
3366 /*
3367 * If <BS> and <DEL> are now the same, redefine <DEL>.
3368 */
3369 p = find_termcode((char_u *)"kD");
3370 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3371 do_fixdel(NULL);
3372 }
3373#if 0
3374 } /* to keep cindent happy */
3375#endif
3376}
3377
3378#endif /* VMS */
3379
3380#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3381/*
3382 * Set mouse clicks on or off.
3383 */
3384 void
3385mch_setmouse(on)
3386 int on;
3387{
3388 static int ison = FALSE;
3389 int xterm_mouse_vers;
3390
3391 if (on == ison) /* return quickly if nothing to do */
3392 return;
3393
3394 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003395
3396# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003397 if (ttym_flags == TTYM_URXVT)
3398 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003399 out_str_nf((char_u *)
3400 (on
3401 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3402 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
3403 ison = on;
3404 }
3405# endif
3406
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003407# ifdef FEAT_MOUSE_SGR
3408 if (ttym_flags == TTYM_SGR)
3409 {
3410 out_str_nf((char_u *)
3411 (on
3412 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3413 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
3414 ison = on;
3415 }
3416# endif
3417
Bram Moolenaar071d4272004-06-13 20:20:40 +00003418 if (xterm_mouse_vers > 0)
3419 {
3420 if (on) /* enable mouse events, use mouse tracking if available */
3421 out_str_nf((char_u *)
3422 (xterm_mouse_vers > 1
3423 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3424 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3425 else /* disable mouse events, could probably always send the same */
3426 out_str_nf((char_u *)
3427 (xterm_mouse_vers > 1
3428 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3429 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3430 ison = on;
3431 }
3432
3433# ifdef FEAT_MOUSE_DEC
3434 else if (ttym_flags == TTYM_DEC)
3435 {
3436 if (on) /* enable mouse events */
3437 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3438 else /* disable mouse events */
3439 out_str_nf((char_u *)"\033['z");
3440 ison = on;
3441 }
3442# endif
3443
3444# ifdef FEAT_MOUSE_GPM
3445 else
3446 {
3447 if (on)
3448 {
3449 if (gpm_open())
3450 ison = TRUE;
3451 }
3452 else
3453 {
3454 gpm_close();
3455 ison = FALSE;
3456 }
3457 }
3458# endif
3459
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003460# ifdef FEAT_SYSMOUSE
3461 else
3462 {
3463 if (on)
3464 {
3465 if (sysmouse_open() == OK)
3466 ison = TRUE;
3467 }
3468 else
3469 {
3470 sysmouse_close();
3471 ison = FALSE;
3472 }
3473 }
3474# endif
3475
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476# ifdef FEAT_MOUSE_JSB
3477 else
3478 {
3479 if (on)
3480 {
3481 /* D - Enable Mouse up/down messages
3482 * L - Enable Left Button Reporting
3483 * M - Enable Middle Button Reporting
3484 * R - Enable Right Button Reporting
3485 * K - Enable SHIFT and CTRL key Reporting
3486 * + - Enable Advanced messaging of mouse moves and up/down messages
3487 * Q - Quiet No Ack
3488 * # - Numeric value of mouse pointer required
3489 * 0 = Multiview 2000 cursor, used as standard
3490 * 1 = Windows Arrow
3491 * 2 = Windows I Beam
3492 * 3 = Windows Hour Glass
3493 * 4 = Windows Cross Hair
3494 * 5 = Windows UP Arrow
3495 */
3496#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3497 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3498 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3499#else
3500 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3501 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3502#endif
3503 ison = TRUE;
3504 }
3505 else
3506 {
3507 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3508 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3509 ison = FALSE;
3510 }
3511 }
3512# endif
3513# ifdef FEAT_MOUSE_PTERM
3514 else
3515 {
3516 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3517 if (on)
3518 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3519 else
3520 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3521 ison = on;
3522 }
3523# endif
3524}
3525
3526/*
3527 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3528 */
3529 void
3530check_mouse_termcode()
3531{
3532# ifdef FEAT_MOUSE_XTERM
3533 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003534# ifdef FEAT_MOUSE_URXVT
3535 && use_xterm_mouse() != 3
3536# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537# ifdef FEAT_GUI
3538 && !gui.in_use
3539# endif
3540 )
3541 {
3542 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003543 ? IF_EB("\233M", CSI_STR "M")
3544 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003545 if (*p_mouse != NUL)
3546 {
3547 /* force mouse off and maybe on to send possibly new mouse
3548 * activation sequence to the xterm, with(out) drag tracing. */
3549 mch_setmouse(FALSE);
3550 setmouse();
3551 }
3552 }
3553 else
3554 del_mouse_termcode(KS_MOUSE);
3555# endif
3556
3557# ifdef FEAT_MOUSE_GPM
3558 if (!use_xterm_mouse()
3559# ifdef FEAT_GUI
3560 && !gui.in_use
3561# endif
3562 )
3563 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3564# endif
3565
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003566# ifdef FEAT_SYSMOUSE
3567 if (!use_xterm_mouse()
3568# ifdef FEAT_GUI
3569 && !gui.in_use
3570# endif
3571 )
3572 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3573# endif
3574
Bram Moolenaar071d4272004-06-13 20:20:40 +00003575# ifdef FEAT_MOUSE_JSB
3576 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3577 if (!use_xterm_mouse()
3578# ifdef FEAT_GUI
3579 && !gui.in_use
3580# endif
3581 )
3582 set_mouse_termcode(KS_JSBTERM_MOUSE,
3583 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3584 else
3585 del_mouse_termcode(KS_JSBTERM_MOUSE);
3586# endif
3587
3588# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003589 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590 * define it in the GUI or when using an xterm. */
3591 if (!use_xterm_mouse()
3592# ifdef FEAT_GUI
3593 && !gui.in_use
3594# endif
3595 )
3596 set_mouse_termcode(KS_NETTERM_MOUSE,
3597 (char_u *)IF_EB("\033}", ESC_STR "}"));
3598 else
3599 del_mouse_termcode(KS_NETTERM_MOUSE);
3600# endif
3601
3602# ifdef FEAT_MOUSE_DEC
3603 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3604 if (!use_xterm_mouse()
3605# ifdef FEAT_GUI
3606 && !gui.in_use
3607# endif
3608 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003609 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3610 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003611 else
3612 del_mouse_termcode(KS_DEC_MOUSE);
3613# endif
3614# ifdef FEAT_MOUSE_PTERM
3615 /* same as the dec mouse */
3616 if (!use_xterm_mouse()
3617# ifdef FEAT_GUI
3618 && !gui.in_use
3619# endif
3620 )
3621 set_mouse_termcode(KS_PTERM_MOUSE,
3622 (char_u *) IF_EB("\033[", ESC_STR "["));
3623 else
3624 del_mouse_termcode(KS_PTERM_MOUSE);
3625# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003626# ifdef FEAT_MOUSE_URXVT
3627 /* same as the dec mouse */
3628 if (use_xterm_mouse() == 3
3629# ifdef FEAT_GUI
3630 && !gui.in_use
3631# endif
3632 )
3633 {
3634 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3635 ? IF_EB("\233", CSI_STR)
3636 : IF_EB("\033[", ESC_STR "[")));
3637
3638 if (*p_mouse != NUL)
3639 {
3640 mch_setmouse(FALSE);
3641 setmouse();
3642 }
3643 }
3644 else
3645 del_mouse_termcode(KS_URXVT_MOUSE);
3646# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003647# ifdef FEAT_MOUSE_SGR
3648 /* same as the dec mouse */
3649 if (use_xterm_mouse() == 4
3650# ifdef FEAT_GUI
3651 && !gui.in_use
3652# endif
3653 )
3654 {
3655 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3656 ? IF_EB("\233<", CSI_STR "<")
3657 : IF_EB("\033[<", ESC_STR "[<")));
3658
3659 if (*p_mouse != NUL)
3660 {
3661 mch_setmouse(FALSE);
3662 setmouse();
3663 }
3664 }
3665 else
3666 del_mouse_termcode(KS_SGR_MOUSE);
3667# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003668}
3669#endif
3670
3671/*
3672 * set screen mode, always fails.
3673 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003674 int
3675mch_screenmode(arg)
Bram Moolenaar78a15312009-05-15 19:33:18 +00003676 char_u *arg UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003677{
3678 EMSG(_(e_screenmode));
3679 return FAIL;
3680}
3681
3682#ifndef VMS
3683
3684/*
3685 * Try to get the current window size:
3686 * 1. with an ioctl(), most accurate method
3687 * 2. from the environment variables LINES and COLUMNS
3688 * 3. from the termcap
3689 * 4. keep using the old values
3690 * Return OK when size could be determined, FAIL otherwise.
3691 */
3692 int
3693mch_get_shellsize()
3694{
3695 long rows = 0;
3696 long columns = 0;
3697 char_u *p;
3698
3699 /*
3700 * For OS/2 use _scrsize().
3701 */
3702# ifdef __EMX__
3703 {
3704 int s[2];
3705
3706 _scrsize(s);
3707 columns = s[0];
3708 rows = s[1];
3709 }
3710# endif
3711
3712 /*
3713 * 1. try using an ioctl. It is the most accurate method.
3714 *
3715 * Try using TIOCGWINSZ first, some systems that have it also define
3716 * TIOCGSIZE but don't have a struct ttysize.
3717 */
3718# ifdef TIOCGWINSZ
3719 {
3720 struct winsize ws;
3721 int fd = 1;
3722
3723 /* When stdout is not a tty, use stdin for the ioctl(). */
3724 if (!isatty(fd) && isatty(read_cmd_fd))
3725 fd = read_cmd_fd;
3726 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3727 {
3728 columns = ws.ws_col;
3729 rows = ws.ws_row;
3730 }
3731 }
3732# else /* TIOCGWINSZ */
3733# ifdef TIOCGSIZE
3734 {
3735 struct ttysize ts;
3736 int fd = 1;
3737
3738 /* When stdout is not a tty, use stdin for the ioctl(). */
3739 if (!isatty(fd) && isatty(read_cmd_fd))
3740 fd = read_cmd_fd;
3741 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3742 {
3743 columns = ts.ts_cols;
3744 rows = ts.ts_lines;
3745 }
3746 }
3747# endif /* TIOCGSIZE */
3748# endif /* TIOCGWINSZ */
3749
3750 /*
3751 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003752 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3753 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003754 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003755 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003756 {
3757 if ((p = (char_u *)getenv("LINES")))
3758 rows = atoi((char *)p);
3759 if ((p = (char_u *)getenv("COLUMNS")))
3760 columns = atoi((char *)p);
3761 }
3762
3763#ifdef HAVE_TGETENT
3764 /*
3765 * 3. try reading "co" and "li" entries from termcap
3766 */
3767 if (columns == 0 || rows == 0)
3768 getlinecol(&columns, &rows);
3769#endif
3770
3771 /*
3772 * 4. If everything fails, use the old values
3773 */
3774 if (columns <= 0 || rows <= 0)
3775 return FAIL;
3776
3777 Rows = rows;
3778 Columns = columns;
3779 return OK;
3780}
3781
3782/*
3783 * Try to set the window size to Rows and Columns.
3784 */
3785 void
3786mch_set_shellsize()
3787{
3788 if (*T_CWS)
3789 {
3790 /*
3791 * NOTE: if you get an error here that term_set_winsize() is
3792 * undefined, check the output of configure. It could probably not
3793 * find a ncurses, termcap or termlib library.
3794 */
3795 term_set_winsize((int)Rows, (int)Columns);
3796 out_flush();
3797 screen_start(); /* don't know where cursor is now */
3798 }
3799}
3800
3801#endif /* VMS */
3802
3803/*
3804 * Rows and/or Columns has changed.
3805 */
3806 void
3807mch_new_shellsize()
3808{
3809 /* Nothing to do. */
3810}
3811
Bram Moolenaar205b8862011-09-07 15:04:31 +02003812/*
3813 * Wait for process "child" to end.
3814 * Return "child" if it exited properly, <= 0 on error.
3815 */
3816 static pid_t
3817wait4pid(child, status)
3818 pid_t child;
3819 waitstatus *status;
3820{
3821 pid_t wait_pid = 0;
3822
3823 while (wait_pid != child)
3824 {
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003825 /* When compiled with Python threads are probably used, in which case
3826 * wait() sometimes hangs for no obvious reason. Use waitpid()
3827 * instead and loop (like the GUI). Also needed for other interfaces,
3828 * they might call system(). */
3829# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02003830 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003831# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02003832 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003833# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02003834 if (wait_pid == 0)
3835 {
Bram Moolenaar75676462013-01-30 14:55:42 +01003836 /* Wait for 10 msec before trying again. */
Bram Moolenaar205b8862011-09-07 15:04:31 +02003837 mch_delay(10L, TRUE);
3838 continue;
3839 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02003840 if (wait_pid <= 0
3841# ifdef ECHILD
3842 && errno == ECHILD
3843# endif
3844 )
3845 break;
3846 }
3847 return wait_pid;
3848}
3849
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850 int
3851mch_call_shell(cmd, options)
3852 char_u *cmd;
3853 int options; /* SHELL_*, see vim.h */
3854{
3855#ifdef VMS
3856 char *ifn = NULL;
3857 char *ofn = NULL;
3858#endif
3859 int tmode = cur_tmode;
3860#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3861 int x;
3862# ifndef __EMX__
3863 char_u *newcmd; /* only needed for unix */
3864# else
3865 /*
3866 * Set the preferred shell in the EMXSHELL environment variable (but
3867 * only if it is different from what is already in the environment).
3868 * Emx then takes care of whether to use "/c" or "-c" in an
3869 * intelligent way. Simply pass the whole thing to emx's system() call.
3870 * Emx also starts an interactive shell if system() is passed an empty
3871 * string.
3872 */
3873 char_u *p, *old;
3874
3875 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3876 {
3877 /* should check HAVE_SETENV, but I know we don't have it. */
3878 p = alloc(10 + strlen(p_sh));
3879 if (p)
3880 {
3881 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3882 putenv((char *)p); /* don't free the pointer! */
3883 }
3884 }
3885# endif
3886
3887 out_flush();
3888
3889 if (options & SHELL_COOKED)
3890 settmode(TMODE_COOK); /* set to normal mode */
3891
Bram Moolenaar62b42182010-09-21 22:09:37 +02003892# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01003893 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02003894 loose_clipboard();
3895# endif
3896
Bram Moolenaar071d4272004-06-13 20:20:40 +00003897# ifdef __EMX__
3898 if (cmd == NULL)
3899 x = system(""); /* this starts an interactive shell in emx */
3900 else
3901 x = system((char *)cmd);
3902 /* system() returns -1 when error occurs in starting shell */
3903 if (x == -1 && !emsg_silent)
3904 {
3905 MSG_PUTS(_("\nCannot execute shell "));
3906 msg_outtrans(p_sh);
3907 msg_putchar('\n');
3908 }
3909# else /* not __EMX__ */
3910 if (cmd == NULL)
3911 x = system((char *)p_sh);
3912 else
3913 {
3914# ifdef VMS
3915 if (ofn = strchr((char *)cmd, '>'))
3916 *ofn++ = '\0';
3917 if (ifn = strchr((char *)cmd, '<'))
3918 {
3919 char *p;
3920
3921 *ifn++ = '\0';
3922 p = strchr(ifn,' '); /* chop off any trailing spaces */
3923 if (p)
3924 *p = '\0';
3925 }
3926 if (ofn)
3927 x = vms_sys((char *)cmd, ofn, ifn);
3928 else
3929 x = system((char *)cmd);
3930# else
3931 newcmd = lalloc(STRLEN(p_sh)
3932 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3933 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3934 if (newcmd == NULL)
3935 x = 0;
3936 else
3937 {
3938 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3939 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3940 (char *)p_shcf,
3941 (char *)cmd);
3942 x = system((char *)newcmd);
3943 vim_free(newcmd);
3944 }
3945# endif
3946 }
3947# ifdef VMS
3948 x = vms_sys_status(x);
3949# endif
3950 if (emsg_silent)
3951 ;
3952 else if (x == 127)
3953 MSG_PUTS(_("\nCannot execute shell sh\n"));
3954# endif /* __EMX__ */
3955 else if (x && !(options & SHELL_SILENT))
3956 {
3957 MSG_PUTS(_("\nshell returned "));
3958 msg_outnum((long)x);
3959 msg_putchar('\n');
3960 }
3961
3962 if (tmode == TMODE_RAW)
3963 settmode(TMODE_RAW); /* set to raw mode */
3964# ifdef FEAT_TITLE
3965 resettitle();
3966# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01003967# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3968 restore_clipboard();
3969# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003970 return x;
3971
3972#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3973
Bram Moolenaardf177f62005-02-22 08:39:57 +00003974# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3975 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003976
3977 char_u *newcmd = NULL;
3978 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003979 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003980 pid_t wait_pid = 0;
3981# ifdef HAVE_UNION_WAIT
3982 union wait status;
3983# else
3984 int status = -1;
3985# endif
3986 int retval = -1;
3987 char **argv = NULL;
3988 int argc;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02003989 char_u *p_shcf_copy = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003990 int i;
3991 char_u *p;
3992 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003993 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003994# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995 int pty_slave_fd = -1;
3996 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003997# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003998 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003999 int fd_fromshell[2];
4000 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004001# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004002 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004003# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004 static char envbuf_Rows[20];
4005 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004006# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004007 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004008
Bram Moolenaar62b42182010-09-21 22:09:37 +02004009 newcmd = vim_strsave(p_sh);
4010 if (newcmd == NULL) /* out of memory */
4011 goto error;
4012
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013 out_flush();
4014 if (options & SHELL_COOKED)
4015 settmode(TMODE_COOK); /* set to normal mode */
4016
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004017 /*
4018 * Do this loop twice:
4019 * 1: find number of arguments
4020 * 2: separate them and build argv[]
4021 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022 for (i = 0; i < 2; ++i)
4023 {
4024 p = newcmd;
4025 inquote = FALSE;
4026 argc = 0;
4027 for (;;)
4028 {
4029 if (i == 1)
4030 argv[argc] = (char *)p;
4031 ++argc;
4032 while (*p && (inquote || (*p != ' ' && *p != TAB)))
4033 {
4034 if (*p == '"')
4035 inquote = !inquote;
4036 ++p;
4037 }
4038 if (*p == NUL)
4039 break;
4040 if (i == 1)
4041 *p++ = NUL;
4042 p = skipwhite(p);
4043 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00004044 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004045 {
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004046 /*
4047 * Account for possible multiple args in p_shcf.
4048 */
4049 p = p_shcf;
4050 for (;;)
4051 {
4052 p = skiptowhite(p);
4053 if (*p == NUL)
4054 break;
4055 ++argc;
4056 p = skipwhite(p);
4057 }
4058
Bram Moolenaar071d4272004-06-13 20:20:40 +00004059 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
4060 if (argv == NULL) /* out of memory */
4061 goto error;
4062 }
4063 }
4064 if (cmd != NULL)
4065 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004066 char_u *s;
4067
Bram Moolenaar071d4272004-06-13 20:20:40 +00004068 if (extra_shell_arg != NULL)
4069 argv[argc++] = (char *)extra_shell_arg;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004070
4071 /* Break 'shellcmdflag' into white separated parts. This doesn't
4072 * handle quoted strings, they are very unlikely to appear. */
4073 p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
4074 if (p_shcf_copy == NULL) /* out of memory */
4075 goto error;
4076 s = p_shcf_copy;
4077 p = p_shcf;
4078 while (*p != NUL)
4079 {
4080 argv[argc++] = (char *)s;
4081 while (*p && *p != ' ' && *p != TAB)
4082 *s++ = *p++;
4083 *s++ = NUL;
4084 p = skipwhite(p);
4085 }
4086
Bram Moolenaar071d4272004-06-13 20:20:40 +00004087 argv[argc++] = (char *)cmd;
4088 }
4089 argv[argc] = NULL;
4090
Bram Moolenaar071d4272004-06-13 20:20:40 +00004091 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004092 * For the GUI, when writing the output into the buffer and when reading
4093 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4094 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004095 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004096 if ((options & (SHELL_READ|SHELL_WRITE))
4097# ifdef FEAT_GUI
4098 || (gui.in_use && show_shell_mess)
4099# endif
4100 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004102# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004103 /*
4104 * Try to open a master pty.
4105 * If this works, open the slave pty.
4106 * If the slave can't be opened, close the master pty.
4107 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004108 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004109 {
4110 pty_master_fd = OpenPTY(&tty_name); /* open pty */
Bram Moolenaare70172e2011-08-04 19:36:52 +02004111 if (pty_master_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 {
Bram Moolenaare70172e2011-08-04 19:36:52 +02004113 /* Leaving out O_NOCTTY may lead to waitpid() always returning
4114 * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4115 * adding O_NOCTTY always works when defined. */
4116#ifdef O_NOCTTY
4117 pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4118#else
4119 pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4120#endif
4121 if (pty_slave_fd < 0)
4122 {
4123 close(pty_master_fd);
4124 pty_master_fd = -1;
4125 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126 }
4127 }
4128 /*
4129 * If not opening a pty or it didn't work, try using pipes.
4130 */
4131 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004132# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133 {
4134 pipe_error = (pipe(fd_toshell) < 0);
4135 if (!pipe_error) /* pipe create OK */
4136 {
4137 pipe_error = (pipe(fd_fromshell) < 0);
4138 if (pipe_error) /* pipe create failed */
4139 {
4140 close(fd_toshell[0]);
4141 close(fd_toshell[1]);
4142 }
4143 }
4144 if (pipe_error)
4145 {
4146 MSG_PUTS(_("\nCannot create pipes\n"));
4147 out_flush();
4148 }
4149 }
4150 }
4151
4152 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004153 {
4154# ifdef __BEOS__
4155 beos_cleanup_read_thread();
4156# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004157
Bram Moolenaar071d4272004-06-13 20:20:40 +00004158 if ((pid = fork()) == -1) /* maybe we should use vfork() */
4159 {
4160 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004161 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004163 || (gui.in_use && show_shell_mess)
4164# endif
4165 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004166 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004167# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168 if (pty_master_fd >= 0) /* close the pseudo tty */
4169 {
4170 close(pty_master_fd);
4171 close(pty_slave_fd);
4172 }
4173 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004174# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175 {
4176 close(fd_toshell[0]);
4177 close(fd_toshell[1]);
4178 close(fd_fromshell[0]);
4179 close(fd_fromshell[1]);
4180 }
4181 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004182 }
4183 else if (pid == 0) /* child */
4184 {
4185 reset_signals(); /* handle signals normally */
4186
4187 if (!show_shell_mess || (options & SHELL_EXPAND))
4188 {
4189 int fd;
4190
4191 /*
4192 * Don't want to show any message from the shell. Can't just
4193 * close stdout and stderr though, because some systems will
4194 * break if you try to write to them after that, so we must
4195 * use dup() to replace them with something else -- webb
4196 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4197 * waiting for input.
4198 */
4199 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4200 fclose(stdin);
4201 fclose(stdout);
4202 fclose(stderr);
4203
4204 /*
4205 * If any of these open()'s and dup()'s fail, we just continue
4206 * anyway. It's not fatal, and on most systems it will make
4207 * no difference at all. On a few it will cause the execvp()
4208 * to exit with a non-zero status even when the completion
4209 * could be done, which is nothing too serious. If the open()
4210 * or dup() failed we'd just do the same thing ourselves
4211 * anyway -- webb
4212 */
4213 if (fd >= 0)
4214 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004215 ignored = dup(fd); /* To replace stdin (fd 0) */
4216 ignored = dup(fd); /* To replace stdout (fd 1) */
4217 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004218
4219 /* Don't need this now that we've duplicated it */
4220 close(fd);
4221 }
4222 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004223 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004224# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004225 || gui.in_use
4226# endif
4227 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228 {
4229
Bram Moolenaardf177f62005-02-22 08:39:57 +00004230# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004231 /* Create our own process group, so that the child and all its
4232 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004233 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004234 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004235 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004236 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004237# if defined(SIGHUP)
4238 /* When doing "!xterm&" and 'shell' is bash: the shell
4239 * will exit and send SIGHUP to all processes in its
4240 * group, killing the just started process. Ignore SIGHUP
4241 * to avoid that. (suggested by Simon Schubert)
4242 */
4243 signal(SIGHUP, SIG_IGN);
4244# endif
4245 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004246# endif
4247# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004248 if (pty_slave_fd >= 0)
4249 {
4250 /* push stream discipline modules */
4251 if (options & SHELL_COOKED)
4252 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004254 /* Try to become controlling tty (probably doesn't work,
4255 * unless run by root) */
4256 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004258 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004259# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004260 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004261# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262 setenv("TERM", "dumb", 1);
4263 sprintf((char *)envbuf, "%ld", Rows);
4264 setenv("ROWS", (char *)envbuf, 1);
4265 sprintf((char *)envbuf, "%ld", Rows);
4266 setenv("LINES", (char *)envbuf, 1);
4267 sprintf((char *)envbuf, "%ld", Columns);
4268 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004269# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004270 /*
4271 * Putenv does not copy the string, it has to remain valid.
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004272 * Use a static array to avoid losing allocated memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004273 */
4274 putenv("TERM=dumb");
4275 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
4276 putenv(envbuf_Rows);
4277 sprintf(envbuf_Rows, "LINES=%ld", Rows);
4278 putenv(envbuf_Rows);
4279 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
4280 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004281# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004282
Bram Moolenaara5792f52005-11-23 21:25:05 +00004283 /*
4284 * stderr is only redirected when using the GUI, so that a
4285 * program like gpg can still access the terminal to get a
4286 * passphrase using stderr.
4287 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004288# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289 if (pty_master_fd >= 0)
4290 {
4291 close(pty_master_fd); /* close master side of pty */
4292
4293 /* set up stdin/stdout/stderr for the child */
4294 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004295 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004296 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004297 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004298 if (gui.in_use)
4299 {
4300 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004301 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004302 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303
4304 close(pty_slave_fd); /* has been dupped, close it now */
4305 }
4306 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004307# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004308 {
4309 /* set up stdin for the child */
4310 close(fd_toshell[1]);
4311 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004312 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004313 close(fd_toshell[0]);
4314
4315 /* set up stdout for the child */
4316 close(fd_fromshell[0]);
4317 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004318 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319 close(fd_fromshell[1]);
4320
Bram Moolenaara5792f52005-11-23 21:25:05 +00004321# ifdef FEAT_GUI
4322 if (gui.in_use)
4323 {
4324 /* set up stderr for the child */
4325 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004326 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004327 }
4328# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004329 }
4330 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004331
Bram Moolenaar071d4272004-06-13 20:20:40 +00004332 /*
4333 * There is no type cast for the argv, because the type may be
4334 * different on different machines. This may cause a warning
4335 * message with strict compilers, don't worry about it.
4336 * Call _exit() instead of exit() to avoid closing the connection
4337 * to the X server (esp. with GTK, which uses atexit()).
4338 */
4339 execvp(argv[0], argv);
4340 _exit(EXEC_FAILED); /* exec failed, return failure code */
4341 }
4342 else /* parent */
4343 {
4344 /*
4345 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004346 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004347 */
4348 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004349 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004350
4351 /*
4352 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004353 * This is also used to pipe stdin/stdout to/from the external
4354 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004355 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004356 if ((options & (SHELL_READ|SHELL_WRITE))
4357# ifdef FEAT_GUI
4358 || (gui.in_use && show_shell_mess)
4359# endif
4360 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004361 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004362# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004363 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004364# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004365 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004366# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004367 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4368 int ta_len = 0; /* valid bytes in ta_buf[] */
4369 int len;
4370 int p_more_save;
4371 int old_State;
4372 int c;
4373 int toshell_fd;
4374 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004375 garray_T ga;
4376 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004377# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4378 struct timeval start_tv;
4379# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004380
Bram Moolenaardf177f62005-02-22 08:39:57 +00004381# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382 if (pty_master_fd >= 0)
4383 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004384 fromshell_fd = pty_master_fd;
4385 toshell_fd = dup(pty_master_fd);
4386 }
4387 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004388# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004389 {
4390 close(fd_toshell[0]);
4391 close(fd_fromshell[1]);
4392 toshell_fd = fd_toshell[1];
4393 fromshell_fd = fd_fromshell[0];
4394 }
4395
4396 /*
4397 * Write to the child if there are typed characters.
4398 * Read from the child if there are characters available.
4399 * Repeat the reading a few times if more characters are
4400 * available. Need to check for typed keys now and then, but
4401 * not too often (delays when no chars are available).
4402 * This loop is quit if no characters can be read from the pty
4403 * (WaitForChar detected special condition), or there are no
4404 * characters available and the child has exited.
4405 * Only check if the child has exited when there is no more
4406 * output. The child may exit before all the output has
4407 * been printed.
4408 *
4409 * Currently this busy loops!
4410 * This can probably dead-lock when the write blocks!
4411 */
4412 p_more_save = p_more;
4413 p_more = FALSE;
4414 old_State = State;
4415 State = EXTERNCMD; /* don't redraw at window resize */
4416
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004417 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004418 {
4419 /* Fork a process that will write the lines to the
4420 * external program. */
4421 if ((wpid = fork()) == -1)
4422 {
4423 MSG_PUTS(_("\nCannot fork\n"));
4424 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004425 else if (wpid == 0) /* child */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004426 {
4427 linenr_T lnum = curbuf->b_op_start.lnum;
4428 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004429 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004430 size_t l;
4431
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004432 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004433 for (;;)
4434 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004435 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004436 if (l == 0)
4437 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004438 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004439 /* NL -> NUL translation */
4440 len = write(toshell_fd, "", (size_t)1);
4441 else
4442 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004443 char_u *s = vim_strchr(lp + written, NL);
4444
Bram Moolenaar89d40322006-08-29 15:30:07 +00004445 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004446 s == NULL ? l
4447 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004448 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004449 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004450 {
4451 /* Finished a line, add a NL, unless this line
4452 * should not have one. */
4453 if (lnum != curbuf->b_op_end.lnum
4454 || !curbuf->b_p_bin
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004455 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004456 && (lnum !=
4457 curbuf->b_ml.ml_line_count
4458 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004459 ignored = write(toshell_fd, "\n",
4460 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004461 ++lnum;
4462 if (lnum > curbuf->b_op_end.lnum)
4463 {
4464 /* finished all the lines, close pipe */
4465 close(toshell_fd);
4466 toshell_fd = -1;
4467 break;
4468 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004469 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004470 written = 0;
4471 }
4472 else if (len > 0)
4473 written += len;
4474 }
4475 _exit(0);
4476 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004477 else /* parent */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004478 {
4479 close(toshell_fd);
4480 toshell_fd = -1;
4481 }
4482 }
4483
4484 if (options & SHELL_READ)
4485 ga_init2(&ga, 1, BUFLEN);
4486
4487 noread_cnt = 0;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004488# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4489 gettimeofday(&start_tv, NULL);
4490# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004491 for (;;)
4492 {
4493 /*
4494 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004495 * if there are any.
4496 * Don't do this if we are expanding wild cards (would eat
4497 * typeahead).
4498 * Don't do this when filtering and terminal is in cooked
4499 * mode, the shell command will handle the I/O. Avoids
4500 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004501 * Don't get characters when the child has already
4502 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004503 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004504 * while (noread_cnt > 4), avoids that ":r !ls" eats
4505 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004506 */
4507 len = 0;
4508 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004509 && ((options &
4510 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4511 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004512# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004513 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004514# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004515 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004516 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004517 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004518 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004519 if (ta_len == 0)
4520 {
4521 /* Get extra characters when we don't have any.
4522 * Reset the counter and timer. */
4523 noread_cnt = 0;
4524# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4525 gettimeofday(&start_tv, NULL);
4526# endif
4527 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4528 }
4529 if (ta_len > 0 || len > 0)
4530 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004531 /*
4532 * For pipes:
4533 * Check for CTRL-C: send interrupt signal to child.
4534 * Check for CTRL-D: EOF, close pipe to child.
4535 */
4536 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4537 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004538# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539 /*
4540 * Send SIGINT to the child's group or all
4541 * processes in our group.
4542 */
4543 if (ta_buf[ta_len] == Ctrl_C
4544 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004545 {
4546# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004547 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004548# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004550# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004551 if (wpid > 0)
4552 kill(wpid, SIGINT);
4553 }
4554# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004555 if (pty_master_fd < 0 && toshell_fd >= 0
4556 && ta_buf[ta_len] == Ctrl_D)
4557 {
4558 close(toshell_fd);
4559 toshell_fd = -1;
4560 }
4561 }
4562
4563 /* replace K_BS by <BS> and K_DEL by <DEL> */
4564 for (i = ta_len; i < ta_len + len; ++i)
4565 {
4566 if (ta_buf[i] == CSI && len - i > 2)
4567 {
4568 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4569 if (c == K_DEL || c == K_KDEL || c == K_BS)
4570 {
4571 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4572 (size_t)(len - i - 2));
4573 if (c == K_DEL || c == K_KDEL)
4574 ta_buf[i] = DEL;
4575 else
4576 ta_buf[i] = Ctrl_H;
4577 len -= 2;
4578 }
4579 }
4580 else if (ta_buf[i] == '\r')
4581 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004582# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004583 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00004584 i += (*mb_ptr2len_len)(ta_buf + i,
4585 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004586# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004587 }
4588
4589 /*
4590 * For pipes: echo the typed characters.
4591 * For a pty this does not seem to work.
4592 */
4593 if (pty_master_fd < 0)
4594 {
4595 for (i = ta_len; i < ta_len + len; ++i)
4596 {
4597 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4598 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004599# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600 else if (has_mbyte)
4601 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004602 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004603
4604 msg_outtrans_len(ta_buf + i, l);
4605 i += l - 1;
4606 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004607# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004608 else
4609 msg_outtrans_len(ta_buf + i, 1);
4610 }
4611 windgoto(msg_row, msg_col);
4612 out_flush();
4613 }
4614
4615 ta_len += len;
4616
4617 /*
4618 * Write the characters to the child, unless EOF has
4619 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004620 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004621 * When writing buffer lines, drop the typed
4622 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004623 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004624 if (options & SHELL_WRITE)
4625 ta_len = 0;
4626 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 {
4628 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4629 if (len > 0)
4630 {
4631 ta_len -= len;
4632 mch_memmove(ta_buf, ta_buf + len, ta_len);
4633 }
4634 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004635 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004636 }
4637
Bram Moolenaardf177f62005-02-22 08:39:57 +00004638 if (got_int)
4639 {
4640 /* CTRL-C sends a signal to the child, we ignore it
4641 * ourselves */
4642# ifdef HAVE_SETSID
4643 kill(-pid, SIGINT);
4644# else
4645 kill(0, SIGINT);
4646# endif
4647 if (wpid > 0)
4648 kill(wpid, SIGINT);
4649 got_int = FALSE;
4650 }
4651
Bram Moolenaar071d4272004-06-13 20:20:40 +00004652 /*
4653 * Check if the child has any characters to be printed.
4654 * Read them and write them to our window. Repeat this as
4655 * long as there is something to do, avoid the 10ms wait
4656 * for mch_inchar(), or sending typeahead characters to
4657 * the external process.
4658 * TODO: This should handle escape sequences, compatible
4659 * to some terminal (vt52?).
4660 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004661 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004662 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4663 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004664 len = read_eintr(fromshell_fd, buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004665# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004666 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004667# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004668 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004669# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004670 );
4671 if (len <= 0) /* end of file or error */
4672 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004673
4674 noread_cnt = 0;
4675 if (options & SHELL_READ)
4676 {
4677 /* Do NUL -> NL translation, append NL separated
4678 * lines to the current buffer. */
4679 for (i = 0; i < len; ++i)
4680 {
4681 if (buffer[i] == NL)
4682 append_ga_line(&ga);
4683 else if (buffer[i] == NUL)
4684 ga_append(&ga, NL);
4685 else
4686 ga_append(&ga, buffer[i]);
4687 }
4688 }
4689# ifdef FEAT_MBYTE
4690 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004691 {
4692 int l;
4693
Bram Moolenaardf177f62005-02-22 08:39:57 +00004694 len += buffer_off;
4695 buffer[len] = NUL;
4696
Bram Moolenaar071d4272004-06-13 20:20:40 +00004697 /* Check if the last character in buffer[] is
4698 * incomplete, keep these bytes for the next
4699 * round. */
4700 for (p = buffer; p < buffer + len; p += l)
4701 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004702 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004703 if (l == 0)
4704 l = 1; /* NUL byte? */
4705 else if (MB_BYTE2LEN(*p) != l)
4706 break;
4707 }
4708 if (p == buffer) /* no complete character */
4709 {
4710 /* avoid getting stuck at an illegal byte */
4711 if (len >= 12)
4712 ++p;
4713 else
4714 {
4715 buffer_off = len;
4716 continue;
4717 }
4718 }
4719 c = *p;
4720 *p = NUL;
4721 msg_puts(buffer);
4722 if (p < buffer + len)
4723 {
4724 *p = c;
4725 buffer_off = (buffer + len) - p;
4726 mch_memmove(buffer, p, buffer_off);
4727 continue;
4728 }
4729 buffer_off = 0;
4730 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004731# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004732 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004733 {
4734 buffer[len] = NUL;
4735 msg_puts(buffer);
4736 }
4737
4738 windgoto(msg_row, msg_col);
4739 cursor_on();
4740 out_flush();
4741 if (got_int)
4742 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004743
4744# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4745 {
4746 struct timeval now_tv;
4747 long msec;
4748
4749 /* Avoid that we keep looping here without
4750 * checking for a CTRL-C for a long time. Don't
4751 * break out too often to avoid losing typeahead. */
4752 gettimeofday(&now_tv, NULL);
4753 msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
4754 + (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
4755 if (msec > 2000)
4756 {
4757 noread_cnt = 5;
4758 break;
4759 }
4760 }
4761# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004762 }
4763
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004764 /* If we already detected the child has finished break the
4765 * loop now. */
4766 if (wait_pid == pid)
4767 break;
4768
Bram Moolenaar071d4272004-06-13 20:20:40 +00004769 /*
4770 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004771 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004773# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004774 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004775# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004776 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004777# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004778 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4779 || (wait_pid == pid && WIFEXITED(status)))
4780 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004781 /* Don't break the loop yet, try reading more
4782 * characters from "fromshell_fd" first. When using
4783 * pipes there might still be something to read and
4784 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004785 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004787 else
4788 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004789
Bram Moolenaar95a51352013-03-21 22:53:50 +01004790# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004791 /* Handle any X events, e.g. serving the clipboard. */
4792 clip_update();
4793# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004794 }
4795finished:
4796 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004797 if (options & SHELL_READ)
4798 {
4799 if (ga.ga_len > 0)
4800 {
4801 append_ga_line(&ga);
4802 /* remember that the NL was missing */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004803 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004804 }
4805 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004806 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004807 ga_clear(&ga);
4808 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004809
Bram Moolenaar071d4272004-06-13 20:20:40 +00004810 /*
4811 * Give all typeahead that wasn't used back to ui_inchar().
4812 */
4813 if (ta_len)
4814 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815 State = old_State;
4816 if (toshell_fd >= 0)
4817 close(toshell_fd);
4818 close(fromshell_fd);
4819 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01004820# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004821 else
4822 {
4823 /*
4824 * Similar to the loop above, but only handle X events, no
4825 * I/O.
4826 */
4827 for (;;)
4828 {
4829 if (got_int)
4830 {
4831 /* CTRL-C sends a signal to the child, we ignore it
4832 * ourselves */
4833# ifdef HAVE_SETSID
4834 kill(-pid, SIGINT);
4835# else
4836 kill(0, SIGINT);
4837# endif
4838 got_int = FALSE;
4839 }
4840# ifdef __NeXT__
4841 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4842# else
4843 wait_pid = waitpid(pid, &status, WNOHANG);
4844# endif
4845 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4846 || (wait_pid == pid && WIFEXITED(status)))
4847 {
4848 wait_pid = pid;
4849 break;
4850 }
4851
4852 /* Handle any X events, e.g. serving the clipboard. */
4853 clip_update();
4854
4855 mch_delay(10L, TRUE);
4856 }
4857 }
4858# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004859
4860 /*
4861 * Wait until our child has exited.
4862 * Ignore wait() returning pids of other children and returning
4863 * because of some signal like SIGWINCH.
4864 * Don't wait if wait_pid was already set above, indicating the
4865 * child already exited.
4866 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02004867 if (wait_pid != pid)
4868 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004869
Bram Moolenaar624891f2010-10-13 16:22:09 +02004870# ifdef FEAT_GUI
4871 /* Close slave side of pty. Only do this after the child has
4872 * exited, otherwise the child may hang when it tries to write on
4873 * the pty. */
4874 if (pty_master_fd >= 0)
4875 close(pty_slave_fd);
4876# endif
4877
Bram Moolenaardf177f62005-02-22 08:39:57 +00004878 /* Make sure the child that writes to the external program is
4879 * dead. */
4880 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004881 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004882 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02004883 wait4pid(wpid, NULL);
4884 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004885
Bram Moolenaar071d4272004-06-13 20:20:40 +00004886 /*
4887 * Set to raw mode right now, otherwise a CTRL-C after
4888 * catch_signals() will kill Vim.
4889 */
4890 if (tmode == TMODE_RAW)
4891 settmode(TMODE_RAW);
4892 did_settmode = TRUE;
4893 set_signals();
4894
4895 if (WIFEXITED(status))
4896 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004897 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004898 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01004899 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004900 {
4901 if (retval == EXEC_FAILED)
4902 {
4903 MSG_PUTS(_("\nCannot execute shell "));
4904 msg_outtrans(p_sh);
4905 msg_putchar('\n');
4906 }
4907 else if (!(options & SHELL_SILENT))
4908 {
4909 MSG_PUTS(_("\nshell returned "));
4910 msg_outnum((long)retval);
4911 msg_putchar('\n');
4912 }
4913 }
4914 }
4915 else
4916 MSG_PUTS(_("\nCommand terminated\n"));
4917 }
4918 }
4919 vim_free(argv);
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004920 vim_free(p_shcf_copy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004921
4922error:
4923 if (!did_settmode)
4924 if (tmode == TMODE_RAW)
4925 settmode(TMODE_RAW); /* set to raw mode */
4926# ifdef FEAT_TITLE
4927 resettitle();
4928# endif
4929 vim_free(newcmd);
4930
4931 return retval;
4932
4933#endif /* USE_SYSTEM */
4934}
4935
4936/*
4937 * Check for CTRL-C typed by reading all available characters.
4938 * In cooked mode we should get SIGINT, no need to check.
4939 */
4940 void
4941mch_breakcheck()
4942{
4943 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4944 fill_input_buf(FALSE);
4945}
4946
4947/*
4948 * Wait "msec" msec until a character is available from the keyboard or from
4949 * inbuf[]. msec == -1 will block forever.
4950 * When a GUI is being used, this will never get called -- webb
4951 */
4952 static int
4953WaitForChar(msec)
4954 long msec;
4955{
4956#ifdef FEAT_MOUSE_GPM
4957 int gpm_process_wanted;
4958#endif
4959#ifdef FEAT_XCLIPBOARD
4960 int rest;
4961#endif
4962 int avail;
4963
4964 if (input_available()) /* something in inbuf[] */
4965 return 1;
4966
4967#if defined(FEAT_MOUSE_DEC)
4968 /* May need to query the mouse position. */
4969 if (WantQueryMouse)
4970 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004971 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004972 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4973 }
4974#endif
4975
4976 /*
4977 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4978 * events. This is a bit complicated, because they might both be defined.
4979 */
4980#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4981# ifdef FEAT_XCLIPBOARD
4982 rest = 0;
4983 if (do_xterm_trace())
4984 rest = msec;
4985# endif
4986 do
4987 {
4988# ifdef FEAT_XCLIPBOARD
4989 if (rest != 0)
4990 {
4991 msec = XT_TRACE_DELAY;
4992 if (rest >= 0 && rest < XT_TRACE_DELAY)
4993 msec = rest;
4994 if (rest >= 0)
4995 rest -= msec;
4996 }
4997# endif
4998# ifdef FEAT_MOUSE_GPM
4999 gpm_process_wanted = 0;
5000 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
5001# else
5002 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
5003# endif
5004 if (!avail)
5005 {
5006 if (input_available())
5007 return 1;
5008# ifdef FEAT_XCLIPBOARD
5009 if (rest == 0 || !do_xterm_trace())
5010# endif
5011 break;
5012 }
5013 }
5014 while (FALSE
5015# ifdef FEAT_MOUSE_GPM
5016 || (gpm_process_wanted && mch_gpm_process() == 0)
5017# endif
5018# ifdef FEAT_XCLIPBOARD
5019 || (!avail && rest != 0)
5020# endif
5021 );
5022
5023#else
5024 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
5025#endif
5026 return avail;
5027}
5028
5029/*
5030 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005031 * "msec" == 0 will check for characters once.
5032 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005033 * When a GUI is being used, this will not be used for input -- webb
5034 * Returns also, when a request from Sniff is waiting -- toni.
5035 * Or when a Linux GPM mouse event is waiting.
5036 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005037#if defined(__BEOS__)
5038 int
5039#else
5040 static int
5041#endif
5042RealWaitForChar(fd, msec, check_for_gpm)
5043 int fd;
5044 long msec;
Bram Moolenaar78a15312009-05-15 19:33:18 +00005045 int *check_for_gpm UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005046{
5047 int ret;
Bram Moolenaar67c53842010-05-22 18:28:27 +02005048#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02005049 int nb_fd = netbeans_filedesc();
Bram Moolenaar67c53842010-05-22 18:28:27 +02005050#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005051#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005052 static int busy = FALSE;
5053
5054 /* May retry getting characters after an event was handled. */
5055# define MAY_LOOP
5056
5057# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5058 /* Remember at what time we started, so that we know how much longer we
5059 * should wait after being interrupted. */
5060# define USE_START_TV
5061 struct timeval start_tv;
5062
5063 if (msec > 0 && (
5064# ifdef FEAT_XCLIPBOARD
5065 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005066# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005067 ||
5068# endif
5069# endif
5070# ifdef USE_XSMP
5071 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005072# ifdef FEAT_MZSCHEME
5073 ||
5074# endif
5075# endif
5076# ifdef FEAT_MZSCHEME
5077 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005078# endif
5079 ))
5080 gettimeofday(&start_tv, NULL);
5081# endif
5082
5083 /* Handle being called recursively. This may happen for the session
5084 * manager stuff, it may save the file, which does a breakcheck. */
5085 if (busy)
5086 return 0;
5087#endif
5088
5089#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00005090 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005091#endif
5092 {
5093#ifdef MAY_LOOP
5094 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005095# ifdef FEAT_MZSCHEME
5096 int mzquantum_used = FALSE;
5097# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005098#endif
5099#ifndef HAVE_SELECT
Bram Moolenaar67c53842010-05-22 18:28:27 +02005100 struct pollfd fds[6];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005101 int nfd;
5102# ifdef FEAT_XCLIPBOARD
5103 int xterm_idx = -1;
5104# endif
5105# ifdef FEAT_MOUSE_GPM
5106 int gpm_idx = -1;
5107# endif
5108# ifdef USE_XSMP
5109 int xsmp_idx = -1;
5110# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005111# ifdef FEAT_NETBEANS_INTG
5112 int nb_idx = -1;
5113# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005114 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005115
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005116# ifdef FEAT_MZSCHEME
5117 mzvim_check_threads();
5118 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5119 {
5120 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
5121 mzquantum_used = TRUE;
5122 }
5123# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005124 fds[0].fd = fd;
5125 fds[0].events = POLLIN;
5126 nfd = 1;
5127
5128# ifdef FEAT_SNIFF
5129# define SNIFF_IDX 1
5130 if (want_sniff_request)
5131 {
5132 fds[SNIFF_IDX].fd = fd_from_sniff;
5133 fds[SNIFF_IDX].events = POLLIN;
5134 nfd++;
5135 }
5136# endif
5137# ifdef FEAT_XCLIPBOARD
5138 if (xterm_Shell != (Widget)0)
5139 {
5140 xterm_idx = nfd;
5141 fds[nfd].fd = ConnectionNumber(xterm_dpy);
5142 fds[nfd].events = POLLIN;
5143 nfd++;
5144 }
5145# endif
5146# ifdef FEAT_MOUSE_GPM
5147 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5148 {
5149 gpm_idx = nfd;
5150 fds[nfd].fd = gpm_fd;
5151 fds[nfd].events = POLLIN;
5152 nfd++;
5153 }
5154# endif
5155# ifdef USE_XSMP
5156 if (xsmp_icefd != -1)
5157 {
5158 xsmp_idx = nfd;
5159 fds[nfd].fd = xsmp_icefd;
5160 fds[nfd].events = POLLIN;
5161 nfd++;
5162 }
5163# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005164#ifdef FEAT_NETBEANS_INTG
5165 if (nb_fd != -1)
5166 {
5167 nb_idx = nfd;
5168 fds[nfd].fd = nb_fd;
5169 fds[nfd].events = POLLIN;
5170 nfd++;
5171 }
5172#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005173
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005174 ret = poll(fds, nfd, towait);
5175# ifdef FEAT_MZSCHEME
5176 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005177 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005178 finished = FALSE;
5179# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005180
5181# ifdef FEAT_SNIFF
5182 if (ret < 0)
5183 sniff_disconnect(1);
5184 else if (want_sniff_request)
5185 {
5186 if (fds[SNIFF_IDX].revents & POLLHUP)
5187 sniff_disconnect(1);
5188 if (fds[SNIFF_IDX].revents & POLLIN)
5189 sniff_request_waiting = 1;
5190 }
5191# endif
5192# ifdef FEAT_XCLIPBOARD
5193 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
5194 {
5195 xterm_update(); /* Maybe we should hand out clipboard */
5196 if (--ret == 0 && !input_available())
5197 /* Try again */
5198 finished = FALSE;
5199 }
5200# endif
5201# ifdef FEAT_MOUSE_GPM
5202 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
5203 {
5204 *check_for_gpm = 1;
5205 }
5206# endif
5207# ifdef USE_XSMP
5208 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
5209 {
5210 if (fds[xsmp_idx].revents & POLLIN)
5211 {
5212 busy = TRUE;
5213 xsmp_handle_requests();
5214 busy = FALSE;
5215 }
5216 else if (fds[xsmp_idx].revents & POLLHUP)
5217 {
5218 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005219 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005220 xsmp_close();
5221 }
5222 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005223 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005224 }
5225# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005226#ifdef FEAT_NETBEANS_INTG
5227 if (ret > 0 && nb_idx != -1 && fds[nb_idx].revents & POLLIN)
5228 {
5229 netbeans_read();
5230 --ret;
5231 }
5232#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005233
5234
5235#else /* HAVE_SELECT */
5236
5237 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005238 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005239 fd_set rfds, efds;
5240 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005241 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005242
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005243# ifdef FEAT_MZSCHEME
5244 mzvim_check_threads();
5245 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5246 {
5247 towait = p_mzq; /* don't wait longer than 'mzquantum' */
5248 mzquantum_used = TRUE;
5249 }
5250# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005251# ifdef __EMX__
5252 /* don't check for incoming chars if not in raw mode, because select()
5253 * always returns TRUE then (in some version of emx.dll) */
5254 if (curr_tmode != TMODE_RAW)
5255 return 0;
5256# endif
5257
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005258 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005259 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005260 tv.tv_sec = towait / 1000;
5261 tv.tv_usec = (towait % 1000) * (1000000/1000);
5262 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005263 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005264 else
5265 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005266
5267 /*
5268 * Select on ready for reading and exceptional condition (end of file).
5269 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005270select_eintr:
5271 FD_ZERO(&rfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005272 FD_ZERO(&efds);
5273 FD_SET(fd, &rfds);
5274# if !defined(__QNX__) && !defined(__CYGWIN32__)
5275 /* For QNX select() always returns 1 if this is set. Why? */
5276 FD_SET(fd, &efds);
5277# endif
5278 maxfd = fd;
5279
5280# ifdef FEAT_SNIFF
5281 if (want_sniff_request)
5282 {
5283 FD_SET(fd_from_sniff, &rfds);
5284 FD_SET(fd_from_sniff, &efds);
5285 if (maxfd < fd_from_sniff)
5286 maxfd = fd_from_sniff;
5287 }
5288# endif
5289# ifdef FEAT_XCLIPBOARD
5290 if (xterm_Shell != (Widget)0)
5291 {
5292 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
5293 if (maxfd < ConnectionNumber(xterm_dpy))
5294 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02005295
5296 /* An event may have already been read but not handled. In
5297 * particulary, XFlush may cause this. */
5298 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005299 }
5300# endif
5301# ifdef FEAT_MOUSE_GPM
5302 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5303 {
5304 FD_SET(gpm_fd, &rfds);
5305 FD_SET(gpm_fd, &efds);
5306 if (maxfd < gpm_fd)
5307 maxfd = gpm_fd;
5308 }
5309# endif
5310# ifdef USE_XSMP
5311 if (xsmp_icefd != -1)
5312 {
5313 FD_SET(xsmp_icefd, &rfds);
5314 FD_SET(xsmp_icefd, &efds);
5315 if (maxfd < xsmp_icefd)
5316 maxfd = xsmp_icefd;
5317 }
5318# endif
Bram Moolenaardd82d692012-08-15 17:26:57 +02005319# ifdef FEAT_NETBEANS_INTG
Bram Moolenaar67c53842010-05-22 18:28:27 +02005320 if (nb_fd != -1)
5321 {
5322 FD_SET(nb_fd, &rfds);
5323 if (maxfd < nb_fd)
5324 maxfd = nb_fd;
5325 }
Bram Moolenaardd82d692012-08-15 17:26:57 +02005326# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005327
5328# ifdef OLD_VMS
5329 /* Old VMS as v6.2 and older have broken select(). It waits more than
5330 * required. Should not be used */
5331 ret = 0;
5332# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005333 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
5334# endif
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005335# ifdef EINTR
5336 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005337 {
5338 /* Check whether window has been resized, EINTR may be caused by
5339 * SIGWINCH. */
5340 if (do_resize)
5341 handle_resize();
5342
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005343 /* Interrupted by a signal, need to try again. We ignore msec
5344 * here, because we do want to check even after a timeout if
5345 * characters are available. Needed for reading output of an
5346 * external command after the process has finished. */
5347 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005348 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005349# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00005350# ifdef __TANDEM
5351 if (ret == -1 && errno == ENOTSUP)
5352 {
5353 FD_ZERO(&rfds);
5354 FD_ZERO(&efds);
5355 ret = 0;
5356 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005357# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005358# ifdef FEAT_MZSCHEME
5359 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005360 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005361 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005362# endif
5363
5364# ifdef FEAT_SNIFF
5365 if (ret < 0 )
5366 sniff_disconnect(1);
5367 else if (ret > 0 && want_sniff_request)
5368 {
5369 if (FD_ISSET(fd_from_sniff, &efds))
5370 sniff_disconnect(1);
5371 if (FD_ISSET(fd_from_sniff, &rfds))
5372 sniff_request_waiting = 1;
5373 }
5374# endif
5375# ifdef FEAT_XCLIPBOARD
5376 if (ret > 0 && xterm_Shell != (Widget)0
5377 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
5378 {
5379 xterm_update(); /* Maybe we should hand out clipboard */
5380 /* continue looping when we only got the X event and the input
5381 * buffer is empty */
5382 if (--ret == 0 && !input_available())
5383 {
5384 /* Try again */
5385 finished = FALSE;
5386 }
5387 }
5388# endif
5389# ifdef FEAT_MOUSE_GPM
5390 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
5391 {
5392 if (FD_ISSET(gpm_fd, &efds))
5393 gpm_close();
5394 else if (FD_ISSET(gpm_fd, &rfds))
5395 *check_for_gpm = 1;
5396 }
5397# endif
5398# ifdef USE_XSMP
5399 if (ret > 0 && xsmp_icefd != -1)
5400 {
5401 if (FD_ISSET(xsmp_icefd, &efds))
5402 {
5403 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005404 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005405 xsmp_close();
5406 if (--ret == 0)
5407 finished = FALSE; /* keep going if event was only one */
5408 }
5409 else if (FD_ISSET(xsmp_icefd, &rfds))
5410 {
5411 busy = TRUE;
5412 xsmp_handle_requests();
5413 busy = FALSE;
5414 if (--ret == 0)
5415 finished = FALSE; /* keep going if event was only one */
5416 }
5417 }
5418# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005419#ifdef FEAT_NETBEANS_INTG
5420 if (ret > 0 && nb_fd != -1 && FD_ISSET(nb_fd, &rfds))
5421 {
5422 netbeans_read();
5423 --ret;
5424 }
5425#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005426
5427#endif /* HAVE_SELECT */
5428
5429#ifdef MAY_LOOP
5430 if (finished || msec == 0)
5431 break;
5432
5433 /* We're going to loop around again, find out for how long */
5434 if (msec > 0)
5435 {
5436# ifdef USE_START_TV
5437 struct timeval mtv;
5438
5439 /* Compute remaining wait time. */
5440 gettimeofday(&mtv, NULL);
5441 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
5442 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
5443# else
5444 /* Guess we got interrupted halfway. */
5445 msec = msec / 2;
5446# endif
5447 if (msec <= 0)
5448 break; /* waited long enough */
5449 }
5450#endif
5451 }
5452
5453 return (ret > 0);
5454}
5455
5456#ifndef VMS
5457
5458#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00005459/*
Bram Moolenaar02743632005-07-25 20:42:36 +00005460 * Expand a path into all matching files and/or directories. Handles "*",
5461 * "?", "[a-z]", "**", etc.
5462 * "path" has backslashes before chars that are not to be expanded.
5463 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005464 */
5465 int
5466mch_expandpath(gap, path, flags)
5467 garray_T *gap;
5468 char_u *path;
5469 int flags; /* EW_* flags */
5470{
Bram Moolenaar02743632005-07-25 20:42:36 +00005471 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005472}
5473#endif
5474
5475/*
5476 * mch_expand_wildcards() - this code does wild-card pattern matching using
5477 * the shell
5478 *
5479 * return OK for success, FAIL for error (you may lose some memory) and put
5480 * an error message in *file.
5481 *
5482 * num_pat is number of input patterns
5483 * pat is array of pointers to input patterns
5484 * num_file is pointer to number of matched file names
5485 * file is pointer to array of pointers to matched file names
5486 */
5487
5488#ifndef SEEK_SET
5489# define SEEK_SET 0
5490#endif
5491#ifndef SEEK_END
5492# define SEEK_END 2
5493#endif
5494
Bram Moolenaar5555acc2006-04-07 21:33:12 +00005495#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00005496
Bram Moolenaar071d4272004-06-13 20:20:40 +00005497 int
5498mch_expand_wildcards(num_pat, pat, num_file, file, flags)
5499 int num_pat;
5500 char_u **pat;
5501 int *num_file;
5502 char_u ***file;
5503 int flags; /* EW_* flags */
5504{
5505 int i;
5506 size_t len;
5507 char_u *p;
5508 int dir;
5509#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00005510 /*
5511 * This is the OS/2 implementation.
5512 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005513# define EXPL_ALLOC_INC 16
5514 char_u **expl_files;
5515 size_t files_alloced, files_free;
5516 char_u *buf;
5517 int has_wildcard;
5518
5519 *num_file = 0; /* default: no files found */
5520 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
5521 files_free = EXPL_ALLOC_INC; /* how much space is not used */
5522 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
5523 if (*file == NULL)
5524 return FAIL;
5525
5526 for (; num_pat > 0; num_pat--, pat++)
5527 {
5528 expl_files = NULL;
5529 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
5530 /* expand environment var or home dir */
5531 buf = expand_env_save(*pat);
5532 else
5533 buf = vim_strsave(*pat);
5534 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005535 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005536 if (has_wildcard) /* yes, so expand them */
5537 expl_files = (char_u **)_fnexplode(buf);
5538
5539 /*
5540 * return value of buf if no wildcards left,
5541 * OR if no match AND EW_NOTFOUND is set.
5542 */
5543 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
5544 || (expl_files == NULL && (flags & EW_NOTFOUND)))
5545 { /* simply save the current contents of *buf */
5546 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
5547 if (expl_files != NULL)
5548 {
5549 expl_files[0] = vim_strsave(buf);
5550 expl_files[1] = NULL;
5551 }
5552 }
5553 vim_free(buf);
5554
5555 /*
5556 * Count number of names resulting from expansion,
5557 * At the same time add a backslash to the end of names that happen to
5558 * be directories, and replace slashes with backslashes.
5559 */
5560 if (expl_files)
5561 {
5562 for (i = 0; (p = expl_files[i]) != NULL; i++)
5563 {
5564 dir = mch_isdir(p);
5565 /* If we don't want dirs and this is one, skip it */
5566 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5567 continue;
5568
Bram Moolenaara2031822006-03-07 22:29:51 +00005569 /* Skip files that are not executable if we check for that. */
5570 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
5571 continue;
5572
Bram Moolenaar071d4272004-06-13 20:20:40 +00005573 if (--files_free == 0)
5574 {
5575 /* need more room in table of pointers */
5576 files_alloced += EXPL_ALLOC_INC;
5577 *file = (char_u **)vim_realloc(*file,
5578 sizeof(char_u **) * files_alloced);
5579 if (*file == NULL)
5580 {
5581 EMSG(_(e_outofmem));
5582 *num_file = 0;
5583 return FAIL;
5584 }
5585 files_free = EXPL_ALLOC_INC;
5586 }
5587 slash_adjust(p);
5588 if (dir)
5589 {
5590 /* For a directory we add a '/', unless it's already
5591 * there. */
5592 len = STRLEN(p);
5593 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5594 {
5595 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005596 if (!after_pathsep((*file)[*num_file],
5597 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005598 {
5599 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005600 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005601 }
5602 }
5603 }
5604 else
5605 {
5606 (*file)[*num_file] = vim_strsave(p);
5607 }
5608
5609 /*
5610 * Error message already given by either alloc or vim_strsave.
5611 * Should return FAIL, but returning OK works also.
5612 */
5613 if ((*file)[*num_file] == NULL)
5614 break;
5615 (*num_file)++;
5616 }
5617 _fnexplodefree((char **)expl_files);
5618 }
5619 }
5620 return OK;
5621
5622#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005623 /*
5624 * This is the non-OS/2 implementation (really Unix).
5625 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005626 int j;
5627 char_u *tempname;
5628 char_u *command;
5629 FILE *fd;
5630 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005631#define STYLE_ECHO 0 /* use "echo", the default */
5632#define STYLE_GLOB 1 /* use "glob", for csh */
5633#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5634#define STYLE_PRINT 3 /* use "print -N", for zsh */
5635#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5636 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005637 int shell_style = STYLE_ECHO;
5638 int check_spaces;
5639 static int did_find_nul = FALSE;
5640 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005641 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005642 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005643
5644 *num_file = 0; /* default: no files found */
5645 *file = NULL;
5646
5647 /*
5648 * If there are no wildcards, just copy the names to allocated memory.
5649 * Saves a lot of time, because we don't have to start a new shell.
5650 */
5651 if (!have_wildcard(num_pat, pat))
5652 return save_patterns(num_pat, pat, num_file, file);
5653
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005654# ifdef HAVE_SANDBOX
5655 /* Don't allow any shell command in the sandbox. */
5656 if (sandbox != 0 && check_secure())
5657 return FAIL;
5658# endif
5659
Bram Moolenaar071d4272004-06-13 20:20:40 +00005660 /*
5661 * Don't allow the use of backticks in secure and restricted mode.
5662 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005663 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005664 for (i = 0; i < num_pat; ++i)
5665 if (vim_strchr(pat[i], '`') != NULL
5666 && (check_restricted() || check_secure()))
5667 return FAIL;
5668
5669 /*
5670 * get a name for the temp file
5671 */
5672 if ((tempname = vim_tempname('o')) == NULL)
5673 {
5674 EMSG(_(e_notmp));
5675 return FAIL;
5676 }
5677
5678 /*
5679 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005680 * file.
5681 * STYLE_BT: NL separated
5682 * If expanding `cmd` execute it directly.
5683 * STYLE_GLOB: NUL separated
5684 * If we use *csh, "glob" will work better than "echo".
5685 * STYLE_PRINT: NL or NUL separated
5686 * If we use *zsh, "print -N" will work better than "glob".
5687 * STYLE_VIMGLOB: NL separated
5688 * If we use *sh*, we define "vimglob()".
5689 * STYLE_ECHO: space separated.
5690 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005691 */
5692 if (num_pat == 1 && *pat[0] == '`'
5693 && (len = STRLEN(pat[0])) > 2
5694 && *(pat[0] + len - 1) == '`')
5695 shell_style = STYLE_BT;
5696 else if ((len = STRLEN(p_sh)) >= 3)
5697 {
5698 if (STRCMP(p_sh + len - 3, "csh") == 0)
5699 shell_style = STYLE_GLOB;
5700 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5701 shell_style = STYLE_PRINT;
5702 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005703 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5704 "sh") != NULL)
5705 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005706
Bram Moolenaarc7247912008-01-13 12:54:11 +00005707 /* Compute the length of the command. We need 2 extra bytes: for the
5708 * optional '&' and for the NUL.
5709 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005710 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005711 if (shell_style == STYLE_VIMGLOB)
5712 len += STRLEN(sh_vimglob_func);
5713
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005714 for (i = 0; i < num_pat; ++i)
5715 {
5716 /* Count the length of the patterns in the same way as they are put in
5717 * "command" below. */
5718#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005719 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005720#else
5721 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005722 for (j = 0; pat[i][j] != NUL; ++j)
5723 {
5724 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5725 ++len; /* may add a backslash */
5726 ++len;
5727 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005728#endif
5729 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005730 command = alloc(len);
5731 if (command == NULL)
5732 {
5733 /* out of memory */
5734 vim_free(tempname);
5735 return FAIL;
5736 }
5737
5738 /*
5739 * Build the shell command:
5740 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5741 * recognizes this).
5742 * - Add the shell command to print the expanded names.
5743 * - Add the temp file name.
5744 * - Add the file name patterns.
5745 */
5746 if (shell_style == STYLE_BT)
5747 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005748 /* change `command; command& ` to (command; command ) */
5749 STRCPY(command, "(");
5750 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005751 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005752 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005753 while (p > command && vim_iswhite(*p))
5754 --p;
5755 if (*p == '&') /* remove trailing '&' */
5756 {
5757 ampersent = TRUE;
5758 *p = ' ';
5759 }
5760 STRCAT(command, ">");
5761 }
5762 else
5763 {
5764 if (flags & EW_NOTFOUND)
5765 STRCPY(command, "set nonomatch; ");
5766 else
5767 STRCPY(command, "unset nonomatch; ");
5768 if (shell_style == STYLE_GLOB)
5769 STRCAT(command, "glob >");
5770 else if (shell_style == STYLE_PRINT)
5771 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005772 else if (shell_style == STYLE_VIMGLOB)
5773 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005774 else
5775 STRCAT(command, "echo >");
5776 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005777
Bram Moolenaar071d4272004-06-13 20:20:40 +00005778 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005779
Bram Moolenaar071d4272004-06-13 20:20:40 +00005780 if (shell_style != STYLE_BT)
5781 for (i = 0; i < num_pat; ++i)
5782 {
5783 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005784 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005785 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005786#ifdef USE_SYSTEM
5787 STRCAT(command, " \"");
5788 STRCAT(command, pat[i]);
5789 STRCAT(command, "\"");
5790#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005791 int intick = FALSE;
5792
Bram Moolenaar071d4272004-06-13 20:20:40 +00005793 p = command + STRLEN(command);
5794 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005795 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005796 {
5797 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005798 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005799 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5800 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005801 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005802 * backslash inside backticks, before a special character
5803 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005804 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005805 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5806 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005807 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005808 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005809 }
5810 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005811 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005812 /* Put a backslash before a special character, but not
5813 * when inside ``. */
5814 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005815
5816 /* Copy one character. */
5817 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005818 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005819 *p = NUL;
5820#endif
5821 }
5822 if (flags & EW_SILENT)
5823 show_shell_mess = FALSE;
5824 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00005825 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005826
5827 /*
5828 * Using zsh -G: If a pattern has no matches, it is just deleted from
5829 * the argument list, otherwise zsh gives an error message and doesn't
5830 * expand any other pattern.
5831 */
5832 if (shell_style == STYLE_PRINT)
5833 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5834
5835 /*
5836 * If we use -f then shell variables set in .cshrc won't get expanded.
5837 * vi can do it, so we will too, but it is only necessary if there is a "$"
5838 * in one of the patterns, otherwise we can still use the fast option.
5839 */
5840 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5841 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5842
5843 /*
5844 * execute the shell command
5845 */
5846 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5847
5848 /* When running in the background, give it some time to create the temp
5849 * file, but don't wait for it to finish. */
5850 if (ampersent)
5851 mch_delay(10L, TRUE);
5852
5853 extra_shell_arg = NULL; /* cleanup */
5854 show_shell_mess = TRUE;
5855 vim_free(command);
5856
Bram Moolenaarc7247912008-01-13 12:54:11 +00005857 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005858 {
5859 mch_remove(tempname);
5860 vim_free(tempname);
5861 /*
5862 * With interactive completion, the error message is not printed.
5863 * However with USE_SYSTEM, I don't know how to turn off error messages
5864 * from the shell, so screen may still get messed up -- webb.
5865 */
5866#ifndef USE_SYSTEM
5867 if (!(flags & EW_SILENT))
5868#endif
5869 {
5870 redraw_later_clear(); /* probably messed up screen */
5871 msg_putchar('\n'); /* clear bottom line quickly */
5872 cmdline_row = Rows - 1; /* continue on last line */
5873#ifdef USE_SYSTEM
5874 if (!(flags & EW_SILENT))
5875#endif
5876 {
5877 MSG(_(e_wildexpand));
5878 msg_start(); /* don't overwrite this message */
5879 }
5880 }
5881 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5882 * EW_NOTFOUND is given */
5883 if (shell_style == STYLE_BT)
5884 return FAIL;
5885 goto notfound;
5886 }
5887
5888 /*
5889 * read the names from the file into memory
5890 */
5891 fd = fopen((char *)tempname, READBIN);
5892 if (fd == NULL)
5893 {
5894 /* Something went wrong, perhaps a file name with a special char. */
5895 if (!(flags & EW_SILENT))
5896 {
5897 MSG(_(e_wildexpand));
5898 msg_start(); /* don't overwrite this message */
5899 }
5900 vim_free(tempname);
5901 goto notfound;
5902 }
5903 fseek(fd, 0L, SEEK_END);
5904 len = ftell(fd); /* get size of temp file */
5905 fseek(fd, 0L, SEEK_SET);
5906 buffer = alloc(len + 1);
5907 if (buffer == NULL)
5908 {
5909 /* out of memory */
5910 mch_remove(tempname);
5911 vim_free(tempname);
5912 fclose(fd);
5913 return FAIL;
5914 }
5915 i = fread((char *)buffer, 1, len, fd);
5916 fclose(fd);
5917 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00005918 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005919 {
5920 /* unexpected read error */
5921 EMSG2(_(e_notread), tempname);
5922 vim_free(tempname);
5923 vim_free(buffer);
5924 return FAIL;
5925 }
5926 vim_free(tempname);
5927
Bram Moolenaarc7247912008-01-13 12:54:11 +00005928# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005929 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5930 p = buffer;
5931 for (i = 0; i < len; ++i)
5932 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5933 *p++ = buffer[i];
5934 len = p - buffer;
5935# endif
5936
5937
5938 /* file names are separated with Space */
5939 if (shell_style == STYLE_ECHO)
5940 {
5941 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5942 p = buffer;
5943 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5944 {
5945 while (*p != ' ' && *p != '\n')
5946 ++p;
5947 p = skipwhite(p); /* skip to next entry */
5948 }
5949 }
5950 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005951 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005952 {
5953 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5954 p = buffer;
5955 for (i = 0; *p != NUL; ++i) /* count number of entries */
5956 {
5957 while (*p != '\n' && *p != NUL)
5958 ++p;
5959 if (*p != NUL)
5960 ++p;
5961 p = skipwhite(p); /* skip leading white space */
5962 }
5963 }
5964 /* file names are separated with NUL */
5965 else
5966 {
5967 /*
5968 * Some versions of zsh use spaces instead of NULs to separate
5969 * results. Only do this when there is no NUL before the end of the
5970 * buffer, otherwise we would never be able to use file names with
5971 * embedded spaces when zsh does use NULs.
5972 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5973 * don't check for spaces again.
5974 */
5975 check_spaces = FALSE;
5976 if (shell_style == STYLE_PRINT && !did_find_nul)
5977 {
5978 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02005979 buffer[len] = NUL;
Bram Moolenaar78a15312009-05-15 19:33:18 +00005980 if (len && (int)STRLEN(buffer) < (int)len - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005981 did_find_nul = TRUE;
5982 else
5983 check_spaces = TRUE;
5984 }
5985
5986 /*
5987 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5988 * already is one, for STYLE_GLOB it needs to be added.
5989 */
5990 if (len && buffer[len - 1] == NUL)
5991 --len;
5992 else
5993 buffer[len] = NUL;
5994 i = 0;
5995 for (p = buffer; p < buffer + len; ++p)
5996 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5997 {
5998 ++i;
5999 *p = NUL;
6000 }
6001 if (len)
6002 ++i; /* count last entry */
6003 }
6004 if (i == 0)
6005 {
6006 /*
6007 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6008 * /bin/sh will happily expand it to nothing rather than returning an
6009 * error; and hey, it's good to check anyway -- webb.
6010 */
6011 vim_free(buffer);
6012 goto notfound;
6013 }
6014 *num_file = i;
6015 *file = (char_u **)alloc(sizeof(char_u *) * i);
6016 if (*file == NULL)
6017 {
6018 /* out of memory */
6019 vim_free(buffer);
6020 return FAIL;
6021 }
6022
6023 /*
6024 * Isolate the individual file names.
6025 */
6026 p = buffer;
6027 for (i = 0; i < *num_file; ++i)
6028 {
6029 (*file)[i] = p;
6030 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006031 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6032 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006033 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006034 while (!(shell_style == STYLE_ECHO && *p == ' ')
6035 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006036 ++p;
6037 if (p == buffer + len) /* last entry */
6038 *p = NUL;
6039 else
6040 {
6041 *p++ = NUL;
6042 p = skipwhite(p); /* skip to next entry */
6043 }
6044 }
6045 else /* NUL separates */
6046 {
6047 while (*p && p < buffer + len) /* skip entry */
6048 ++p;
6049 ++p; /* skip NUL */
6050 }
6051 }
6052
6053 /*
6054 * Move the file names to allocated memory.
6055 */
6056 for (j = 0, i = 0; i < *num_file; ++i)
6057 {
6058 /* Require the files to exist. Helps when using /bin/sh */
6059 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6060 continue;
6061
6062 /* check if this entry should be included */
6063 dir = (mch_isdir((*file)[i]));
6064 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6065 continue;
6066
Bram Moolenaara2031822006-03-07 22:29:51 +00006067 /* Skip files that are not executable if we check for that. */
6068 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
6069 continue;
6070
Bram Moolenaar071d4272004-06-13 20:20:40 +00006071 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
6072 if (p)
6073 {
6074 STRCPY(p, (*file)[i]);
6075 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00006076 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006077 (*file)[j++] = p;
6078 }
6079 }
6080 vim_free(buffer);
6081 *num_file = j;
6082
6083 if (*num_file == 0) /* rejected all entries */
6084 {
6085 vim_free(*file);
6086 *file = NULL;
6087 goto notfound;
6088 }
6089
6090 return OK;
6091
6092notfound:
6093 if (flags & EW_NOTFOUND)
6094 return save_patterns(num_pat, pat, num_file, file);
6095 return FAIL;
6096
6097#endif /* __EMX__ */
6098}
6099
6100#endif /* VMS */
6101
6102#ifndef __EMX__
6103 static int
6104save_patterns(num_pat, pat, num_file, file)
6105 int num_pat;
6106 char_u **pat;
6107 int *num_file;
6108 char_u ***file;
6109{
6110 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006111 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006112
6113 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
6114 if (*file == NULL)
6115 return FAIL;
6116 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006117 {
6118 s = vim_strsave(pat[i]);
6119 if (s != NULL)
6120 /* Be compatible with expand_filename(): halve the number of
6121 * backslashes. */
6122 backslash_halve(s);
6123 (*file)[i] = s;
6124 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006125 *num_file = num_pat;
6126 return OK;
6127}
6128#endif
6129
6130
6131/*
6132 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
6133 * expand.
6134 */
6135 int
6136mch_has_exp_wildcard(p)
6137 char_u *p;
6138{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006139 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006140 {
6141#ifndef OS2
6142 if (*p == '\\' && p[1] != NUL)
6143 ++p;
6144 else
6145#endif
6146 if (vim_strchr((char_u *)
6147#ifdef VMS
6148 "*?%"
6149#else
6150# ifdef OS2
6151 "*?"
6152# else
6153 "*?[{'"
6154# endif
6155#endif
6156 , *p) != NULL)
6157 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006158 }
6159 return FALSE;
6160}
6161
6162/*
6163 * Return TRUE if the string "p" contains a wildcard.
6164 * Don't recognize '~' at the end as a wildcard.
6165 */
6166 int
6167mch_has_wildcard(p)
6168 char_u *p;
6169{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006170 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006171 {
6172#ifndef OS2
6173 if (*p == '\\' && p[1] != NUL)
6174 ++p;
6175 else
6176#endif
6177 if (vim_strchr((char_u *)
6178#ifdef VMS
6179 "*?%$"
6180#else
6181# ifdef OS2
6182# ifdef VIM_BACKTICK
6183 "*?$`"
6184# else
6185 "*?$"
6186# endif
6187# else
6188 "*?[{`'$"
6189# endif
6190#endif
6191 , *p) != NULL
6192 || (*p == '~' && p[1] != NUL))
6193 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006194 }
6195 return FALSE;
6196}
6197
6198#ifndef __EMX__
6199 static int
6200have_wildcard(num, file)
6201 int num;
6202 char_u **file;
6203{
6204 int i;
6205
6206 for (i = 0; i < num; i++)
6207 if (mch_has_wildcard(file[i]))
6208 return 1;
6209 return 0;
6210}
6211
6212 static int
6213have_dollars(num, file)
6214 int num;
6215 char_u **file;
6216{
6217 int i;
6218
6219 for (i = 0; i < num; i++)
6220 if (vim_strchr(file[i], '$') != NULL)
6221 return TRUE;
6222 return FALSE;
6223}
6224#endif /* ifndef __EMX__ */
6225
6226#ifndef HAVE_RENAME
6227/*
6228 * Scaled-down version of rename(), which is missing in Xenix.
6229 * This version can only move regular files and will fail if the
6230 * destination exists.
6231 */
6232 int
6233mch_rename(src, dest)
6234 const char *src, *dest;
6235{
6236 struct stat st;
6237
6238 if (stat(dest, &st) >= 0) /* fail if destination exists */
6239 return -1;
6240 if (link(src, dest) != 0) /* link file to new name */
6241 return -1;
6242 if (mch_remove(src) == 0) /* delete link to old name */
6243 return 0;
6244 return -1;
6245}
6246#endif /* !HAVE_RENAME */
6247
6248#ifdef FEAT_MOUSE_GPM
6249/*
6250 * Initializes connection with gpm (if it isn't already opened)
6251 * Return 1 if succeeded (or connection already opened), 0 if failed
6252 */
6253 static int
6254gpm_open()
6255{
6256 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
6257
6258 if (!gpm_flag)
6259 {
6260 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
6261 gpm_connect.defaultMask = ~GPM_HARD;
6262 /* Default handling for mouse move*/
6263 gpm_connect.minMod = 0; /* Handle any modifier keys */
6264 gpm_connect.maxMod = 0xffff;
6265 if (Gpm_Open(&gpm_connect, 0) > 0)
6266 {
6267 /* gpm library tries to handling TSTP causes
6268 * problems. Anyways, we close connection to Gpm whenever
6269 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006270 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00006271 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006272# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00006273 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006274# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006275 return 1; /* succeed */
6276 }
6277 if (gpm_fd == -2)
6278 Gpm_Close(); /* We don't want to talk to xterm via gpm */
6279 return 0;
6280 }
6281 return 1; /* already open */
6282}
6283
6284/*
6285 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00006286 */
6287 static void
6288gpm_close()
6289{
6290 if (gpm_flag && gpm_fd >= 0) /* if Open */
6291 Gpm_Close();
6292}
6293
6294/* Reads gpm event and adds special keys to input buf. Returns length of
6295 * generated key sequence.
6296 * This function is made after gui_send_mouse_event
6297 */
6298 static int
6299mch_gpm_process()
6300{
6301 int button;
6302 static Gpm_Event gpm_event;
6303 char_u string[6];
6304 int_u vim_modifiers;
6305 int row,col;
6306 unsigned char buttons_mask;
6307 unsigned char gpm_modifiers;
6308 static unsigned char old_buttons = 0;
6309
6310 Gpm_GetEvent(&gpm_event);
6311
6312#ifdef FEAT_GUI
6313 /* Don't put events in the input queue now. */
6314 if (hold_gui_events)
6315 return 0;
6316#endif
6317
6318 row = gpm_event.y - 1;
6319 col = gpm_event.x - 1;
6320
6321 string[0] = ESC; /* Our termcode */
6322 string[1] = 'M';
6323 string[2] = 'G';
6324 switch (GPM_BARE_EVENTS(gpm_event.type))
6325 {
6326 case GPM_DRAG:
6327 string[3] = MOUSE_DRAG;
6328 break;
6329 case GPM_DOWN:
6330 buttons_mask = gpm_event.buttons & ~old_buttons;
6331 old_buttons = gpm_event.buttons;
6332 switch (buttons_mask)
6333 {
6334 case GPM_B_LEFT:
6335 button = MOUSE_LEFT;
6336 break;
6337 case GPM_B_MIDDLE:
6338 button = MOUSE_MIDDLE;
6339 break;
6340 case GPM_B_RIGHT:
6341 button = MOUSE_RIGHT;
6342 break;
6343 default:
6344 return 0;
6345 /*Don't know what to do. Can more than one button be
6346 * reported in one event? */
6347 }
6348 string[3] = (char_u)(button | 0x20);
6349 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
6350 break;
6351 case GPM_UP:
6352 string[3] = MOUSE_RELEASE;
6353 old_buttons &= ~gpm_event.buttons;
6354 break;
6355 default:
6356 return 0;
6357 }
6358 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
6359 gpm_modifiers = gpm_event.modifiers;
6360 vim_modifiers = 0x0;
6361 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
6362 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
6363 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
6364 */
6365 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
6366 vim_modifiers |= MOUSE_SHIFT;
6367
6368 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
6369 vim_modifiers |= MOUSE_CTRL;
6370 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
6371 vim_modifiers |= MOUSE_ALT;
6372 string[3] |= vim_modifiers;
6373 string[4] = (char_u)(col + ' ' + 1);
6374 string[5] = (char_u)(row + ' ' + 1);
6375 add_to_input_buf(string, 6);
6376 return 6;
6377}
6378#endif /* FEAT_MOUSE_GPM */
6379
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006380#ifdef FEAT_SYSMOUSE
6381/*
6382 * Initialize connection with sysmouse.
6383 * Let virtual console inform us with SIGUSR2 for pending sysmouse
6384 * output, any sysmouse output than will be processed via sig_sysmouse().
6385 * Return OK if succeeded, FAIL if failed.
6386 */
6387 static int
6388sysmouse_open()
6389{
6390 struct mouse_info mouse;
6391
6392 mouse.operation = MOUSE_MODE;
6393 mouse.u.mode.mode = 0;
6394 mouse.u.mode.signal = SIGUSR2;
6395 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
6396 {
6397 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
6398 mouse.operation = MOUSE_SHOW;
6399 ioctl(1, CONS_MOUSECTL, &mouse);
6400 return OK;
6401 }
6402 return FAIL;
6403}
6404
6405/*
6406 * Stop processing SIGUSR2 signals, and also make sure that
6407 * virtual console do not send us any sysmouse related signal.
6408 */
6409 static void
6410sysmouse_close()
6411{
6412 struct mouse_info mouse;
6413
6414 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
6415 mouse.operation = MOUSE_MODE;
6416 mouse.u.mode.mode = 0;
6417 mouse.u.mode.signal = 0;
6418 ioctl(1, CONS_MOUSECTL, &mouse);
6419}
6420
6421/*
6422 * Gets info from sysmouse and adds special keys to input buf.
6423 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006424 static RETSIGTYPE
6425sig_sysmouse SIGDEFARG(sigarg)
6426{
6427 struct mouse_info mouse;
6428 struct video_info video;
6429 char_u string[6];
6430 int row, col;
6431 int button;
6432 int buttons;
6433 static int oldbuttons = 0;
6434
6435#ifdef FEAT_GUI
6436 /* Don't put events in the input queue now. */
6437 if (hold_gui_events)
6438 return;
6439#endif
6440
6441 mouse.operation = MOUSE_GETINFO;
6442 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
6443 && ioctl(1, FBIO_MODEINFO, &video) != -1
6444 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
6445 && video.vi_cheight > 0 && video.vi_cwidth > 0)
6446 {
6447 row = mouse.u.data.y / video.vi_cheight;
6448 col = mouse.u.data.x / video.vi_cwidth;
6449 buttons = mouse.u.data.buttons;
6450 string[0] = ESC; /* Our termcode */
6451 string[1] = 'M';
6452 string[2] = 'S';
6453 if (oldbuttons == buttons && buttons != 0)
6454 {
6455 button = MOUSE_DRAG;
6456 }
6457 else
6458 {
6459 switch (buttons)
6460 {
6461 case 0:
6462 button = MOUSE_RELEASE;
6463 break;
6464 case 1:
6465 button = MOUSE_LEFT;
6466 break;
6467 case 2:
6468 button = MOUSE_MIDDLE;
6469 break;
6470 case 4:
6471 button = MOUSE_RIGHT;
6472 break;
6473 default:
6474 return;
6475 }
6476 oldbuttons = buttons;
6477 }
6478 string[3] = (char_u)(button);
6479 string[4] = (char_u)(col + ' ' + 1);
6480 string[5] = (char_u)(row + ' ' + 1);
6481 add_to_input_buf(string, 6);
6482 }
6483 return;
6484}
6485#endif /* FEAT_SYSMOUSE */
6486
Bram Moolenaar071d4272004-06-13 20:20:40 +00006487#if defined(FEAT_LIBCALL) || defined(PROTO)
6488typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
6489typedef char_u * (*INTPROCSTR)__ARGS((int));
6490typedef int (*STRPROCINT)__ARGS((char_u *));
6491typedef int (*INTPROCINT)__ARGS((int));
6492
6493/*
6494 * Call a DLL routine which takes either a string or int param
6495 * and returns an allocated string.
6496 */
6497 int
6498mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
6499 char_u *libname;
6500 char_u *funcname;
6501 char_u *argstring; /* NULL when using a argint */
6502 int argint;
6503 char_u **string_result;/* NULL when using number_result */
6504 int *number_result;
6505{
6506# if defined(USE_DLOPEN)
6507 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006508 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006509# else
6510 shl_t hinstLib;
6511# endif
6512 STRPROCSTR ProcAdd;
6513 INTPROCSTR ProcAddI;
6514 char_u *retval_str = NULL;
6515 int retval_int = 0;
6516 int success = FALSE;
6517
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006518 /*
6519 * Get a handle to the DLL module.
6520 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006521# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006522 /* First clear any error, it's not cleared by the dlopen() call. */
6523 (void)dlerror();
6524
Bram Moolenaar071d4272004-06-13 20:20:40 +00006525 hinstLib = dlopen((char *)libname, RTLD_LAZY
6526# ifdef RTLD_LOCAL
6527 | RTLD_LOCAL
6528# endif
6529 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006530 if (hinstLib == NULL)
6531 {
6532 /* "dlerr" must be used before dlclose() */
6533 dlerr = (char *)dlerror();
6534 if (dlerr != NULL)
6535 EMSG2(_("dlerror = \"%s\""), dlerr);
6536 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006537# else
6538 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
6539# endif
6540
6541 /* If the handle is valid, try to get the function address. */
6542 if (hinstLib != NULL)
6543 {
6544# ifdef HAVE_SETJMP_H
6545 /*
6546 * Catch a crash when calling the library function. For example when
6547 * using a number where a string pointer is expected.
6548 */
6549 mch_startjmp();
6550 if (SETJMP(lc_jump_env) != 0)
6551 {
6552 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006553# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006554 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006555# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006556 mch_didjmp();
6557 }
6558 else
6559# endif
6560 {
6561 retval_str = NULL;
6562 retval_int = 0;
6563
6564 if (argstring != NULL)
6565 {
6566# if defined(USE_DLOPEN)
6567 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006568 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006569# else
6570 if (shl_findsym(&hinstLib, (const char *)funcname,
6571 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
6572 ProcAdd = NULL;
6573# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006574 if ((success = (ProcAdd != NULL
6575# if defined(USE_DLOPEN)
6576 && dlerr == NULL
6577# endif
6578 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006579 {
6580 if (string_result == NULL)
6581 retval_int = ((STRPROCINT)ProcAdd)(argstring);
6582 else
6583 retval_str = (ProcAdd)(argstring);
6584 }
6585 }
6586 else
6587 {
6588# if defined(USE_DLOPEN)
6589 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006590 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006591# else
6592 if (shl_findsym(&hinstLib, (const char *)funcname,
6593 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
6594 ProcAddI = NULL;
6595# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006596 if ((success = (ProcAddI != NULL
6597# if defined(USE_DLOPEN)
6598 && dlerr == NULL
6599# endif
6600 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006601 {
6602 if (string_result == NULL)
6603 retval_int = ((INTPROCINT)ProcAddI)(argint);
6604 else
6605 retval_str = (ProcAddI)(argint);
6606 }
6607 }
6608
6609 /* Save the string before we free the library. */
6610 /* Assume that a "1" or "-1" result is an illegal pointer. */
6611 if (string_result == NULL)
6612 *number_result = retval_int;
6613 else if (retval_str != NULL
6614 && retval_str != (char_u *)1
6615 && retval_str != (char_u *)-1)
6616 *string_result = vim_strsave(retval_str);
6617 }
6618
6619# ifdef HAVE_SETJMP_H
6620 mch_endjmp();
6621# ifdef SIGHASARG
6622 if (lc_signal != 0)
6623 {
6624 int i;
6625
6626 /* try to find the name of this signal */
6627 for (i = 0; signal_info[i].sig != -1; i++)
6628 if (lc_signal == signal_info[i].sig)
6629 break;
6630 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6631 }
6632# endif
6633# endif
6634
Bram Moolenaar071d4272004-06-13 20:20:40 +00006635# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006636 /* "dlerr" must be used before dlclose() */
6637 if (dlerr != NULL)
6638 EMSG2(_("dlerror = \"%s\""), dlerr);
6639
6640 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006641 (void)dlclose(hinstLib);
6642# else
6643 (void)shl_unload(hinstLib);
6644# endif
6645 }
6646
6647 if (!success)
6648 {
6649 EMSG2(_(e_libcall), funcname);
6650 return FAIL;
6651 }
6652
6653 return OK;
6654}
6655#endif
6656
6657#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6658static int xterm_trace = -1; /* default: disabled */
6659static int xterm_button;
6660
6661/*
6662 * Setup a dummy window for X selections in a terminal.
6663 */
6664 void
6665setup_term_clip()
6666{
6667 int z = 0;
6668 char *strp = "";
6669 Widget AppShell;
6670
6671 if (!x_connect_to_server())
6672 return;
6673
6674 open_app_context();
6675 if (app_context != NULL && xterm_Shell == (Widget)0)
6676 {
6677 int (*oldhandler)();
6678#if defined(HAVE_SETJMP_H)
6679 int (*oldIOhandler)();
6680#endif
6681# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6682 struct timeval start_tv;
6683
6684 if (p_verbose > 0)
6685 gettimeofday(&start_tv, NULL);
6686# endif
6687
6688 /* Ignore X errors while opening the display */
6689 oldhandler = XSetErrorHandler(x_error_check);
6690
6691#if defined(HAVE_SETJMP_H)
6692 /* Ignore X IO errors while opening the display */
6693 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6694 mch_startjmp();
6695 if (SETJMP(lc_jump_env) != 0)
6696 {
6697 mch_didjmp();
6698 xterm_dpy = NULL;
6699 }
6700 else
6701#endif
6702 {
6703 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6704 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6705#if defined(HAVE_SETJMP_H)
6706 mch_endjmp();
6707#endif
6708 }
6709
6710#if defined(HAVE_SETJMP_H)
6711 /* Now handle X IO errors normally. */
6712 (void)XSetIOErrorHandler(oldIOhandler);
6713#endif
6714 /* Now handle X errors normally. */
6715 (void)XSetErrorHandler(oldhandler);
6716
6717 if (xterm_dpy == NULL)
6718 {
6719 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006720 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006721 return;
6722 }
6723
6724 /* Catch terminating error of the X server connection. */
6725 (void)XSetIOErrorHandler(x_IOerror_handler);
6726
6727# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6728 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006729 {
6730 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006731 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006732 verbose_leave();
6733 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006734# endif
6735
6736 /* Create a Shell to make converters work. */
6737 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6738 applicationShellWidgetClass, xterm_dpy,
6739 NULL);
6740 if (AppShell == (Widget)0)
6741 return;
6742 xterm_Shell = XtVaCreatePopupShell("VIM",
6743 topLevelShellWidgetClass, AppShell,
6744 XtNmappedWhenManaged, 0,
6745 XtNwidth, 1,
6746 XtNheight, 1,
6747 NULL);
6748 if (xterm_Shell == (Widget)0)
6749 return;
6750
6751 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02006752 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006753 if (x11_display == NULL)
6754 x11_display = xterm_dpy;
6755
6756 XtRealizeWidget(xterm_Shell);
6757 XSync(xterm_dpy, False);
6758 xterm_update();
6759 }
6760 if (xterm_Shell != (Widget)0)
6761 {
6762 clip_init(TRUE);
6763 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6764 x11_window = (Window)atol(strp);
6765 /* Check if $WINDOWID is valid. */
6766 if (test_x11_window(xterm_dpy) == FAIL)
6767 x11_window = 0;
6768 if (x11_window != 0)
6769 xterm_trace = 0;
6770 }
6771}
6772
6773 void
6774start_xterm_trace(button)
6775 int button;
6776{
6777 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6778 return;
6779 xterm_trace = 1;
6780 xterm_button = button;
6781 do_xterm_trace();
6782}
6783
6784
6785 void
6786stop_xterm_trace()
6787{
6788 if (xterm_trace < 0)
6789 return;
6790 xterm_trace = 0;
6791}
6792
6793/*
6794 * Query the xterm pointer and generate mouse termcodes if necessary
6795 * return TRUE if dragging is active, else FALSE
6796 */
6797 static int
6798do_xterm_trace()
6799{
6800 Window root, child;
6801 int root_x, root_y;
6802 int win_x, win_y;
6803 int row, col;
6804 int_u mask_return;
6805 char_u buf[50];
6806 char_u *strp;
6807 long got_hints;
6808 static char_u *mouse_code;
6809 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6810 static int prev_row = 0, prev_col = 0;
6811 static XSizeHints xterm_hints;
6812
6813 if (xterm_trace <= 0)
6814 return FALSE;
6815
6816 if (xterm_trace == 1)
6817 {
6818 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006819 * have changed recently. */
6820 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6821 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006822 || xterm_hints.width_inc <= 1
6823 || xterm_hints.height_inc <= 1)
6824 {
6825 xterm_trace = -1; /* Not enough data -- disable tracing */
6826 return FALSE;
6827 }
6828
6829 /* Rely on the same mouse code for the duration of this */
6830 mouse_code = find_termcode(mouse_name);
6831 prev_row = mouse_row;
6832 prev_row = mouse_col;
6833 xterm_trace = 2;
6834
6835 /* Find the offset of the chars, there might be a scrollbar on the
6836 * left of the window and/or a menu on the top (eterm etc.) */
6837 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6838 &win_x, &win_y, &mask_return);
6839 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6840 - (xterm_hints.height_inc / 2);
6841 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6842 xterm_hints.y = 2;
6843 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6844 - (xterm_hints.width_inc / 2);
6845 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6846 xterm_hints.x = 2;
6847 return TRUE;
6848 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006849 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006850 {
6851 xterm_trace = 0;
6852 return FALSE;
6853 }
6854
6855 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6856 &win_x, &win_y, &mask_return);
6857
6858 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6859 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6860 if (row == prev_row && col == prev_col)
6861 return TRUE;
6862
6863 STRCPY(buf, mouse_code);
6864 strp = buf + STRLEN(buf);
6865 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6866 *strp++ = (char_u)(col + ' ' + 1);
6867 *strp++ = (char_u)(row + ' ' + 1);
6868 *strp = 0;
6869 add_to_input_buf(buf, STRLEN(buf));
6870
6871 prev_row = row;
6872 prev_col = col;
6873 return TRUE;
6874}
6875
6876# if defined(FEAT_GUI) || defined(PROTO)
6877/*
6878 * Destroy the display, window and app_context. Required for GTK.
6879 */
6880 void
6881clear_xterm_clip()
6882{
6883 if (xterm_Shell != (Widget)0)
6884 {
6885 XtDestroyWidget(xterm_Shell);
6886 xterm_Shell = (Widget)0;
6887 }
6888 if (xterm_dpy != NULL)
6889 {
Bram Moolenaare8208012008-06-20 09:59:25 +00006890# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006891 /* Lesstif and Solaris crash here, lose some memory */
6892 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00006893# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006894 if (x11_display == xterm_dpy)
6895 x11_display = NULL;
6896 xterm_dpy = NULL;
6897 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006898# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006899 if (app_context != (XtAppContext)NULL)
6900 {
6901 /* Lesstif and Solaris crash here, lose some memory */
6902 XtDestroyApplicationContext(app_context);
6903 app_context = (XtAppContext)NULL;
6904 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006905# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006906}
6907# endif
6908
6909/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01006910 * Catch up with GUI or X events.
6911 */
6912 static void
6913clip_update()
6914{
6915# ifdef FEAT_GUI
6916 if (gui.in_use)
6917 gui_mch_update();
6918 else
6919# endif
6920 if (xterm_Shell != (Widget)0)
6921 xterm_update();
6922}
6923
6924/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006925 * Catch up with any queued X events. This may put keyboard input into the
6926 * input buffer, call resize call-backs, trigger timers etc. If there is
6927 * nothing in the X event queue (& no timers pending), then we return
6928 * immediately.
6929 */
6930 static void
6931xterm_update()
6932{
6933 XEvent event;
6934
6935 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6936 {
6937 XtAppNextEvent(app_context, &event);
6938#ifdef FEAT_CLIENTSERVER
6939 {
6940 XPropertyEvent *e = (XPropertyEvent *)&event;
6941
6942 if (e->type == PropertyNotify && e->window == commWindow
6943 && e->atom == commProperty && e->state == PropertyNewValue)
6944 serverEventProc(xterm_dpy, &event);
6945 }
6946#endif
6947 XtDispatchEvent(&event);
6948 }
6949}
6950
6951 int
6952clip_xterm_own_selection(cbd)
6953 VimClipboard *cbd;
6954{
6955 if (xterm_Shell != (Widget)0)
6956 return clip_x11_own_selection(xterm_Shell, cbd);
6957 return FAIL;
6958}
6959
6960 void
6961clip_xterm_lose_selection(cbd)
6962 VimClipboard *cbd;
6963{
6964 if (xterm_Shell != (Widget)0)
6965 clip_x11_lose_selection(xterm_Shell, cbd);
6966}
6967
6968 void
6969clip_xterm_request_selection(cbd)
6970 VimClipboard *cbd;
6971{
6972 if (xterm_Shell != (Widget)0)
6973 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6974}
6975
6976 void
6977clip_xterm_set_selection(cbd)
6978 VimClipboard *cbd;
6979{
6980 clip_x11_set_selection(cbd);
6981}
6982#endif
6983
6984
6985#if defined(USE_XSMP) || defined(PROTO)
6986/*
6987 * Code for X Session Management Protocol.
6988 */
6989static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6990static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6991static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6992static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6993static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6994
6995
6996# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6997static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6998
6999/*
7000 * This is our chance to ask the user if they want to save,
7001 * or abort the logout
7002 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007003 static void
7004xsmp_handle_interaction(smc_conn, client_data)
7005 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007006 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007007{
7008 cmdmod_T save_cmdmod;
7009 int cancel_shutdown = False;
7010
7011 save_cmdmod = cmdmod;
7012 cmdmod.confirm = TRUE;
7013 if (check_changed_any(FALSE))
7014 /* Mustn't logout */
7015 cancel_shutdown = True;
7016 cmdmod = save_cmdmod;
7017 setcursor(); /* position cursor */
7018 out_flush();
7019
7020 /* Done interaction */
7021 SmcInteractDone(smc_conn, cancel_shutdown);
7022
7023 /* Finish off
7024 * Only end save-yourself here if we're not cancelling shutdown;
7025 * we'll get a cancelled callback later in which we'll end it.
7026 * Hopefully get around glitchy SMs (like GNOME-1)
7027 */
7028 if (!cancel_shutdown)
7029 {
7030 xsmp.save_yourself = False;
7031 SmcSaveYourselfDone(smc_conn, True);
7032 }
7033}
7034# endif
7035
7036/*
7037 * Callback that starts save-yourself.
7038 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007039 static void
7040xsmp_handle_save_yourself(smc_conn, client_data, save_type,
7041 shutdown, interact_style, fast)
7042 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007043 SmPointer client_data UNUSED;
7044 int save_type UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007045 Bool shutdown;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007046 int interact_style UNUSED;
7047 Bool fast UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007048{
7049 /* Handle already being in saveyourself */
7050 if (xsmp.save_yourself)
7051 SmcSaveYourselfDone(smc_conn, True);
7052 xsmp.save_yourself = True;
7053 xsmp.shutdown = shutdown;
7054
7055 /* First up, preserve all files */
7056 out_flush();
7057 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
7058
7059 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007060 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007061
7062# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7063 /* Now see if we can ask about unsaved files */
7064 if (shutdown && !fast && gui.in_use)
7065 /* Need to interact with user, but need SM's permission */
7066 SmcInteractRequest(smc_conn, SmDialogError,
7067 xsmp_handle_interaction, client_data);
7068 else
7069# endif
7070 {
7071 /* Can stop the cycle here */
7072 SmcSaveYourselfDone(smc_conn, True);
7073 xsmp.save_yourself = False;
7074 }
7075}
7076
7077
7078/*
7079 * Callback to warn us of imminent death.
7080 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007081 static void
7082xsmp_die(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007083 SmcConn smc_conn UNUSED;
7084 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007085{
7086 xsmp_close();
7087
7088 /* quit quickly leaving swapfiles for modified buffers behind */
7089 getout_preserve_modified(0);
7090}
7091
7092
7093/*
7094 * Callback to tell us that save-yourself has completed.
7095 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007096 static void
7097xsmp_save_complete(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007098 SmcConn smc_conn UNUSED;
7099 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007100{
7101 xsmp.save_yourself = False;
7102}
7103
7104
7105/*
7106 * Callback to tell us that an instigated shutdown was cancelled
7107 * (maybe even by us)
7108 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007109 static void
7110xsmp_shutdown_cancelled(smc_conn, client_data)
7111 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007112 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007113{
7114 if (xsmp.save_yourself)
7115 SmcSaveYourselfDone(smc_conn, True);
7116 xsmp.save_yourself = False;
7117 xsmp.shutdown = False;
7118}
7119
7120
7121/*
7122 * Callback to tell us that a new ICE connection has been established.
7123 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007124 static void
7125xsmp_ice_connection(iceConn, clientData, opening, watchData)
7126 IceConn iceConn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007127 IcePointer clientData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007128 Bool opening;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007129 IcePointer *watchData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007130{
7131 /* Intercept creation of ICE connection fd */
7132 if (opening)
7133 {
7134 xsmp_icefd = IceConnectionNumber(iceConn);
7135 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7136 }
7137}
7138
7139
7140/* Handle any ICE processing that's required; return FAIL if SM lost */
7141 int
7142xsmp_handle_requests()
7143{
7144 Bool rep;
7145
7146 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7147 == IceProcessMessagesIOError)
7148 {
7149 /* Lost ICE */
7150 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007151 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007152 xsmp_close();
7153 return FAIL;
7154 }
7155 else
7156 return OK;
7157}
7158
7159static int dummy;
7160
7161/* Set up X Session Management Protocol */
7162 void
7163xsmp_init(void)
7164{
7165 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007166 SmcCallbacks smcallbacks;
7167#if 0
7168 SmPropValue smname;
7169 SmProp smnameprop;
7170 SmProp *smprops[1];
7171#endif
7172
7173 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007174 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007175
7176 xsmp.save_yourself = xsmp.shutdown = False;
7177
7178 /* Set up SM callbacks - must have all, even if they're not used */
7179 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
7180 smcallbacks.save_yourself.client_data = NULL;
7181 smcallbacks.die.callback = xsmp_die;
7182 smcallbacks.die.client_data = NULL;
7183 smcallbacks.save_complete.callback = xsmp_save_complete;
7184 smcallbacks.save_complete.client_data = NULL;
7185 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
7186 smcallbacks.shutdown_cancelled.client_data = NULL;
7187
7188 /* Set up a watch on ICE connection creations. The "dummy" argument is
7189 * apparently required for FreeBSD (we get a BUS error when using NULL). */
7190 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
7191 {
7192 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007193 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007194 return;
7195 }
7196
7197 /* Create an SM connection */
7198 xsmp.smcconn = SmcOpenConnection(
7199 NULL,
7200 NULL,
7201 SmProtoMajor,
7202 SmProtoMinor,
7203 SmcSaveYourselfProcMask | SmcDieProcMask
7204 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
7205 &smcallbacks,
7206 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00007207 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007208 sizeof(errorstring),
7209 errorstring);
7210 if (xsmp.smcconn == NULL)
7211 {
7212 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00007213
Bram Moolenaar071d4272004-06-13 20:20:40 +00007214 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007215 {
7216 vim_snprintf(errorreport, sizeof(errorreport),
7217 _("XSMP SmcOpenConnection failed: %s"), errorstring);
7218 verb_msg((char_u *)errorreport);
7219 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007220 return;
7221 }
7222 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
7223
7224#if 0
7225 /* ID ourselves */
7226 smname.value = "vim";
7227 smname.length = 3;
7228 smnameprop.name = "SmProgram";
7229 smnameprop.type = "SmARRAY8";
7230 smnameprop.num_vals = 1;
7231 smnameprop.vals = &smname;
7232
7233 smprops[0] = &smnameprop;
7234 SmcSetProperties(xsmp.smcconn, 1, smprops);
7235#endif
7236}
7237
7238
7239/* Shut down XSMP comms. */
7240 void
7241xsmp_close()
7242{
7243 if (xsmp_icefd != -1)
7244 {
7245 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00007246 if (xsmp.clientid != NULL)
7247 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00007248 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007249 xsmp_icefd = -1;
7250 }
7251}
7252#endif /* USE_XSMP */
7253
7254
7255#ifdef EBCDIC
7256/* Translate character to its CTRL- value */
7257char CtrlTable[] =
7258{
7259/* 00 - 5E */
7260 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7261 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7262 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7263 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7264 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7265 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7266/* ^ */ 0x1E,
7267/* - */ 0x1F,
7268/* 61 - 6C */
7269 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7270/* _ */ 0x1F,
7271/* 6E - 80 */
7272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7273/* a */ 0x01,
7274/* b */ 0x02,
7275/* c */ 0x03,
7276/* d */ 0x37,
7277/* e */ 0x2D,
7278/* f */ 0x2E,
7279/* g */ 0x2F,
7280/* h */ 0x16,
7281/* i */ 0x05,
7282/* 8A - 90 */
7283 0, 0, 0, 0, 0, 0, 0,
7284/* j */ 0x15,
7285/* k */ 0x0B,
7286/* l */ 0x0C,
7287/* m */ 0x0D,
7288/* n */ 0x0E,
7289/* o */ 0x0F,
7290/* p */ 0x10,
7291/* q */ 0x11,
7292/* r */ 0x12,
7293/* 9A - A1 */
7294 0, 0, 0, 0, 0, 0, 0, 0,
7295/* s */ 0x13,
7296/* t */ 0x3C,
7297/* u */ 0x3D,
7298/* v */ 0x32,
7299/* w */ 0x26,
7300/* x */ 0x18,
7301/* y */ 0x19,
7302/* z */ 0x3F,
7303/* AA - AC */
7304 0, 0, 0,
7305/* [ */ 0x27,
7306/* AE - BC */
7307 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7308/* ] */ 0x1D,
7309/* BE - C0 */ 0, 0, 0,
7310/* A */ 0x01,
7311/* B */ 0x02,
7312/* C */ 0x03,
7313/* D */ 0x37,
7314/* E */ 0x2D,
7315/* F */ 0x2E,
7316/* G */ 0x2F,
7317/* H */ 0x16,
7318/* I */ 0x05,
7319/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
7320/* J */ 0x15,
7321/* K */ 0x0B,
7322/* L */ 0x0C,
7323/* M */ 0x0D,
7324/* N */ 0x0E,
7325/* O */ 0x0F,
7326/* P */ 0x10,
7327/* Q */ 0x11,
7328/* R */ 0x12,
7329/* DA - DF */ 0, 0, 0, 0, 0, 0,
7330/* \ */ 0x1C,
7331/* E1 */ 0,
7332/* S */ 0x13,
7333/* T */ 0x3C,
7334/* U */ 0x3D,
7335/* V */ 0x32,
7336/* W */ 0x26,
7337/* X */ 0x18,
7338/* Y */ 0x19,
7339/* Z */ 0x3F,
7340/* EA - FF*/ 0, 0, 0, 0, 0, 0,
7341 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7342};
7343
7344char MetaCharTable[]=
7345{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7346 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
7347 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
7348 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
7349 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
7350};
7351
7352
7353/* TODO: Use characters NOT numbers!!! */
7354char CtrlCharTable[]=
7355{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7356 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
7357 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
7358 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
7359 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
7360};
7361
7362
7363#endif