blob: f878fa9578d474e72d470d8b8ebd1b39f574912e [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 */
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003496# ifdef JSBTERM_MOUSE_NONADVANCED
3497 /* Disables full feedback of pointer movements */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003498 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3499 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003500# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003501 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3502 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003503# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003504 ison = TRUE;
3505 }
3506 else
3507 {
3508 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3509 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3510 ison = FALSE;
3511 }
3512 }
3513# endif
3514# ifdef FEAT_MOUSE_PTERM
3515 else
3516 {
3517 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3518 if (on)
3519 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3520 else
3521 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3522 ison = on;
3523 }
3524# endif
3525}
3526
3527/*
3528 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3529 */
3530 void
3531check_mouse_termcode()
3532{
3533# ifdef FEAT_MOUSE_XTERM
3534 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003535# ifdef FEAT_MOUSE_URXVT
3536 && use_xterm_mouse() != 3
3537# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538# ifdef FEAT_GUI
3539 && !gui.in_use
3540# endif
3541 )
3542 {
3543 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003544 ? IF_EB("\233M", CSI_STR "M")
3545 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546 if (*p_mouse != NUL)
3547 {
3548 /* force mouse off and maybe on to send possibly new mouse
3549 * activation sequence to the xterm, with(out) drag tracing. */
3550 mch_setmouse(FALSE);
3551 setmouse();
3552 }
3553 }
3554 else
3555 del_mouse_termcode(KS_MOUSE);
3556# endif
3557
3558# ifdef FEAT_MOUSE_GPM
3559 if (!use_xterm_mouse()
3560# ifdef FEAT_GUI
3561 && !gui.in_use
3562# endif
3563 )
3564 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3565# endif
3566
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003567# ifdef FEAT_SYSMOUSE
3568 if (!use_xterm_mouse()
3569# ifdef FEAT_GUI
3570 && !gui.in_use
3571# endif
3572 )
3573 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3574# endif
3575
Bram Moolenaar071d4272004-06-13 20:20:40 +00003576# ifdef FEAT_MOUSE_JSB
3577 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3578 if (!use_xterm_mouse()
3579# ifdef FEAT_GUI
3580 && !gui.in_use
3581# endif
3582 )
3583 set_mouse_termcode(KS_JSBTERM_MOUSE,
3584 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3585 else
3586 del_mouse_termcode(KS_JSBTERM_MOUSE);
3587# endif
3588
3589# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003590 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003591 * define it in the GUI or when using an xterm. */
3592 if (!use_xterm_mouse()
3593# ifdef FEAT_GUI
3594 && !gui.in_use
3595# endif
3596 )
3597 set_mouse_termcode(KS_NETTERM_MOUSE,
3598 (char_u *)IF_EB("\033}", ESC_STR "}"));
3599 else
3600 del_mouse_termcode(KS_NETTERM_MOUSE);
3601# endif
3602
3603# ifdef FEAT_MOUSE_DEC
3604 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3605 if (!use_xterm_mouse()
3606# ifdef FEAT_GUI
3607 && !gui.in_use
3608# endif
3609 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003610 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3611 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003612 else
3613 del_mouse_termcode(KS_DEC_MOUSE);
3614# endif
3615# ifdef FEAT_MOUSE_PTERM
3616 /* same as the dec mouse */
3617 if (!use_xterm_mouse()
3618# ifdef FEAT_GUI
3619 && !gui.in_use
3620# endif
3621 )
3622 set_mouse_termcode(KS_PTERM_MOUSE,
3623 (char_u *) IF_EB("\033[", ESC_STR "["));
3624 else
3625 del_mouse_termcode(KS_PTERM_MOUSE);
3626# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003627# ifdef FEAT_MOUSE_URXVT
3628 /* same as the dec mouse */
3629 if (use_xterm_mouse() == 3
3630# ifdef FEAT_GUI
3631 && !gui.in_use
3632# endif
3633 )
3634 {
3635 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3636 ? IF_EB("\233", CSI_STR)
3637 : IF_EB("\033[", ESC_STR "[")));
3638
3639 if (*p_mouse != NUL)
3640 {
3641 mch_setmouse(FALSE);
3642 setmouse();
3643 }
3644 }
3645 else
3646 del_mouse_termcode(KS_URXVT_MOUSE);
3647# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003648# ifdef FEAT_MOUSE_SGR
3649 /* same as the dec mouse */
3650 if (use_xterm_mouse() == 4
3651# ifdef FEAT_GUI
3652 && !gui.in_use
3653# endif
3654 )
3655 {
3656 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3657 ? IF_EB("\233<", CSI_STR "<")
3658 : IF_EB("\033[<", ESC_STR "[<")));
3659
3660 if (*p_mouse != NUL)
3661 {
3662 mch_setmouse(FALSE);
3663 setmouse();
3664 }
3665 }
3666 else
3667 del_mouse_termcode(KS_SGR_MOUSE);
3668# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669}
3670#endif
3671
3672/*
3673 * set screen mode, always fails.
3674 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003675 int
3676mch_screenmode(arg)
Bram Moolenaar78a15312009-05-15 19:33:18 +00003677 char_u *arg UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678{
3679 EMSG(_(e_screenmode));
3680 return FAIL;
3681}
3682
3683#ifndef VMS
3684
3685/*
3686 * Try to get the current window size:
3687 * 1. with an ioctl(), most accurate method
3688 * 2. from the environment variables LINES and COLUMNS
3689 * 3. from the termcap
3690 * 4. keep using the old values
3691 * Return OK when size could be determined, FAIL otherwise.
3692 */
3693 int
3694mch_get_shellsize()
3695{
3696 long rows = 0;
3697 long columns = 0;
3698 char_u *p;
3699
3700 /*
3701 * For OS/2 use _scrsize().
3702 */
3703# ifdef __EMX__
3704 {
3705 int s[2];
3706
3707 _scrsize(s);
3708 columns = s[0];
3709 rows = s[1];
3710 }
3711# endif
3712
3713 /*
3714 * 1. try using an ioctl. It is the most accurate method.
3715 *
3716 * Try using TIOCGWINSZ first, some systems that have it also define
3717 * TIOCGSIZE but don't have a struct ttysize.
3718 */
3719# ifdef TIOCGWINSZ
3720 {
3721 struct winsize ws;
3722 int fd = 1;
3723
3724 /* When stdout is not a tty, use stdin for the ioctl(). */
3725 if (!isatty(fd) && isatty(read_cmd_fd))
3726 fd = read_cmd_fd;
3727 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3728 {
3729 columns = ws.ws_col;
3730 rows = ws.ws_row;
3731 }
3732 }
3733# else /* TIOCGWINSZ */
3734# ifdef TIOCGSIZE
3735 {
3736 struct ttysize ts;
3737 int fd = 1;
3738
3739 /* When stdout is not a tty, use stdin for the ioctl(). */
3740 if (!isatty(fd) && isatty(read_cmd_fd))
3741 fd = read_cmd_fd;
3742 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3743 {
3744 columns = ts.ts_cols;
3745 rows = ts.ts_lines;
3746 }
3747 }
3748# endif /* TIOCGSIZE */
3749# endif /* TIOCGWINSZ */
3750
3751 /*
3752 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003753 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3754 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003756 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003757 {
3758 if ((p = (char_u *)getenv("LINES")))
3759 rows = atoi((char *)p);
3760 if ((p = (char_u *)getenv("COLUMNS")))
3761 columns = atoi((char *)p);
3762 }
3763
3764#ifdef HAVE_TGETENT
3765 /*
3766 * 3. try reading "co" and "li" entries from termcap
3767 */
3768 if (columns == 0 || rows == 0)
3769 getlinecol(&columns, &rows);
3770#endif
3771
3772 /*
3773 * 4. If everything fails, use the old values
3774 */
3775 if (columns <= 0 || rows <= 0)
3776 return FAIL;
3777
3778 Rows = rows;
3779 Columns = columns;
3780 return OK;
3781}
3782
3783/*
3784 * Try to set the window size to Rows and Columns.
3785 */
3786 void
3787mch_set_shellsize()
3788{
3789 if (*T_CWS)
3790 {
3791 /*
3792 * NOTE: if you get an error here that term_set_winsize() is
3793 * undefined, check the output of configure. It could probably not
3794 * find a ncurses, termcap or termlib library.
3795 */
3796 term_set_winsize((int)Rows, (int)Columns);
3797 out_flush();
3798 screen_start(); /* don't know where cursor is now */
3799 }
3800}
3801
3802#endif /* VMS */
3803
3804/*
3805 * Rows and/or Columns has changed.
3806 */
3807 void
3808mch_new_shellsize()
3809{
3810 /* Nothing to do. */
3811}
3812
Bram Moolenaar205b8862011-09-07 15:04:31 +02003813/*
3814 * Wait for process "child" to end.
3815 * Return "child" if it exited properly, <= 0 on error.
3816 */
3817 static pid_t
3818wait4pid(child, status)
3819 pid_t child;
3820 waitstatus *status;
3821{
3822 pid_t wait_pid = 0;
3823
3824 while (wait_pid != child)
3825 {
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003826 /* When compiled with Python threads are probably used, in which case
3827 * wait() sometimes hangs for no obvious reason. Use waitpid()
3828 * instead and loop (like the GUI). Also needed for other interfaces,
3829 * they might call system(). */
3830# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02003831 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003832# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02003833 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003834# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02003835 if (wait_pid == 0)
3836 {
Bram Moolenaar75676462013-01-30 14:55:42 +01003837 /* Wait for 10 msec before trying again. */
Bram Moolenaar205b8862011-09-07 15:04:31 +02003838 mch_delay(10L, TRUE);
3839 continue;
3840 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02003841 if (wait_pid <= 0
3842# ifdef ECHILD
3843 && errno == ECHILD
3844# endif
3845 )
3846 break;
3847 }
3848 return wait_pid;
3849}
3850
Bram Moolenaar071d4272004-06-13 20:20:40 +00003851 int
3852mch_call_shell(cmd, options)
3853 char_u *cmd;
3854 int options; /* SHELL_*, see vim.h */
3855{
3856#ifdef VMS
3857 char *ifn = NULL;
3858 char *ofn = NULL;
3859#endif
3860 int tmode = cur_tmode;
3861#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3862 int x;
3863# ifndef __EMX__
3864 char_u *newcmd; /* only needed for unix */
3865# else
3866 /*
3867 * Set the preferred shell in the EMXSHELL environment variable (but
3868 * only if it is different from what is already in the environment).
3869 * Emx then takes care of whether to use "/c" or "-c" in an
3870 * intelligent way. Simply pass the whole thing to emx's system() call.
3871 * Emx also starts an interactive shell if system() is passed an empty
3872 * string.
3873 */
3874 char_u *p, *old;
3875
3876 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3877 {
3878 /* should check HAVE_SETENV, but I know we don't have it. */
3879 p = alloc(10 + strlen(p_sh));
3880 if (p)
3881 {
3882 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3883 putenv((char *)p); /* don't free the pointer! */
3884 }
3885 }
3886# endif
3887
3888 out_flush();
3889
3890 if (options & SHELL_COOKED)
3891 settmode(TMODE_COOK); /* set to normal mode */
3892
Bram Moolenaar62b42182010-09-21 22:09:37 +02003893# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01003894 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02003895 loose_clipboard();
3896# endif
3897
Bram Moolenaar071d4272004-06-13 20:20:40 +00003898# ifdef __EMX__
3899 if (cmd == NULL)
3900 x = system(""); /* this starts an interactive shell in emx */
3901 else
3902 x = system((char *)cmd);
3903 /* system() returns -1 when error occurs in starting shell */
3904 if (x == -1 && !emsg_silent)
3905 {
3906 MSG_PUTS(_("\nCannot execute shell "));
3907 msg_outtrans(p_sh);
3908 msg_putchar('\n');
3909 }
3910# else /* not __EMX__ */
3911 if (cmd == NULL)
3912 x = system((char *)p_sh);
3913 else
3914 {
3915# ifdef VMS
3916 if (ofn = strchr((char *)cmd, '>'))
3917 *ofn++ = '\0';
3918 if (ifn = strchr((char *)cmd, '<'))
3919 {
3920 char *p;
3921
3922 *ifn++ = '\0';
3923 p = strchr(ifn,' '); /* chop off any trailing spaces */
3924 if (p)
3925 *p = '\0';
3926 }
3927 if (ofn)
3928 x = vms_sys((char *)cmd, ofn, ifn);
3929 else
3930 x = system((char *)cmd);
3931# else
3932 newcmd = lalloc(STRLEN(p_sh)
3933 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3934 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3935 if (newcmd == NULL)
3936 x = 0;
3937 else
3938 {
3939 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3940 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3941 (char *)p_shcf,
3942 (char *)cmd);
3943 x = system((char *)newcmd);
3944 vim_free(newcmd);
3945 }
3946# endif
3947 }
3948# ifdef VMS
3949 x = vms_sys_status(x);
3950# endif
3951 if (emsg_silent)
3952 ;
3953 else if (x == 127)
3954 MSG_PUTS(_("\nCannot execute shell sh\n"));
3955# endif /* __EMX__ */
3956 else if (x && !(options & SHELL_SILENT))
3957 {
3958 MSG_PUTS(_("\nshell returned "));
3959 msg_outnum((long)x);
3960 msg_putchar('\n');
3961 }
3962
3963 if (tmode == TMODE_RAW)
3964 settmode(TMODE_RAW); /* set to raw mode */
3965# ifdef FEAT_TITLE
3966 resettitle();
3967# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01003968# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3969 restore_clipboard();
3970# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003971 return x;
3972
3973#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3974
Bram Moolenaardf177f62005-02-22 08:39:57 +00003975# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3976 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003977
3978 char_u *newcmd = NULL;
3979 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003980 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003981 pid_t wait_pid = 0;
3982# ifdef HAVE_UNION_WAIT
3983 union wait status;
3984# else
3985 int status = -1;
3986# endif
3987 int retval = -1;
3988 char **argv = NULL;
3989 int argc;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02003990 char_u *p_shcf_copy = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003991 int i;
3992 char_u *p;
3993 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003995# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003996 int pty_slave_fd = -1;
3997 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003998# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003999 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004000 int fd_fromshell[2];
4001 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004002# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004003 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004004# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004005 static char envbuf_Rows[20];
4006 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004007# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004008 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004009
Bram Moolenaar62b42182010-09-21 22:09:37 +02004010 newcmd = vim_strsave(p_sh);
4011 if (newcmd == NULL) /* out of memory */
4012 goto error;
4013
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014 out_flush();
4015 if (options & SHELL_COOKED)
4016 settmode(TMODE_COOK); /* set to normal mode */
4017
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004018 /*
4019 * Do this loop twice:
4020 * 1: find number of arguments
4021 * 2: separate them and build argv[]
4022 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023 for (i = 0; i < 2; ++i)
4024 {
4025 p = newcmd;
4026 inquote = FALSE;
4027 argc = 0;
4028 for (;;)
4029 {
4030 if (i == 1)
4031 argv[argc] = (char *)p;
4032 ++argc;
4033 while (*p && (inquote || (*p != ' ' && *p != TAB)))
4034 {
4035 if (*p == '"')
4036 inquote = !inquote;
4037 ++p;
4038 }
4039 if (*p == NUL)
4040 break;
4041 if (i == 1)
4042 *p++ = NUL;
4043 p = skipwhite(p);
4044 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00004045 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004046 {
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004047 /*
4048 * Account for possible multiple args in p_shcf.
4049 */
4050 p = p_shcf;
4051 for (;;)
4052 {
4053 p = skiptowhite(p);
4054 if (*p == NUL)
4055 break;
4056 ++argc;
4057 p = skipwhite(p);
4058 }
4059
Bram Moolenaar071d4272004-06-13 20:20:40 +00004060 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
4061 if (argv == NULL) /* out of memory */
4062 goto error;
4063 }
4064 }
4065 if (cmd != NULL)
4066 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004067 char_u *s;
4068
Bram Moolenaar071d4272004-06-13 20:20:40 +00004069 if (extra_shell_arg != NULL)
4070 argv[argc++] = (char *)extra_shell_arg;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004071
4072 /* Break 'shellcmdflag' into white separated parts. This doesn't
4073 * handle quoted strings, they are very unlikely to appear. */
4074 p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
4075 if (p_shcf_copy == NULL) /* out of memory */
4076 goto error;
4077 s = p_shcf_copy;
4078 p = p_shcf;
4079 while (*p != NUL)
4080 {
4081 argv[argc++] = (char *)s;
4082 while (*p && *p != ' ' && *p != TAB)
4083 *s++ = *p++;
4084 *s++ = NUL;
4085 p = skipwhite(p);
4086 }
4087
Bram Moolenaar071d4272004-06-13 20:20:40 +00004088 argv[argc++] = (char *)cmd;
4089 }
4090 argv[argc] = NULL;
4091
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004093 * For the GUI, when writing the output into the buffer and when reading
4094 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4095 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004097 if ((options & (SHELL_READ|SHELL_WRITE))
4098# ifdef FEAT_GUI
4099 || (gui.in_use && show_shell_mess)
4100# endif
4101 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004102 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004103# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104 /*
4105 * Try to open a master pty.
4106 * If this works, open the slave pty.
4107 * If the slave can't be opened, close the master pty.
4108 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004109 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004110 {
4111 pty_master_fd = OpenPTY(&tty_name); /* open pty */
Bram Moolenaare70172e2011-08-04 19:36:52 +02004112 if (pty_master_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004113 {
Bram Moolenaare70172e2011-08-04 19:36:52 +02004114 /* Leaving out O_NOCTTY may lead to waitpid() always returning
4115 * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4116 * adding O_NOCTTY always works when defined. */
4117#ifdef O_NOCTTY
4118 pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4119#else
4120 pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4121#endif
4122 if (pty_slave_fd < 0)
4123 {
4124 close(pty_master_fd);
4125 pty_master_fd = -1;
4126 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004127 }
4128 }
4129 /*
4130 * If not opening a pty or it didn't work, try using pipes.
4131 */
4132 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004133# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004134 {
4135 pipe_error = (pipe(fd_toshell) < 0);
4136 if (!pipe_error) /* pipe create OK */
4137 {
4138 pipe_error = (pipe(fd_fromshell) < 0);
4139 if (pipe_error) /* pipe create failed */
4140 {
4141 close(fd_toshell[0]);
4142 close(fd_toshell[1]);
4143 }
4144 }
4145 if (pipe_error)
4146 {
4147 MSG_PUTS(_("\nCannot create pipes\n"));
4148 out_flush();
4149 }
4150 }
4151 }
4152
4153 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 {
4155# ifdef __BEOS__
4156 beos_cleanup_read_thread();
4157# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004158
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159 if ((pid = fork()) == -1) /* maybe we should use vfork() */
4160 {
4161 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004162 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004164 || (gui.in_use && show_shell_mess)
4165# endif
4166 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004168# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169 if (pty_master_fd >= 0) /* close the pseudo tty */
4170 {
4171 close(pty_master_fd);
4172 close(pty_slave_fd);
4173 }
4174 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004175# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176 {
4177 close(fd_toshell[0]);
4178 close(fd_toshell[1]);
4179 close(fd_fromshell[0]);
4180 close(fd_fromshell[1]);
4181 }
4182 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004183 }
4184 else if (pid == 0) /* child */
4185 {
4186 reset_signals(); /* handle signals normally */
4187
4188 if (!show_shell_mess || (options & SHELL_EXPAND))
4189 {
4190 int fd;
4191
4192 /*
4193 * Don't want to show any message from the shell. Can't just
4194 * close stdout and stderr though, because some systems will
4195 * break if you try to write to them after that, so we must
4196 * use dup() to replace them with something else -- webb
4197 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4198 * waiting for input.
4199 */
4200 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4201 fclose(stdin);
4202 fclose(stdout);
4203 fclose(stderr);
4204
4205 /*
4206 * If any of these open()'s and dup()'s fail, we just continue
4207 * anyway. It's not fatal, and on most systems it will make
4208 * no difference at all. On a few it will cause the execvp()
4209 * to exit with a non-zero status even when the completion
4210 * could be done, which is nothing too serious. If the open()
4211 * or dup() failed we'd just do the same thing ourselves
4212 * anyway -- webb
4213 */
4214 if (fd >= 0)
4215 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004216 ignored = dup(fd); /* To replace stdin (fd 0) */
4217 ignored = dup(fd); /* To replace stdout (fd 1) */
4218 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219
4220 /* Don't need this now that we've duplicated it */
4221 close(fd);
4222 }
4223 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004224 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004225# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004226 || gui.in_use
4227# endif
4228 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229 {
4230
Bram Moolenaardf177f62005-02-22 08:39:57 +00004231# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004232 /* Create our own process group, so that the child and all its
4233 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004234 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004235 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004236 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004237 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004238# if defined(SIGHUP)
4239 /* When doing "!xterm&" and 'shell' is bash: the shell
4240 * will exit and send SIGHUP to all processes in its
4241 * group, killing the just started process. Ignore SIGHUP
4242 * to avoid that. (suggested by Simon Schubert)
4243 */
4244 signal(SIGHUP, SIG_IGN);
4245# endif
4246 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004247# endif
4248# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004249 if (pty_slave_fd >= 0)
4250 {
4251 /* push stream discipline modules */
4252 if (options & SHELL_COOKED)
4253 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004254# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004255 /* Try to become controlling tty (probably doesn't work,
4256 * unless run by root) */
4257 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004258# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004259 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004260# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004262# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263 setenv("TERM", "dumb", 1);
4264 sprintf((char *)envbuf, "%ld", Rows);
4265 setenv("ROWS", (char *)envbuf, 1);
4266 sprintf((char *)envbuf, "%ld", Rows);
4267 setenv("LINES", (char *)envbuf, 1);
4268 sprintf((char *)envbuf, "%ld", Columns);
4269 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004270# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271 /*
4272 * Putenv does not copy the string, it has to remain valid.
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004273 * Use a static array to avoid losing allocated memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004274 */
4275 putenv("TERM=dumb");
4276 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
4277 putenv(envbuf_Rows);
4278 sprintf(envbuf_Rows, "LINES=%ld", Rows);
4279 putenv(envbuf_Rows);
4280 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
4281 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004282# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004283
Bram Moolenaara5792f52005-11-23 21:25:05 +00004284 /*
4285 * stderr is only redirected when using the GUI, so that a
4286 * program like gpg can still access the terminal to get a
4287 * passphrase using stderr.
4288 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004289# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004290 if (pty_master_fd >= 0)
4291 {
4292 close(pty_master_fd); /* close master side of pty */
4293
4294 /* set up stdin/stdout/stderr for the child */
4295 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004296 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004297 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004298 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004299 if (gui.in_use)
4300 {
4301 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004302 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004303 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004304
4305 close(pty_slave_fd); /* has been dupped, close it now */
4306 }
4307 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004308# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309 {
4310 /* set up stdin for the child */
4311 close(fd_toshell[1]);
4312 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004313 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314 close(fd_toshell[0]);
4315
4316 /* set up stdout for the child */
4317 close(fd_fromshell[0]);
4318 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004319 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320 close(fd_fromshell[1]);
4321
Bram Moolenaara5792f52005-11-23 21:25:05 +00004322# ifdef FEAT_GUI
4323 if (gui.in_use)
4324 {
4325 /* set up stderr for the child */
4326 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004327 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004328 }
4329# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004330 }
4331 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004332
Bram Moolenaar071d4272004-06-13 20:20:40 +00004333 /*
4334 * There is no type cast for the argv, because the type may be
4335 * different on different machines. This may cause a warning
4336 * message with strict compilers, don't worry about it.
4337 * Call _exit() instead of exit() to avoid closing the connection
4338 * to the X server (esp. with GTK, which uses atexit()).
4339 */
4340 execvp(argv[0], argv);
4341 _exit(EXEC_FAILED); /* exec failed, return failure code */
4342 }
4343 else /* parent */
4344 {
4345 /*
4346 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004347 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004348 */
4349 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004350 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004351
4352 /*
4353 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004354 * This is also used to pipe stdin/stdout to/from the external
4355 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004356 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004357 if ((options & (SHELL_READ|SHELL_WRITE))
4358# ifdef FEAT_GUI
4359 || (gui.in_use && show_shell_mess)
4360# endif
4361 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004362 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004363# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004364 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004365# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004366 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004367# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004368 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4369 int ta_len = 0; /* valid bytes in ta_buf[] */
4370 int len;
4371 int p_more_save;
4372 int old_State;
4373 int c;
4374 int toshell_fd;
4375 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004376 garray_T ga;
4377 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004378# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4379 struct timeval start_tv;
4380# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004381
Bram Moolenaardf177f62005-02-22 08:39:57 +00004382# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004383 if (pty_master_fd >= 0)
4384 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004385 fromshell_fd = pty_master_fd;
4386 toshell_fd = dup(pty_master_fd);
4387 }
4388 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004389# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004390 {
4391 close(fd_toshell[0]);
4392 close(fd_fromshell[1]);
4393 toshell_fd = fd_toshell[1];
4394 fromshell_fd = fd_fromshell[0];
4395 }
4396
4397 /*
4398 * Write to the child if there are typed characters.
4399 * Read from the child if there are characters available.
4400 * Repeat the reading a few times if more characters are
4401 * available. Need to check for typed keys now and then, but
4402 * not too often (delays when no chars are available).
4403 * This loop is quit if no characters can be read from the pty
4404 * (WaitForChar detected special condition), or there are no
4405 * characters available and the child has exited.
4406 * Only check if the child has exited when there is no more
4407 * output. The child may exit before all the output has
4408 * been printed.
4409 *
4410 * Currently this busy loops!
4411 * This can probably dead-lock when the write blocks!
4412 */
4413 p_more_save = p_more;
4414 p_more = FALSE;
4415 old_State = State;
4416 State = EXTERNCMD; /* don't redraw at window resize */
4417
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004418 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004419 {
4420 /* Fork a process that will write the lines to the
4421 * external program. */
4422 if ((wpid = fork()) == -1)
4423 {
4424 MSG_PUTS(_("\nCannot fork\n"));
4425 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004426 else if (wpid == 0) /* child */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004427 {
4428 linenr_T lnum = curbuf->b_op_start.lnum;
4429 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004430 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004431 size_t l;
4432
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004433 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004434 for (;;)
4435 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004436 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004437 if (l == 0)
4438 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004439 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004440 /* NL -> NUL translation */
4441 len = write(toshell_fd, "", (size_t)1);
4442 else
4443 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004444 char_u *s = vim_strchr(lp + written, NL);
4445
Bram Moolenaar89d40322006-08-29 15:30:07 +00004446 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004447 s == NULL ? l
4448 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004449 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004450 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004451 {
4452 /* Finished a line, add a NL, unless this line
4453 * should not have one. */
4454 if (lnum != curbuf->b_op_end.lnum
4455 || !curbuf->b_p_bin
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004456 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004457 && (lnum !=
4458 curbuf->b_ml.ml_line_count
4459 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004460 ignored = write(toshell_fd, "\n",
4461 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004462 ++lnum;
4463 if (lnum > curbuf->b_op_end.lnum)
4464 {
4465 /* finished all the lines, close pipe */
4466 close(toshell_fd);
4467 toshell_fd = -1;
4468 break;
4469 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004470 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004471 written = 0;
4472 }
4473 else if (len > 0)
4474 written += len;
4475 }
4476 _exit(0);
4477 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004478 else /* parent */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004479 {
4480 close(toshell_fd);
4481 toshell_fd = -1;
4482 }
4483 }
4484
4485 if (options & SHELL_READ)
4486 ga_init2(&ga, 1, BUFLEN);
4487
4488 noread_cnt = 0;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004489# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4490 gettimeofday(&start_tv, NULL);
4491# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004492 for (;;)
4493 {
4494 /*
4495 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004496 * if there are any.
4497 * Don't do this if we are expanding wild cards (would eat
4498 * typeahead).
4499 * Don't do this when filtering and terminal is in cooked
4500 * mode, the shell command will handle the I/O. Avoids
4501 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004502 * Don't get characters when the child has already
4503 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004504 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004505 * while (noread_cnt > 4), avoids that ":r !ls" eats
4506 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507 */
4508 len = 0;
4509 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004510 && ((options &
4511 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4512 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004513# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004514 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004515# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004516 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004517 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004518 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004519 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004520 if (ta_len == 0)
4521 {
4522 /* Get extra characters when we don't have any.
4523 * Reset the counter and timer. */
4524 noread_cnt = 0;
4525# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4526 gettimeofday(&start_tv, NULL);
4527# endif
4528 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4529 }
4530 if (ta_len > 0 || len > 0)
4531 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532 /*
4533 * For pipes:
4534 * Check for CTRL-C: send interrupt signal to child.
4535 * Check for CTRL-D: EOF, close pipe to child.
4536 */
4537 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4538 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004539# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540 /*
4541 * Send SIGINT to the child's group or all
4542 * processes in our group.
4543 */
4544 if (ta_buf[ta_len] == Ctrl_C
4545 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004546 {
4547# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004548 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004549# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004550 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004552 if (wpid > 0)
4553 kill(wpid, SIGINT);
4554 }
4555# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556 if (pty_master_fd < 0 && toshell_fd >= 0
4557 && ta_buf[ta_len] == Ctrl_D)
4558 {
4559 close(toshell_fd);
4560 toshell_fd = -1;
4561 }
4562 }
4563
4564 /* replace K_BS by <BS> and K_DEL by <DEL> */
4565 for (i = ta_len; i < ta_len + len; ++i)
4566 {
4567 if (ta_buf[i] == CSI && len - i > 2)
4568 {
4569 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4570 if (c == K_DEL || c == K_KDEL || c == K_BS)
4571 {
4572 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4573 (size_t)(len - i - 2));
4574 if (c == K_DEL || c == K_KDEL)
4575 ta_buf[i] = DEL;
4576 else
4577 ta_buf[i] = Ctrl_H;
4578 len -= 2;
4579 }
4580 }
4581 else if (ta_buf[i] == '\r')
4582 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004583# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00004585 i += (*mb_ptr2len_len)(ta_buf + i,
4586 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004587# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004588 }
4589
4590 /*
4591 * For pipes: echo the typed characters.
4592 * For a pty this does not seem to work.
4593 */
4594 if (pty_master_fd < 0)
4595 {
4596 for (i = ta_len; i < ta_len + len; ++i)
4597 {
4598 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4599 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004600# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004601 else if (has_mbyte)
4602 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004603 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604
4605 msg_outtrans_len(ta_buf + i, l);
4606 i += l - 1;
4607 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004608# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004609 else
4610 msg_outtrans_len(ta_buf + i, 1);
4611 }
4612 windgoto(msg_row, msg_col);
4613 out_flush();
4614 }
4615
4616 ta_len += len;
4617
4618 /*
4619 * Write the characters to the child, unless EOF has
4620 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004621 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004622 * When writing buffer lines, drop the typed
4623 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004624 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004625 if (options & SHELL_WRITE)
4626 ta_len = 0;
4627 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004628 {
4629 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4630 if (len > 0)
4631 {
4632 ta_len -= len;
4633 mch_memmove(ta_buf, ta_buf + len, ta_len);
4634 }
4635 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004636 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004637 }
4638
Bram Moolenaardf177f62005-02-22 08:39:57 +00004639 if (got_int)
4640 {
4641 /* CTRL-C sends a signal to the child, we ignore it
4642 * ourselves */
4643# ifdef HAVE_SETSID
4644 kill(-pid, SIGINT);
4645# else
4646 kill(0, SIGINT);
4647# endif
4648 if (wpid > 0)
4649 kill(wpid, SIGINT);
4650 got_int = FALSE;
4651 }
4652
Bram Moolenaar071d4272004-06-13 20:20:40 +00004653 /*
4654 * Check if the child has any characters to be printed.
4655 * Read them and write them to our window. Repeat this as
4656 * long as there is something to do, avoid the 10ms wait
4657 * for mch_inchar(), or sending typeahead characters to
4658 * the external process.
4659 * TODO: This should handle escape sequences, compatible
4660 * to some terminal (vt52?).
4661 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004662 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004663 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4664 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004665 len = read_eintr(fromshell_fd, buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004666# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004667 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004668# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004669 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004670# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004671 );
4672 if (len <= 0) /* end of file or error */
4673 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004674
4675 noread_cnt = 0;
4676 if (options & SHELL_READ)
4677 {
4678 /* Do NUL -> NL translation, append NL separated
4679 * lines to the current buffer. */
4680 for (i = 0; i < len; ++i)
4681 {
4682 if (buffer[i] == NL)
4683 append_ga_line(&ga);
4684 else if (buffer[i] == NUL)
4685 ga_append(&ga, NL);
4686 else
4687 ga_append(&ga, buffer[i]);
4688 }
4689 }
4690# ifdef FEAT_MBYTE
4691 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004692 {
4693 int l;
4694
Bram Moolenaardf177f62005-02-22 08:39:57 +00004695 len += buffer_off;
4696 buffer[len] = NUL;
4697
Bram Moolenaar071d4272004-06-13 20:20:40 +00004698 /* Check if the last character in buffer[] is
4699 * incomplete, keep these bytes for the next
4700 * round. */
4701 for (p = buffer; p < buffer + len; p += l)
4702 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004703 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004704 if (l == 0)
4705 l = 1; /* NUL byte? */
4706 else if (MB_BYTE2LEN(*p) != l)
4707 break;
4708 }
4709 if (p == buffer) /* no complete character */
4710 {
4711 /* avoid getting stuck at an illegal byte */
4712 if (len >= 12)
4713 ++p;
4714 else
4715 {
4716 buffer_off = len;
4717 continue;
4718 }
4719 }
4720 c = *p;
4721 *p = NUL;
4722 msg_puts(buffer);
4723 if (p < buffer + len)
4724 {
4725 *p = c;
4726 buffer_off = (buffer + len) - p;
4727 mch_memmove(buffer, p, buffer_off);
4728 continue;
4729 }
4730 buffer_off = 0;
4731 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004732# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004733 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004734 {
4735 buffer[len] = NUL;
4736 msg_puts(buffer);
4737 }
4738
4739 windgoto(msg_row, msg_col);
4740 cursor_on();
4741 out_flush();
4742 if (got_int)
4743 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004744
4745# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4746 {
4747 struct timeval now_tv;
4748 long msec;
4749
4750 /* Avoid that we keep looping here without
4751 * checking for a CTRL-C for a long time. Don't
4752 * break out too often to avoid losing typeahead. */
4753 gettimeofday(&now_tv, NULL);
4754 msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
4755 + (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
4756 if (msec > 2000)
4757 {
4758 noread_cnt = 5;
4759 break;
4760 }
4761 }
4762# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004763 }
4764
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004765 /* If we already detected the child has finished break the
4766 * loop now. */
4767 if (wait_pid == pid)
4768 break;
4769
Bram Moolenaar071d4272004-06-13 20:20:40 +00004770 /*
4771 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004772 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004773 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004774# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004775 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004776# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004777 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004778# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4780 || (wait_pid == pid && WIFEXITED(status)))
4781 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004782 /* Don't break the loop yet, try reading more
4783 * characters from "fromshell_fd" first. When using
4784 * pipes there might still be something to read and
4785 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004787 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004788 else
4789 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004790
Bram Moolenaar95a51352013-03-21 22:53:50 +01004791# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004792 /* Handle any X events, e.g. serving the clipboard. */
4793 clip_update();
4794# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004795 }
4796finished:
4797 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004798 if (options & SHELL_READ)
4799 {
4800 if (ga.ga_len > 0)
4801 {
4802 append_ga_line(&ga);
4803 /* remember that the NL was missing */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004804 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004805 }
4806 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004807 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004808 ga_clear(&ga);
4809 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004810
Bram Moolenaar071d4272004-06-13 20:20:40 +00004811 /*
4812 * Give all typeahead that wasn't used back to ui_inchar().
4813 */
4814 if (ta_len)
4815 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004816 State = old_State;
4817 if (toshell_fd >= 0)
4818 close(toshell_fd);
4819 close(fromshell_fd);
4820 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01004821# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004822 else
4823 {
4824 /*
4825 * Similar to the loop above, but only handle X events, no
4826 * I/O.
4827 */
4828 for (;;)
4829 {
4830 if (got_int)
4831 {
4832 /* CTRL-C sends a signal to the child, we ignore it
4833 * ourselves */
4834# ifdef HAVE_SETSID
4835 kill(-pid, SIGINT);
4836# else
4837 kill(0, SIGINT);
4838# endif
4839 got_int = FALSE;
4840 }
4841# ifdef __NeXT__
4842 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4843# else
4844 wait_pid = waitpid(pid, &status, WNOHANG);
4845# endif
4846 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4847 || (wait_pid == pid && WIFEXITED(status)))
4848 {
4849 wait_pid = pid;
4850 break;
4851 }
4852
4853 /* Handle any X events, e.g. serving the clipboard. */
4854 clip_update();
4855
4856 mch_delay(10L, TRUE);
4857 }
4858 }
4859# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004860
4861 /*
4862 * Wait until our child has exited.
4863 * Ignore wait() returning pids of other children and returning
4864 * because of some signal like SIGWINCH.
4865 * Don't wait if wait_pid was already set above, indicating the
4866 * child already exited.
4867 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02004868 if (wait_pid != pid)
4869 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004870
Bram Moolenaar624891f2010-10-13 16:22:09 +02004871# ifdef FEAT_GUI
4872 /* Close slave side of pty. Only do this after the child has
4873 * exited, otherwise the child may hang when it tries to write on
4874 * the pty. */
4875 if (pty_master_fd >= 0)
4876 close(pty_slave_fd);
4877# endif
4878
Bram Moolenaardf177f62005-02-22 08:39:57 +00004879 /* Make sure the child that writes to the external program is
4880 * dead. */
4881 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004882 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004883 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02004884 wait4pid(wpid, NULL);
4885 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004886
Bram Moolenaar071d4272004-06-13 20:20:40 +00004887 /*
4888 * Set to raw mode right now, otherwise a CTRL-C after
4889 * catch_signals() will kill Vim.
4890 */
4891 if (tmode == TMODE_RAW)
4892 settmode(TMODE_RAW);
4893 did_settmode = TRUE;
4894 set_signals();
4895
4896 if (WIFEXITED(status))
4897 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004898 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004899 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01004900 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901 {
4902 if (retval == EXEC_FAILED)
4903 {
4904 MSG_PUTS(_("\nCannot execute shell "));
4905 msg_outtrans(p_sh);
4906 msg_putchar('\n');
4907 }
4908 else if (!(options & SHELL_SILENT))
4909 {
4910 MSG_PUTS(_("\nshell returned "));
4911 msg_outnum((long)retval);
4912 msg_putchar('\n');
4913 }
4914 }
4915 }
4916 else
4917 MSG_PUTS(_("\nCommand terminated\n"));
4918 }
4919 }
4920 vim_free(argv);
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004921 vim_free(p_shcf_copy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004922
4923error:
4924 if (!did_settmode)
4925 if (tmode == TMODE_RAW)
4926 settmode(TMODE_RAW); /* set to raw mode */
4927# ifdef FEAT_TITLE
4928 resettitle();
4929# endif
4930 vim_free(newcmd);
4931
4932 return retval;
4933
4934#endif /* USE_SYSTEM */
4935}
4936
4937/*
4938 * Check for CTRL-C typed by reading all available characters.
4939 * In cooked mode we should get SIGINT, no need to check.
4940 */
4941 void
4942mch_breakcheck()
4943{
4944 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4945 fill_input_buf(FALSE);
4946}
4947
4948/*
4949 * Wait "msec" msec until a character is available from the keyboard or from
4950 * inbuf[]. msec == -1 will block forever.
4951 * When a GUI is being used, this will never get called -- webb
4952 */
4953 static int
4954WaitForChar(msec)
4955 long msec;
4956{
4957#ifdef FEAT_MOUSE_GPM
4958 int gpm_process_wanted;
4959#endif
4960#ifdef FEAT_XCLIPBOARD
4961 int rest;
4962#endif
4963 int avail;
4964
4965 if (input_available()) /* something in inbuf[] */
4966 return 1;
4967
4968#if defined(FEAT_MOUSE_DEC)
4969 /* May need to query the mouse position. */
4970 if (WantQueryMouse)
4971 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004972 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004973 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4974 }
4975#endif
4976
4977 /*
4978 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4979 * events. This is a bit complicated, because they might both be defined.
4980 */
4981#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4982# ifdef FEAT_XCLIPBOARD
4983 rest = 0;
4984 if (do_xterm_trace())
4985 rest = msec;
4986# endif
4987 do
4988 {
4989# ifdef FEAT_XCLIPBOARD
4990 if (rest != 0)
4991 {
4992 msec = XT_TRACE_DELAY;
4993 if (rest >= 0 && rest < XT_TRACE_DELAY)
4994 msec = rest;
4995 if (rest >= 0)
4996 rest -= msec;
4997 }
4998# endif
4999# ifdef FEAT_MOUSE_GPM
5000 gpm_process_wanted = 0;
5001 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
5002# else
5003 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
5004# endif
5005 if (!avail)
5006 {
5007 if (input_available())
5008 return 1;
5009# ifdef FEAT_XCLIPBOARD
5010 if (rest == 0 || !do_xterm_trace())
5011# endif
5012 break;
5013 }
5014 }
5015 while (FALSE
5016# ifdef FEAT_MOUSE_GPM
5017 || (gpm_process_wanted && mch_gpm_process() == 0)
5018# endif
5019# ifdef FEAT_XCLIPBOARD
5020 || (!avail && rest != 0)
5021# endif
5022 );
5023
5024#else
5025 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
5026#endif
5027 return avail;
5028}
5029
5030/*
5031 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005032 * "msec" == 0 will check for characters once.
5033 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005034 * When a GUI is being used, this will not be used for input -- webb
5035 * Returns also, when a request from Sniff is waiting -- toni.
5036 * Or when a Linux GPM mouse event is waiting.
5037 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005038#if defined(__BEOS__)
5039 int
5040#else
5041 static int
5042#endif
5043RealWaitForChar(fd, msec, check_for_gpm)
5044 int fd;
5045 long msec;
Bram Moolenaar78a15312009-05-15 19:33:18 +00005046 int *check_for_gpm UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005047{
5048 int ret;
Bram Moolenaar67c53842010-05-22 18:28:27 +02005049#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02005050 int nb_fd = netbeans_filedesc();
Bram Moolenaar67c53842010-05-22 18:28:27 +02005051#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005052#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005053 static int busy = FALSE;
5054
5055 /* May retry getting characters after an event was handled. */
5056# define MAY_LOOP
5057
5058# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5059 /* Remember at what time we started, so that we know how much longer we
5060 * should wait after being interrupted. */
5061# define USE_START_TV
5062 struct timeval start_tv;
5063
5064 if (msec > 0 && (
5065# ifdef FEAT_XCLIPBOARD
5066 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005067# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005068 ||
5069# endif
5070# endif
5071# ifdef USE_XSMP
5072 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005073# ifdef FEAT_MZSCHEME
5074 ||
5075# endif
5076# endif
5077# ifdef FEAT_MZSCHEME
5078 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005079# endif
5080 ))
5081 gettimeofday(&start_tv, NULL);
5082# endif
5083
5084 /* Handle being called recursively. This may happen for the session
5085 * manager stuff, it may save the file, which does a breakcheck. */
5086 if (busy)
5087 return 0;
5088#endif
5089
5090#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00005091 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005092#endif
5093 {
5094#ifdef MAY_LOOP
5095 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005096# ifdef FEAT_MZSCHEME
5097 int mzquantum_used = FALSE;
5098# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005099#endif
5100#ifndef HAVE_SELECT
Bram Moolenaar67c53842010-05-22 18:28:27 +02005101 struct pollfd fds[6];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005102 int nfd;
5103# ifdef FEAT_XCLIPBOARD
5104 int xterm_idx = -1;
5105# endif
5106# ifdef FEAT_MOUSE_GPM
5107 int gpm_idx = -1;
5108# endif
5109# ifdef USE_XSMP
5110 int xsmp_idx = -1;
5111# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005112# ifdef FEAT_NETBEANS_INTG
5113 int nb_idx = -1;
5114# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005115 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005116
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005117# ifdef FEAT_MZSCHEME
5118 mzvim_check_threads();
5119 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5120 {
5121 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
5122 mzquantum_used = TRUE;
5123 }
5124# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005125 fds[0].fd = fd;
5126 fds[0].events = POLLIN;
5127 nfd = 1;
5128
5129# ifdef FEAT_SNIFF
5130# define SNIFF_IDX 1
5131 if (want_sniff_request)
5132 {
5133 fds[SNIFF_IDX].fd = fd_from_sniff;
5134 fds[SNIFF_IDX].events = POLLIN;
5135 nfd++;
5136 }
5137# endif
5138# ifdef FEAT_XCLIPBOARD
5139 if (xterm_Shell != (Widget)0)
5140 {
5141 xterm_idx = nfd;
5142 fds[nfd].fd = ConnectionNumber(xterm_dpy);
5143 fds[nfd].events = POLLIN;
5144 nfd++;
5145 }
5146# endif
5147# ifdef FEAT_MOUSE_GPM
5148 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5149 {
5150 gpm_idx = nfd;
5151 fds[nfd].fd = gpm_fd;
5152 fds[nfd].events = POLLIN;
5153 nfd++;
5154 }
5155# endif
5156# ifdef USE_XSMP
5157 if (xsmp_icefd != -1)
5158 {
5159 xsmp_idx = nfd;
5160 fds[nfd].fd = xsmp_icefd;
5161 fds[nfd].events = POLLIN;
5162 nfd++;
5163 }
5164# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005165#ifdef FEAT_NETBEANS_INTG
5166 if (nb_fd != -1)
5167 {
5168 nb_idx = nfd;
5169 fds[nfd].fd = nb_fd;
5170 fds[nfd].events = POLLIN;
5171 nfd++;
5172 }
5173#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005174
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005175 ret = poll(fds, nfd, towait);
5176# ifdef FEAT_MZSCHEME
5177 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005178 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005179 finished = FALSE;
5180# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005181
5182# ifdef FEAT_SNIFF
5183 if (ret < 0)
5184 sniff_disconnect(1);
5185 else if (want_sniff_request)
5186 {
5187 if (fds[SNIFF_IDX].revents & POLLHUP)
5188 sniff_disconnect(1);
5189 if (fds[SNIFF_IDX].revents & POLLIN)
5190 sniff_request_waiting = 1;
5191 }
5192# endif
5193# ifdef FEAT_XCLIPBOARD
5194 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
5195 {
5196 xterm_update(); /* Maybe we should hand out clipboard */
5197 if (--ret == 0 && !input_available())
5198 /* Try again */
5199 finished = FALSE;
5200 }
5201# endif
5202# ifdef FEAT_MOUSE_GPM
5203 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
5204 {
5205 *check_for_gpm = 1;
5206 }
5207# endif
5208# ifdef USE_XSMP
5209 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
5210 {
5211 if (fds[xsmp_idx].revents & POLLIN)
5212 {
5213 busy = TRUE;
5214 xsmp_handle_requests();
5215 busy = FALSE;
5216 }
5217 else if (fds[xsmp_idx].revents & POLLHUP)
5218 {
5219 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005220 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005221 xsmp_close();
5222 }
5223 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005224 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005225 }
5226# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005227#ifdef FEAT_NETBEANS_INTG
5228 if (ret > 0 && nb_idx != -1 && fds[nb_idx].revents & POLLIN)
5229 {
5230 netbeans_read();
5231 --ret;
5232 }
5233#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005234
5235
5236#else /* HAVE_SELECT */
5237
5238 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005239 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005240 fd_set rfds, efds;
5241 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005242 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005243
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005244# ifdef FEAT_MZSCHEME
5245 mzvim_check_threads();
5246 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5247 {
5248 towait = p_mzq; /* don't wait longer than 'mzquantum' */
5249 mzquantum_used = TRUE;
5250 }
5251# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005252# ifdef __EMX__
5253 /* don't check for incoming chars if not in raw mode, because select()
5254 * always returns TRUE then (in some version of emx.dll) */
5255 if (curr_tmode != TMODE_RAW)
5256 return 0;
5257# endif
5258
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005259 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005260 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005261 tv.tv_sec = towait / 1000;
5262 tv.tv_usec = (towait % 1000) * (1000000/1000);
5263 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005264 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005265 else
5266 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005267
5268 /*
5269 * Select on ready for reading and exceptional condition (end of file).
5270 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005271select_eintr:
5272 FD_ZERO(&rfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005273 FD_ZERO(&efds);
5274 FD_SET(fd, &rfds);
5275# if !defined(__QNX__) && !defined(__CYGWIN32__)
5276 /* For QNX select() always returns 1 if this is set. Why? */
5277 FD_SET(fd, &efds);
5278# endif
5279 maxfd = fd;
5280
5281# ifdef FEAT_SNIFF
5282 if (want_sniff_request)
5283 {
5284 FD_SET(fd_from_sniff, &rfds);
5285 FD_SET(fd_from_sniff, &efds);
5286 if (maxfd < fd_from_sniff)
5287 maxfd = fd_from_sniff;
5288 }
5289# endif
5290# ifdef FEAT_XCLIPBOARD
5291 if (xterm_Shell != (Widget)0)
5292 {
5293 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
5294 if (maxfd < ConnectionNumber(xterm_dpy))
5295 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02005296
5297 /* An event may have already been read but not handled. In
5298 * particulary, XFlush may cause this. */
5299 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005300 }
5301# endif
5302# ifdef FEAT_MOUSE_GPM
5303 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5304 {
5305 FD_SET(gpm_fd, &rfds);
5306 FD_SET(gpm_fd, &efds);
5307 if (maxfd < gpm_fd)
5308 maxfd = gpm_fd;
5309 }
5310# endif
5311# ifdef USE_XSMP
5312 if (xsmp_icefd != -1)
5313 {
5314 FD_SET(xsmp_icefd, &rfds);
5315 FD_SET(xsmp_icefd, &efds);
5316 if (maxfd < xsmp_icefd)
5317 maxfd = xsmp_icefd;
5318 }
5319# endif
Bram Moolenaardd82d692012-08-15 17:26:57 +02005320# ifdef FEAT_NETBEANS_INTG
Bram Moolenaar67c53842010-05-22 18:28:27 +02005321 if (nb_fd != -1)
5322 {
5323 FD_SET(nb_fd, &rfds);
5324 if (maxfd < nb_fd)
5325 maxfd = nb_fd;
5326 }
Bram Moolenaardd82d692012-08-15 17:26:57 +02005327# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005328
5329# ifdef OLD_VMS
5330 /* Old VMS as v6.2 and older have broken select(). It waits more than
5331 * required. Should not be used */
5332 ret = 0;
5333# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005334 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
5335# endif
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005336# ifdef EINTR
5337 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005338 {
5339 /* Check whether window has been resized, EINTR may be caused by
5340 * SIGWINCH. */
5341 if (do_resize)
5342 handle_resize();
5343
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005344 /* Interrupted by a signal, need to try again. We ignore msec
5345 * here, because we do want to check even after a timeout if
5346 * characters are available. Needed for reading output of an
5347 * external command after the process has finished. */
5348 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005349 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005350# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00005351# ifdef __TANDEM
5352 if (ret == -1 && errno == ENOTSUP)
5353 {
5354 FD_ZERO(&rfds);
5355 FD_ZERO(&efds);
5356 ret = 0;
5357 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005358# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005359# ifdef FEAT_MZSCHEME
5360 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005361 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005362 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005363# endif
5364
5365# ifdef FEAT_SNIFF
5366 if (ret < 0 )
5367 sniff_disconnect(1);
5368 else if (ret > 0 && want_sniff_request)
5369 {
5370 if (FD_ISSET(fd_from_sniff, &efds))
5371 sniff_disconnect(1);
5372 if (FD_ISSET(fd_from_sniff, &rfds))
5373 sniff_request_waiting = 1;
5374 }
5375# endif
5376# ifdef FEAT_XCLIPBOARD
5377 if (ret > 0 && xterm_Shell != (Widget)0
5378 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
5379 {
5380 xterm_update(); /* Maybe we should hand out clipboard */
5381 /* continue looping when we only got the X event and the input
5382 * buffer is empty */
5383 if (--ret == 0 && !input_available())
5384 {
5385 /* Try again */
5386 finished = FALSE;
5387 }
5388 }
5389# endif
5390# ifdef FEAT_MOUSE_GPM
5391 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
5392 {
5393 if (FD_ISSET(gpm_fd, &efds))
5394 gpm_close();
5395 else if (FD_ISSET(gpm_fd, &rfds))
5396 *check_for_gpm = 1;
5397 }
5398# endif
5399# ifdef USE_XSMP
5400 if (ret > 0 && xsmp_icefd != -1)
5401 {
5402 if (FD_ISSET(xsmp_icefd, &efds))
5403 {
5404 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005405 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005406 xsmp_close();
5407 if (--ret == 0)
5408 finished = FALSE; /* keep going if event was only one */
5409 }
5410 else if (FD_ISSET(xsmp_icefd, &rfds))
5411 {
5412 busy = TRUE;
5413 xsmp_handle_requests();
5414 busy = FALSE;
5415 if (--ret == 0)
5416 finished = FALSE; /* keep going if event was only one */
5417 }
5418 }
5419# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005420#ifdef FEAT_NETBEANS_INTG
5421 if (ret > 0 && nb_fd != -1 && FD_ISSET(nb_fd, &rfds))
5422 {
5423 netbeans_read();
5424 --ret;
5425 }
5426#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005427
5428#endif /* HAVE_SELECT */
5429
5430#ifdef MAY_LOOP
5431 if (finished || msec == 0)
5432 break;
5433
5434 /* We're going to loop around again, find out for how long */
5435 if (msec > 0)
5436 {
5437# ifdef USE_START_TV
5438 struct timeval mtv;
5439
5440 /* Compute remaining wait time. */
5441 gettimeofday(&mtv, NULL);
5442 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
5443 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
5444# else
5445 /* Guess we got interrupted halfway. */
5446 msec = msec / 2;
5447# endif
5448 if (msec <= 0)
5449 break; /* waited long enough */
5450 }
5451#endif
5452 }
5453
5454 return (ret > 0);
5455}
5456
5457#ifndef VMS
5458
5459#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00005460/*
Bram Moolenaar02743632005-07-25 20:42:36 +00005461 * Expand a path into all matching files and/or directories. Handles "*",
5462 * "?", "[a-z]", "**", etc.
5463 * "path" has backslashes before chars that are not to be expanded.
5464 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005465 */
5466 int
5467mch_expandpath(gap, path, flags)
5468 garray_T *gap;
5469 char_u *path;
5470 int flags; /* EW_* flags */
5471{
Bram Moolenaar02743632005-07-25 20:42:36 +00005472 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005473}
5474#endif
5475
5476/*
5477 * mch_expand_wildcards() - this code does wild-card pattern matching using
5478 * the shell
5479 *
5480 * return OK for success, FAIL for error (you may lose some memory) and put
5481 * an error message in *file.
5482 *
5483 * num_pat is number of input patterns
5484 * pat is array of pointers to input patterns
5485 * num_file is pointer to number of matched file names
5486 * file is pointer to array of pointers to matched file names
5487 */
5488
5489#ifndef SEEK_SET
5490# define SEEK_SET 0
5491#endif
5492#ifndef SEEK_END
5493# define SEEK_END 2
5494#endif
5495
Bram Moolenaar5555acc2006-04-07 21:33:12 +00005496#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00005497
Bram Moolenaar071d4272004-06-13 20:20:40 +00005498 int
5499mch_expand_wildcards(num_pat, pat, num_file, file, flags)
5500 int num_pat;
5501 char_u **pat;
5502 int *num_file;
5503 char_u ***file;
5504 int flags; /* EW_* flags */
5505{
5506 int i;
5507 size_t len;
5508 char_u *p;
5509 int dir;
5510#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00005511 /*
5512 * This is the OS/2 implementation.
5513 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005514# define EXPL_ALLOC_INC 16
5515 char_u **expl_files;
5516 size_t files_alloced, files_free;
5517 char_u *buf;
5518 int has_wildcard;
5519
5520 *num_file = 0; /* default: no files found */
5521 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
5522 files_free = EXPL_ALLOC_INC; /* how much space is not used */
5523 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
5524 if (*file == NULL)
5525 return FAIL;
5526
5527 for (; num_pat > 0; num_pat--, pat++)
5528 {
5529 expl_files = NULL;
5530 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
5531 /* expand environment var or home dir */
5532 buf = expand_env_save(*pat);
5533 else
5534 buf = vim_strsave(*pat);
5535 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005536 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005537 if (has_wildcard) /* yes, so expand them */
5538 expl_files = (char_u **)_fnexplode(buf);
5539
5540 /*
5541 * return value of buf if no wildcards left,
5542 * OR if no match AND EW_NOTFOUND is set.
5543 */
5544 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
5545 || (expl_files == NULL && (flags & EW_NOTFOUND)))
5546 { /* simply save the current contents of *buf */
5547 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
5548 if (expl_files != NULL)
5549 {
5550 expl_files[0] = vim_strsave(buf);
5551 expl_files[1] = NULL;
5552 }
5553 }
5554 vim_free(buf);
5555
5556 /*
5557 * Count number of names resulting from expansion,
5558 * At the same time add a backslash to the end of names that happen to
5559 * be directories, and replace slashes with backslashes.
5560 */
5561 if (expl_files)
5562 {
5563 for (i = 0; (p = expl_files[i]) != NULL; i++)
5564 {
5565 dir = mch_isdir(p);
5566 /* If we don't want dirs and this is one, skip it */
5567 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5568 continue;
5569
Bram Moolenaara2031822006-03-07 22:29:51 +00005570 /* Skip files that are not executable if we check for that. */
5571 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
5572 continue;
5573
Bram Moolenaar071d4272004-06-13 20:20:40 +00005574 if (--files_free == 0)
5575 {
5576 /* need more room in table of pointers */
5577 files_alloced += EXPL_ALLOC_INC;
5578 *file = (char_u **)vim_realloc(*file,
5579 sizeof(char_u **) * files_alloced);
5580 if (*file == NULL)
5581 {
5582 EMSG(_(e_outofmem));
5583 *num_file = 0;
5584 return FAIL;
5585 }
5586 files_free = EXPL_ALLOC_INC;
5587 }
5588 slash_adjust(p);
5589 if (dir)
5590 {
5591 /* For a directory we add a '/', unless it's already
5592 * there. */
5593 len = STRLEN(p);
5594 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5595 {
5596 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005597 if (!after_pathsep((*file)[*num_file],
5598 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005599 {
5600 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005601 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005602 }
5603 }
5604 }
5605 else
5606 {
5607 (*file)[*num_file] = vim_strsave(p);
5608 }
5609
5610 /*
5611 * Error message already given by either alloc or vim_strsave.
5612 * Should return FAIL, but returning OK works also.
5613 */
5614 if ((*file)[*num_file] == NULL)
5615 break;
5616 (*num_file)++;
5617 }
5618 _fnexplodefree((char **)expl_files);
5619 }
5620 }
5621 return OK;
5622
5623#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005624 /*
5625 * This is the non-OS/2 implementation (really Unix).
5626 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005627 int j;
5628 char_u *tempname;
5629 char_u *command;
5630 FILE *fd;
5631 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005632#define STYLE_ECHO 0 /* use "echo", the default */
5633#define STYLE_GLOB 1 /* use "glob", for csh */
5634#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5635#define STYLE_PRINT 3 /* use "print -N", for zsh */
5636#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5637 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005638 int shell_style = STYLE_ECHO;
5639 int check_spaces;
5640 static int did_find_nul = FALSE;
5641 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005642 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005643 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005644
5645 *num_file = 0; /* default: no files found */
5646 *file = NULL;
5647
5648 /*
5649 * If there are no wildcards, just copy the names to allocated memory.
5650 * Saves a lot of time, because we don't have to start a new shell.
5651 */
5652 if (!have_wildcard(num_pat, pat))
5653 return save_patterns(num_pat, pat, num_file, file);
5654
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005655# ifdef HAVE_SANDBOX
5656 /* Don't allow any shell command in the sandbox. */
5657 if (sandbox != 0 && check_secure())
5658 return FAIL;
5659# endif
5660
Bram Moolenaar071d4272004-06-13 20:20:40 +00005661 /*
5662 * Don't allow the use of backticks in secure and restricted mode.
5663 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005664 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005665 for (i = 0; i < num_pat; ++i)
5666 if (vim_strchr(pat[i], '`') != NULL
5667 && (check_restricted() || check_secure()))
5668 return FAIL;
5669
5670 /*
5671 * get a name for the temp file
5672 */
5673 if ((tempname = vim_tempname('o')) == NULL)
5674 {
5675 EMSG(_(e_notmp));
5676 return FAIL;
5677 }
5678
5679 /*
5680 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005681 * file.
5682 * STYLE_BT: NL separated
5683 * If expanding `cmd` execute it directly.
5684 * STYLE_GLOB: NUL separated
5685 * If we use *csh, "glob" will work better than "echo".
5686 * STYLE_PRINT: NL or NUL separated
5687 * If we use *zsh, "print -N" will work better than "glob".
5688 * STYLE_VIMGLOB: NL separated
5689 * If we use *sh*, we define "vimglob()".
5690 * STYLE_ECHO: space separated.
5691 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005692 */
5693 if (num_pat == 1 && *pat[0] == '`'
5694 && (len = STRLEN(pat[0])) > 2
5695 && *(pat[0] + len - 1) == '`')
5696 shell_style = STYLE_BT;
5697 else if ((len = STRLEN(p_sh)) >= 3)
5698 {
5699 if (STRCMP(p_sh + len - 3, "csh") == 0)
5700 shell_style = STYLE_GLOB;
5701 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5702 shell_style = STYLE_PRINT;
5703 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005704 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5705 "sh") != NULL)
5706 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005707
Bram Moolenaarc7247912008-01-13 12:54:11 +00005708 /* Compute the length of the command. We need 2 extra bytes: for the
5709 * optional '&' and for the NUL.
5710 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005711 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005712 if (shell_style == STYLE_VIMGLOB)
5713 len += STRLEN(sh_vimglob_func);
5714
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005715 for (i = 0; i < num_pat; ++i)
5716 {
5717 /* Count the length of the patterns in the same way as they are put in
5718 * "command" below. */
5719#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005720 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005721#else
5722 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005723 for (j = 0; pat[i][j] != NUL; ++j)
5724 {
5725 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5726 ++len; /* may add a backslash */
5727 ++len;
5728 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005729#endif
5730 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005731 command = alloc(len);
5732 if (command == NULL)
5733 {
5734 /* out of memory */
5735 vim_free(tempname);
5736 return FAIL;
5737 }
5738
5739 /*
5740 * Build the shell command:
5741 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5742 * recognizes this).
5743 * - Add the shell command to print the expanded names.
5744 * - Add the temp file name.
5745 * - Add the file name patterns.
5746 */
5747 if (shell_style == STYLE_BT)
5748 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005749 /* change `command; command& ` to (command; command ) */
5750 STRCPY(command, "(");
5751 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005752 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005753 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005754 while (p > command && vim_iswhite(*p))
5755 --p;
5756 if (*p == '&') /* remove trailing '&' */
5757 {
5758 ampersent = TRUE;
5759 *p = ' ';
5760 }
5761 STRCAT(command, ">");
5762 }
5763 else
5764 {
5765 if (flags & EW_NOTFOUND)
5766 STRCPY(command, "set nonomatch; ");
5767 else
5768 STRCPY(command, "unset nonomatch; ");
5769 if (shell_style == STYLE_GLOB)
5770 STRCAT(command, "glob >");
5771 else if (shell_style == STYLE_PRINT)
5772 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005773 else if (shell_style == STYLE_VIMGLOB)
5774 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005775 else
5776 STRCAT(command, "echo >");
5777 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005778
Bram Moolenaar071d4272004-06-13 20:20:40 +00005779 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005780
Bram Moolenaar071d4272004-06-13 20:20:40 +00005781 if (shell_style != STYLE_BT)
5782 for (i = 0; i < num_pat; ++i)
5783 {
5784 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005785 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005786 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005787#ifdef USE_SYSTEM
5788 STRCAT(command, " \"");
5789 STRCAT(command, pat[i]);
5790 STRCAT(command, "\"");
5791#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005792 int intick = FALSE;
5793
Bram Moolenaar071d4272004-06-13 20:20:40 +00005794 p = command + STRLEN(command);
5795 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005796 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005797 {
5798 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005799 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005800 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5801 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005802 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005803 * backslash inside backticks, before a special character
5804 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005805 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005806 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5807 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005808 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005809 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005810 }
5811 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005812 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005813 /* Put a backslash before a special character, but not
5814 * when inside ``. */
5815 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005816
5817 /* Copy one character. */
5818 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005819 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005820 *p = NUL;
5821#endif
5822 }
5823 if (flags & EW_SILENT)
5824 show_shell_mess = FALSE;
5825 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00005826 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005827
5828 /*
5829 * Using zsh -G: If a pattern has no matches, it is just deleted from
5830 * the argument list, otherwise zsh gives an error message and doesn't
5831 * expand any other pattern.
5832 */
5833 if (shell_style == STYLE_PRINT)
5834 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5835
5836 /*
5837 * If we use -f then shell variables set in .cshrc won't get expanded.
5838 * vi can do it, so we will too, but it is only necessary if there is a "$"
5839 * in one of the patterns, otherwise we can still use the fast option.
5840 */
5841 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5842 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5843
5844 /*
5845 * execute the shell command
5846 */
5847 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5848
5849 /* When running in the background, give it some time to create the temp
5850 * file, but don't wait for it to finish. */
5851 if (ampersent)
5852 mch_delay(10L, TRUE);
5853
5854 extra_shell_arg = NULL; /* cleanup */
5855 show_shell_mess = TRUE;
5856 vim_free(command);
5857
Bram Moolenaarc7247912008-01-13 12:54:11 +00005858 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005859 {
5860 mch_remove(tempname);
5861 vim_free(tempname);
5862 /*
5863 * With interactive completion, the error message is not printed.
5864 * However with USE_SYSTEM, I don't know how to turn off error messages
5865 * from the shell, so screen may still get messed up -- webb.
5866 */
5867#ifndef USE_SYSTEM
5868 if (!(flags & EW_SILENT))
5869#endif
5870 {
5871 redraw_later_clear(); /* probably messed up screen */
5872 msg_putchar('\n'); /* clear bottom line quickly */
5873 cmdline_row = Rows - 1; /* continue on last line */
5874#ifdef USE_SYSTEM
5875 if (!(flags & EW_SILENT))
5876#endif
5877 {
5878 MSG(_(e_wildexpand));
5879 msg_start(); /* don't overwrite this message */
5880 }
5881 }
5882 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5883 * EW_NOTFOUND is given */
5884 if (shell_style == STYLE_BT)
5885 return FAIL;
5886 goto notfound;
5887 }
5888
5889 /*
5890 * read the names from the file into memory
5891 */
5892 fd = fopen((char *)tempname, READBIN);
5893 if (fd == NULL)
5894 {
5895 /* Something went wrong, perhaps a file name with a special char. */
5896 if (!(flags & EW_SILENT))
5897 {
5898 MSG(_(e_wildexpand));
5899 msg_start(); /* don't overwrite this message */
5900 }
5901 vim_free(tempname);
5902 goto notfound;
5903 }
5904 fseek(fd, 0L, SEEK_END);
5905 len = ftell(fd); /* get size of temp file */
5906 fseek(fd, 0L, SEEK_SET);
5907 buffer = alloc(len + 1);
5908 if (buffer == NULL)
5909 {
5910 /* out of memory */
5911 mch_remove(tempname);
5912 vim_free(tempname);
5913 fclose(fd);
5914 return FAIL;
5915 }
5916 i = fread((char *)buffer, 1, len, fd);
5917 fclose(fd);
5918 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00005919 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005920 {
5921 /* unexpected read error */
5922 EMSG2(_(e_notread), tempname);
5923 vim_free(tempname);
5924 vim_free(buffer);
5925 return FAIL;
5926 }
5927 vim_free(tempname);
5928
Bram Moolenaarc7247912008-01-13 12:54:11 +00005929# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005930 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5931 p = buffer;
5932 for (i = 0; i < len; ++i)
5933 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5934 *p++ = buffer[i];
5935 len = p - buffer;
5936# endif
5937
5938
5939 /* file names are separated with Space */
5940 if (shell_style == STYLE_ECHO)
5941 {
5942 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5943 p = buffer;
5944 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5945 {
5946 while (*p != ' ' && *p != '\n')
5947 ++p;
5948 p = skipwhite(p); /* skip to next entry */
5949 }
5950 }
5951 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005952 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005953 {
5954 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5955 p = buffer;
5956 for (i = 0; *p != NUL; ++i) /* count number of entries */
5957 {
5958 while (*p != '\n' && *p != NUL)
5959 ++p;
5960 if (*p != NUL)
5961 ++p;
5962 p = skipwhite(p); /* skip leading white space */
5963 }
5964 }
5965 /* file names are separated with NUL */
5966 else
5967 {
5968 /*
5969 * Some versions of zsh use spaces instead of NULs to separate
5970 * results. Only do this when there is no NUL before the end of the
5971 * buffer, otherwise we would never be able to use file names with
5972 * embedded spaces when zsh does use NULs.
5973 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5974 * don't check for spaces again.
5975 */
5976 check_spaces = FALSE;
5977 if (shell_style == STYLE_PRINT && !did_find_nul)
5978 {
5979 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02005980 buffer[len] = NUL;
Bram Moolenaar78a15312009-05-15 19:33:18 +00005981 if (len && (int)STRLEN(buffer) < (int)len - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005982 did_find_nul = TRUE;
5983 else
5984 check_spaces = TRUE;
5985 }
5986
5987 /*
5988 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5989 * already is one, for STYLE_GLOB it needs to be added.
5990 */
5991 if (len && buffer[len - 1] == NUL)
5992 --len;
5993 else
5994 buffer[len] = NUL;
5995 i = 0;
5996 for (p = buffer; p < buffer + len; ++p)
5997 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5998 {
5999 ++i;
6000 *p = NUL;
6001 }
6002 if (len)
6003 ++i; /* count last entry */
6004 }
6005 if (i == 0)
6006 {
6007 /*
6008 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6009 * /bin/sh will happily expand it to nothing rather than returning an
6010 * error; and hey, it's good to check anyway -- webb.
6011 */
6012 vim_free(buffer);
6013 goto notfound;
6014 }
6015 *num_file = i;
6016 *file = (char_u **)alloc(sizeof(char_u *) * i);
6017 if (*file == NULL)
6018 {
6019 /* out of memory */
6020 vim_free(buffer);
6021 return FAIL;
6022 }
6023
6024 /*
6025 * Isolate the individual file names.
6026 */
6027 p = buffer;
6028 for (i = 0; i < *num_file; ++i)
6029 {
6030 (*file)[i] = p;
6031 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006032 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6033 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006034 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006035 while (!(shell_style == STYLE_ECHO && *p == ' ')
6036 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006037 ++p;
6038 if (p == buffer + len) /* last entry */
6039 *p = NUL;
6040 else
6041 {
6042 *p++ = NUL;
6043 p = skipwhite(p); /* skip to next entry */
6044 }
6045 }
6046 else /* NUL separates */
6047 {
6048 while (*p && p < buffer + len) /* skip entry */
6049 ++p;
6050 ++p; /* skip NUL */
6051 }
6052 }
6053
6054 /*
6055 * Move the file names to allocated memory.
6056 */
6057 for (j = 0, i = 0; i < *num_file; ++i)
6058 {
6059 /* Require the files to exist. Helps when using /bin/sh */
6060 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6061 continue;
6062
6063 /* check if this entry should be included */
6064 dir = (mch_isdir((*file)[i]));
6065 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6066 continue;
6067
Bram Moolenaara2031822006-03-07 22:29:51 +00006068 /* Skip files that are not executable if we check for that. */
6069 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
6070 continue;
6071
Bram Moolenaar071d4272004-06-13 20:20:40 +00006072 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
6073 if (p)
6074 {
6075 STRCPY(p, (*file)[i]);
6076 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00006077 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006078 (*file)[j++] = p;
6079 }
6080 }
6081 vim_free(buffer);
6082 *num_file = j;
6083
6084 if (*num_file == 0) /* rejected all entries */
6085 {
6086 vim_free(*file);
6087 *file = NULL;
6088 goto notfound;
6089 }
6090
6091 return OK;
6092
6093notfound:
6094 if (flags & EW_NOTFOUND)
6095 return save_patterns(num_pat, pat, num_file, file);
6096 return FAIL;
6097
6098#endif /* __EMX__ */
6099}
6100
6101#endif /* VMS */
6102
6103#ifndef __EMX__
6104 static int
6105save_patterns(num_pat, pat, num_file, file)
6106 int num_pat;
6107 char_u **pat;
6108 int *num_file;
6109 char_u ***file;
6110{
6111 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006112 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006113
6114 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
6115 if (*file == NULL)
6116 return FAIL;
6117 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006118 {
6119 s = vim_strsave(pat[i]);
6120 if (s != NULL)
6121 /* Be compatible with expand_filename(): halve the number of
6122 * backslashes. */
6123 backslash_halve(s);
6124 (*file)[i] = s;
6125 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006126 *num_file = num_pat;
6127 return OK;
6128}
6129#endif
6130
6131
6132/*
6133 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
6134 * expand.
6135 */
6136 int
6137mch_has_exp_wildcard(p)
6138 char_u *p;
6139{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006140 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006141 {
6142#ifndef OS2
6143 if (*p == '\\' && p[1] != NUL)
6144 ++p;
6145 else
6146#endif
6147 if (vim_strchr((char_u *)
6148#ifdef VMS
6149 "*?%"
6150#else
6151# ifdef OS2
6152 "*?"
6153# else
6154 "*?[{'"
6155# endif
6156#endif
6157 , *p) != NULL)
6158 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006159 }
6160 return FALSE;
6161}
6162
6163/*
6164 * Return TRUE if the string "p" contains a wildcard.
6165 * Don't recognize '~' at the end as a wildcard.
6166 */
6167 int
6168mch_has_wildcard(p)
6169 char_u *p;
6170{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006171 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006172 {
6173#ifndef OS2
6174 if (*p == '\\' && p[1] != NUL)
6175 ++p;
6176 else
6177#endif
6178 if (vim_strchr((char_u *)
6179#ifdef VMS
6180 "*?%$"
6181#else
6182# ifdef OS2
6183# ifdef VIM_BACKTICK
6184 "*?$`"
6185# else
6186 "*?$"
6187# endif
6188# else
6189 "*?[{`'$"
6190# endif
6191#endif
6192 , *p) != NULL
6193 || (*p == '~' && p[1] != NUL))
6194 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006195 }
6196 return FALSE;
6197}
6198
6199#ifndef __EMX__
6200 static int
6201have_wildcard(num, file)
6202 int num;
6203 char_u **file;
6204{
6205 int i;
6206
6207 for (i = 0; i < num; i++)
6208 if (mch_has_wildcard(file[i]))
6209 return 1;
6210 return 0;
6211}
6212
6213 static int
6214have_dollars(num, file)
6215 int num;
6216 char_u **file;
6217{
6218 int i;
6219
6220 for (i = 0; i < num; i++)
6221 if (vim_strchr(file[i], '$') != NULL)
6222 return TRUE;
6223 return FALSE;
6224}
6225#endif /* ifndef __EMX__ */
6226
6227#ifndef HAVE_RENAME
6228/*
6229 * Scaled-down version of rename(), which is missing in Xenix.
6230 * This version can only move regular files and will fail if the
6231 * destination exists.
6232 */
6233 int
6234mch_rename(src, dest)
6235 const char *src, *dest;
6236{
6237 struct stat st;
6238
6239 if (stat(dest, &st) >= 0) /* fail if destination exists */
6240 return -1;
6241 if (link(src, dest) != 0) /* link file to new name */
6242 return -1;
6243 if (mch_remove(src) == 0) /* delete link to old name */
6244 return 0;
6245 return -1;
6246}
6247#endif /* !HAVE_RENAME */
6248
6249#ifdef FEAT_MOUSE_GPM
6250/*
6251 * Initializes connection with gpm (if it isn't already opened)
6252 * Return 1 if succeeded (or connection already opened), 0 if failed
6253 */
6254 static int
6255gpm_open()
6256{
6257 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
6258
6259 if (!gpm_flag)
6260 {
6261 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
6262 gpm_connect.defaultMask = ~GPM_HARD;
6263 /* Default handling for mouse move*/
6264 gpm_connect.minMod = 0; /* Handle any modifier keys */
6265 gpm_connect.maxMod = 0xffff;
6266 if (Gpm_Open(&gpm_connect, 0) > 0)
6267 {
6268 /* gpm library tries to handling TSTP causes
6269 * problems. Anyways, we close connection to Gpm whenever
6270 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006271 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00006272 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006273# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00006274 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006275# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006276 return 1; /* succeed */
6277 }
6278 if (gpm_fd == -2)
6279 Gpm_Close(); /* We don't want to talk to xterm via gpm */
6280 return 0;
6281 }
6282 return 1; /* already open */
6283}
6284
6285/*
6286 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00006287 */
6288 static void
6289gpm_close()
6290{
6291 if (gpm_flag && gpm_fd >= 0) /* if Open */
6292 Gpm_Close();
6293}
6294
6295/* Reads gpm event and adds special keys to input buf. Returns length of
6296 * generated key sequence.
6297 * This function is made after gui_send_mouse_event
6298 */
6299 static int
6300mch_gpm_process()
6301{
6302 int button;
6303 static Gpm_Event gpm_event;
6304 char_u string[6];
6305 int_u vim_modifiers;
6306 int row,col;
6307 unsigned char buttons_mask;
6308 unsigned char gpm_modifiers;
6309 static unsigned char old_buttons = 0;
6310
6311 Gpm_GetEvent(&gpm_event);
6312
6313#ifdef FEAT_GUI
6314 /* Don't put events in the input queue now. */
6315 if (hold_gui_events)
6316 return 0;
6317#endif
6318
6319 row = gpm_event.y - 1;
6320 col = gpm_event.x - 1;
6321
6322 string[0] = ESC; /* Our termcode */
6323 string[1] = 'M';
6324 string[2] = 'G';
6325 switch (GPM_BARE_EVENTS(gpm_event.type))
6326 {
6327 case GPM_DRAG:
6328 string[3] = MOUSE_DRAG;
6329 break;
6330 case GPM_DOWN:
6331 buttons_mask = gpm_event.buttons & ~old_buttons;
6332 old_buttons = gpm_event.buttons;
6333 switch (buttons_mask)
6334 {
6335 case GPM_B_LEFT:
6336 button = MOUSE_LEFT;
6337 break;
6338 case GPM_B_MIDDLE:
6339 button = MOUSE_MIDDLE;
6340 break;
6341 case GPM_B_RIGHT:
6342 button = MOUSE_RIGHT;
6343 break;
6344 default:
6345 return 0;
6346 /*Don't know what to do. Can more than one button be
6347 * reported in one event? */
6348 }
6349 string[3] = (char_u)(button | 0x20);
6350 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
6351 break;
6352 case GPM_UP:
6353 string[3] = MOUSE_RELEASE;
6354 old_buttons &= ~gpm_event.buttons;
6355 break;
6356 default:
6357 return 0;
6358 }
6359 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
6360 gpm_modifiers = gpm_event.modifiers;
6361 vim_modifiers = 0x0;
6362 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
6363 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
6364 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
6365 */
6366 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
6367 vim_modifiers |= MOUSE_SHIFT;
6368
6369 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
6370 vim_modifiers |= MOUSE_CTRL;
6371 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
6372 vim_modifiers |= MOUSE_ALT;
6373 string[3] |= vim_modifiers;
6374 string[4] = (char_u)(col + ' ' + 1);
6375 string[5] = (char_u)(row + ' ' + 1);
6376 add_to_input_buf(string, 6);
6377 return 6;
6378}
6379#endif /* FEAT_MOUSE_GPM */
6380
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006381#ifdef FEAT_SYSMOUSE
6382/*
6383 * Initialize connection with sysmouse.
6384 * Let virtual console inform us with SIGUSR2 for pending sysmouse
6385 * output, any sysmouse output than will be processed via sig_sysmouse().
6386 * Return OK if succeeded, FAIL if failed.
6387 */
6388 static int
6389sysmouse_open()
6390{
6391 struct mouse_info mouse;
6392
6393 mouse.operation = MOUSE_MODE;
6394 mouse.u.mode.mode = 0;
6395 mouse.u.mode.signal = SIGUSR2;
6396 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
6397 {
6398 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
6399 mouse.operation = MOUSE_SHOW;
6400 ioctl(1, CONS_MOUSECTL, &mouse);
6401 return OK;
6402 }
6403 return FAIL;
6404}
6405
6406/*
6407 * Stop processing SIGUSR2 signals, and also make sure that
6408 * virtual console do not send us any sysmouse related signal.
6409 */
6410 static void
6411sysmouse_close()
6412{
6413 struct mouse_info mouse;
6414
6415 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
6416 mouse.operation = MOUSE_MODE;
6417 mouse.u.mode.mode = 0;
6418 mouse.u.mode.signal = 0;
6419 ioctl(1, CONS_MOUSECTL, &mouse);
6420}
6421
6422/*
6423 * Gets info from sysmouse and adds special keys to input buf.
6424 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006425 static RETSIGTYPE
6426sig_sysmouse SIGDEFARG(sigarg)
6427{
6428 struct mouse_info mouse;
6429 struct video_info video;
6430 char_u string[6];
6431 int row, col;
6432 int button;
6433 int buttons;
6434 static int oldbuttons = 0;
6435
6436#ifdef FEAT_GUI
6437 /* Don't put events in the input queue now. */
6438 if (hold_gui_events)
6439 return;
6440#endif
6441
6442 mouse.operation = MOUSE_GETINFO;
6443 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
6444 && ioctl(1, FBIO_MODEINFO, &video) != -1
6445 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
6446 && video.vi_cheight > 0 && video.vi_cwidth > 0)
6447 {
6448 row = mouse.u.data.y / video.vi_cheight;
6449 col = mouse.u.data.x / video.vi_cwidth;
6450 buttons = mouse.u.data.buttons;
6451 string[0] = ESC; /* Our termcode */
6452 string[1] = 'M';
6453 string[2] = 'S';
6454 if (oldbuttons == buttons && buttons != 0)
6455 {
6456 button = MOUSE_DRAG;
6457 }
6458 else
6459 {
6460 switch (buttons)
6461 {
6462 case 0:
6463 button = MOUSE_RELEASE;
6464 break;
6465 case 1:
6466 button = MOUSE_LEFT;
6467 break;
6468 case 2:
6469 button = MOUSE_MIDDLE;
6470 break;
6471 case 4:
6472 button = MOUSE_RIGHT;
6473 break;
6474 default:
6475 return;
6476 }
6477 oldbuttons = buttons;
6478 }
6479 string[3] = (char_u)(button);
6480 string[4] = (char_u)(col + ' ' + 1);
6481 string[5] = (char_u)(row + ' ' + 1);
6482 add_to_input_buf(string, 6);
6483 }
6484 return;
6485}
6486#endif /* FEAT_SYSMOUSE */
6487
Bram Moolenaar071d4272004-06-13 20:20:40 +00006488#if defined(FEAT_LIBCALL) || defined(PROTO)
6489typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
6490typedef char_u * (*INTPROCSTR)__ARGS((int));
6491typedef int (*STRPROCINT)__ARGS((char_u *));
6492typedef int (*INTPROCINT)__ARGS((int));
6493
6494/*
6495 * Call a DLL routine which takes either a string or int param
6496 * and returns an allocated string.
6497 */
6498 int
6499mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
6500 char_u *libname;
6501 char_u *funcname;
6502 char_u *argstring; /* NULL when using a argint */
6503 int argint;
6504 char_u **string_result;/* NULL when using number_result */
6505 int *number_result;
6506{
6507# if defined(USE_DLOPEN)
6508 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006509 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006510# else
6511 shl_t hinstLib;
6512# endif
6513 STRPROCSTR ProcAdd;
6514 INTPROCSTR ProcAddI;
6515 char_u *retval_str = NULL;
6516 int retval_int = 0;
6517 int success = FALSE;
6518
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006519 /*
6520 * Get a handle to the DLL module.
6521 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006522# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006523 /* First clear any error, it's not cleared by the dlopen() call. */
6524 (void)dlerror();
6525
Bram Moolenaar071d4272004-06-13 20:20:40 +00006526 hinstLib = dlopen((char *)libname, RTLD_LAZY
6527# ifdef RTLD_LOCAL
6528 | RTLD_LOCAL
6529# endif
6530 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006531 if (hinstLib == NULL)
6532 {
6533 /* "dlerr" must be used before dlclose() */
6534 dlerr = (char *)dlerror();
6535 if (dlerr != NULL)
6536 EMSG2(_("dlerror = \"%s\""), dlerr);
6537 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006538# else
6539 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
6540# endif
6541
6542 /* If the handle is valid, try to get the function address. */
6543 if (hinstLib != NULL)
6544 {
6545# ifdef HAVE_SETJMP_H
6546 /*
6547 * Catch a crash when calling the library function. For example when
6548 * using a number where a string pointer is expected.
6549 */
6550 mch_startjmp();
6551 if (SETJMP(lc_jump_env) != 0)
6552 {
6553 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006554# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006555 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006556# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006557 mch_didjmp();
6558 }
6559 else
6560# endif
6561 {
6562 retval_str = NULL;
6563 retval_int = 0;
6564
6565 if (argstring != NULL)
6566 {
6567# if defined(USE_DLOPEN)
6568 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006569 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006570# else
6571 if (shl_findsym(&hinstLib, (const char *)funcname,
6572 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
6573 ProcAdd = NULL;
6574# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006575 if ((success = (ProcAdd != NULL
6576# if defined(USE_DLOPEN)
6577 && dlerr == NULL
6578# endif
6579 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006580 {
6581 if (string_result == NULL)
6582 retval_int = ((STRPROCINT)ProcAdd)(argstring);
6583 else
6584 retval_str = (ProcAdd)(argstring);
6585 }
6586 }
6587 else
6588 {
6589# if defined(USE_DLOPEN)
6590 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006591 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006592# else
6593 if (shl_findsym(&hinstLib, (const char *)funcname,
6594 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
6595 ProcAddI = NULL;
6596# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006597 if ((success = (ProcAddI != NULL
6598# if defined(USE_DLOPEN)
6599 && dlerr == NULL
6600# endif
6601 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006602 {
6603 if (string_result == NULL)
6604 retval_int = ((INTPROCINT)ProcAddI)(argint);
6605 else
6606 retval_str = (ProcAddI)(argint);
6607 }
6608 }
6609
6610 /* Save the string before we free the library. */
6611 /* Assume that a "1" or "-1" result is an illegal pointer. */
6612 if (string_result == NULL)
6613 *number_result = retval_int;
6614 else if (retval_str != NULL
6615 && retval_str != (char_u *)1
6616 && retval_str != (char_u *)-1)
6617 *string_result = vim_strsave(retval_str);
6618 }
6619
6620# ifdef HAVE_SETJMP_H
6621 mch_endjmp();
6622# ifdef SIGHASARG
6623 if (lc_signal != 0)
6624 {
6625 int i;
6626
6627 /* try to find the name of this signal */
6628 for (i = 0; signal_info[i].sig != -1; i++)
6629 if (lc_signal == signal_info[i].sig)
6630 break;
6631 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6632 }
6633# endif
6634# endif
6635
Bram Moolenaar071d4272004-06-13 20:20:40 +00006636# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006637 /* "dlerr" must be used before dlclose() */
6638 if (dlerr != NULL)
6639 EMSG2(_("dlerror = \"%s\""), dlerr);
6640
6641 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006642 (void)dlclose(hinstLib);
6643# else
6644 (void)shl_unload(hinstLib);
6645# endif
6646 }
6647
6648 if (!success)
6649 {
6650 EMSG2(_(e_libcall), funcname);
6651 return FAIL;
6652 }
6653
6654 return OK;
6655}
6656#endif
6657
6658#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6659static int xterm_trace = -1; /* default: disabled */
6660static int xterm_button;
6661
6662/*
6663 * Setup a dummy window for X selections in a terminal.
6664 */
6665 void
6666setup_term_clip()
6667{
6668 int z = 0;
6669 char *strp = "";
6670 Widget AppShell;
6671
6672 if (!x_connect_to_server())
6673 return;
6674
6675 open_app_context();
6676 if (app_context != NULL && xterm_Shell == (Widget)0)
6677 {
6678 int (*oldhandler)();
6679#if defined(HAVE_SETJMP_H)
6680 int (*oldIOhandler)();
6681#endif
6682# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6683 struct timeval start_tv;
6684
6685 if (p_verbose > 0)
6686 gettimeofday(&start_tv, NULL);
6687# endif
6688
6689 /* Ignore X errors while opening the display */
6690 oldhandler = XSetErrorHandler(x_error_check);
6691
6692#if defined(HAVE_SETJMP_H)
6693 /* Ignore X IO errors while opening the display */
6694 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6695 mch_startjmp();
6696 if (SETJMP(lc_jump_env) != 0)
6697 {
6698 mch_didjmp();
6699 xterm_dpy = NULL;
6700 }
6701 else
6702#endif
6703 {
6704 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6705 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6706#if defined(HAVE_SETJMP_H)
6707 mch_endjmp();
6708#endif
6709 }
6710
6711#if defined(HAVE_SETJMP_H)
6712 /* Now handle X IO errors normally. */
6713 (void)XSetIOErrorHandler(oldIOhandler);
6714#endif
6715 /* Now handle X errors normally. */
6716 (void)XSetErrorHandler(oldhandler);
6717
6718 if (xterm_dpy == NULL)
6719 {
6720 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006721 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006722 return;
6723 }
6724
6725 /* Catch terminating error of the X server connection. */
6726 (void)XSetIOErrorHandler(x_IOerror_handler);
6727
6728# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6729 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006730 {
6731 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006732 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006733 verbose_leave();
6734 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006735# endif
6736
6737 /* Create a Shell to make converters work. */
6738 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6739 applicationShellWidgetClass, xterm_dpy,
6740 NULL);
6741 if (AppShell == (Widget)0)
6742 return;
6743 xterm_Shell = XtVaCreatePopupShell("VIM",
6744 topLevelShellWidgetClass, AppShell,
6745 XtNmappedWhenManaged, 0,
6746 XtNwidth, 1,
6747 XtNheight, 1,
6748 NULL);
6749 if (xterm_Shell == (Widget)0)
6750 return;
6751
6752 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02006753 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006754 if (x11_display == NULL)
6755 x11_display = xterm_dpy;
6756
6757 XtRealizeWidget(xterm_Shell);
6758 XSync(xterm_dpy, False);
6759 xterm_update();
6760 }
6761 if (xterm_Shell != (Widget)0)
6762 {
6763 clip_init(TRUE);
6764 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6765 x11_window = (Window)atol(strp);
6766 /* Check if $WINDOWID is valid. */
6767 if (test_x11_window(xterm_dpy) == FAIL)
6768 x11_window = 0;
6769 if (x11_window != 0)
6770 xterm_trace = 0;
6771 }
6772}
6773
6774 void
6775start_xterm_trace(button)
6776 int button;
6777{
6778 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6779 return;
6780 xterm_trace = 1;
6781 xterm_button = button;
6782 do_xterm_trace();
6783}
6784
6785
6786 void
6787stop_xterm_trace()
6788{
6789 if (xterm_trace < 0)
6790 return;
6791 xterm_trace = 0;
6792}
6793
6794/*
6795 * Query the xterm pointer and generate mouse termcodes if necessary
6796 * return TRUE if dragging is active, else FALSE
6797 */
6798 static int
6799do_xterm_trace()
6800{
6801 Window root, child;
6802 int root_x, root_y;
6803 int win_x, win_y;
6804 int row, col;
6805 int_u mask_return;
6806 char_u buf[50];
6807 char_u *strp;
6808 long got_hints;
6809 static char_u *mouse_code;
6810 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6811 static int prev_row = 0, prev_col = 0;
6812 static XSizeHints xterm_hints;
6813
6814 if (xterm_trace <= 0)
6815 return FALSE;
6816
6817 if (xterm_trace == 1)
6818 {
6819 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006820 * have changed recently. */
6821 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6822 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006823 || xterm_hints.width_inc <= 1
6824 || xterm_hints.height_inc <= 1)
6825 {
6826 xterm_trace = -1; /* Not enough data -- disable tracing */
6827 return FALSE;
6828 }
6829
6830 /* Rely on the same mouse code for the duration of this */
6831 mouse_code = find_termcode(mouse_name);
6832 prev_row = mouse_row;
6833 prev_row = mouse_col;
6834 xterm_trace = 2;
6835
6836 /* Find the offset of the chars, there might be a scrollbar on the
6837 * left of the window and/or a menu on the top (eterm etc.) */
6838 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6839 &win_x, &win_y, &mask_return);
6840 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6841 - (xterm_hints.height_inc / 2);
6842 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6843 xterm_hints.y = 2;
6844 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6845 - (xterm_hints.width_inc / 2);
6846 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6847 xterm_hints.x = 2;
6848 return TRUE;
6849 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006850 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006851 {
6852 xterm_trace = 0;
6853 return FALSE;
6854 }
6855
6856 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6857 &win_x, &win_y, &mask_return);
6858
6859 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6860 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6861 if (row == prev_row && col == prev_col)
6862 return TRUE;
6863
6864 STRCPY(buf, mouse_code);
6865 strp = buf + STRLEN(buf);
6866 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6867 *strp++ = (char_u)(col + ' ' + 1);
6868 *strp++ = (char_u)(row + ' ' + 1);
6869 *strp = 0;
6870 add_to_input_buf(buf, STRLEN(buf));
6871
6872 prev_row = row;
6873 prev_col = col;
6874 return TRUE;
6875}
6876
6877# if defined(FEAT_GUI) || defined(PROTO)
6878/*
6879 * Destroy the display, window and app_context. Required for GTK.
6880 */
6881 void
6882clear_xterm_clip()
6883{
6884 if (xterm_Shell != (Widget)0)
6885 {
6886 XtDestroyWidget(xterm_Shell);
6887 xterm_Shell = (Widget)0;
6888 }
6889 if (xterm_dpy != NULL)
6890 {
Bram Moolenaare8208012008-06-20 09:59:25 +00006891# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006892 /* Lesstif and Solaris crash here, lose some memory */
6893 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00006894# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006895 if (x11_display == xterm_dpy)
6896 x11_display = NULL;
6897 xterm_dpy = NULL;
6898 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006899# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006900 if (app_context != (XtAppContext)NULL)
6901 {
6902 /* Lesstif and Solaris crash here, lose some memory */
6903 XtDestroyApplicationContext(app_context);
6904 app_context = (XtAppContext)NULL;
6905 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006906# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006907}
6908# endif
6909
6910/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01006911 * Catch up with GUI or X events.
6912 */
6913 static void
6914clip_update()
6915{
6916# ifdef FEAT_GUI
6917 if (gui.in_use)
6918 gui_mch_update();
6919 else
6920# endif
6921 if (xterm_Shell != (Widget)0)
6922 xterm_update();
6923}
6924
6925/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00006926 * Catch up with any queued X events. This may put keyboard input into the
6927 * input buffer, call resize call-backs, trigger timers etc. If there is
6928 * nothing in the X event queue (& no timers pending), then we return
6929 * immediately.
6930 */
6931 static void
6932xterm_update()
6933{
6934 XEvent event;
6935
6936 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6937 {
6938 XtAppNextEvent(app_context, &event);
6939#ifdef FEAT_CLIENTSERVER
6940 {
6941 XPropertyEvent *e = (XPropertyEvent *)&event;
6942
6943 if (e->type == PropertyNotify && e->window == commWindow
6944 && e->atom == commProperty && e->state == PropertyNewValue)
6945 serverEventProc(xterm_dpy, &event);
6946 }
6947#endif
6948 XtDispatchEvent(&event);
6949 }
6950}
6951
6952 int
6953clip_xterm_own_selection(cbd)
6954 VimClipboard *cbd;
6955{
6956 if (xterm_Shell != (Widget)0)
6957 return clip_x11_own_selection(xterm_Shell, cbd);
6958 return FAIL;
6959}
6960
6961 void
6962clip_xterm_lose_selection(cbd)
6963 VimClipboard *cbd;
6964{
6965 if (xterm_Shell != (Widget)0)
6966 clip_x11_lose_selection(xterm_Shell, cbd);
6967}
6968
6969 void
6970clip_xterm_request_selection(cbd)
6971 VimClipboard *cbd;
6972{
6973 if (xterm_Shell != (Widget)0)
6974 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6975}
6976
6977 void
6978clip_xterm_set_selection(cbd)
6979 VimClipboard *cbd;
6980{
6981 clip_x11_set_selection(cbd);
6982}
6983#endif
6984
6985
6986#if defined(USE_XSMP) || defined(PROTO)
6987/*
6988 * Code for X Session Management Protocol.
6989 */
6990static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6991static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6992static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6993static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6994static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6995
6996
6997# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6998static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6999
7000/*
7001 * This is our chance to ask the user if they want to save,
7002 * or abort the logout
7003 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007004 static void
7005xsmp_handle_interaction(smc_conn, client_data)
7006 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007007 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007008{
7009 cmdmod_T save_cmdmod;
7010 int cancel_shutdown = False;
7011
7012 save_cmdmod = cmdmod;
7013 cmdmod.confirm = TRUE;
7014 if (check_changed_any(FALSE))
7015 /* Mustn't logout */
7016 cancel_shutdown = True;
7017 cmdmod = save_cmdmod;
7018 setcursor(); /* position cursor */
7019 out_flush();
7020
7021 /* Done interaction */
7022 SmcInteractDone(smc_conn, cancel_shutdown);
7023
7024 /* Finish off
7025 * Only end save-yourself here if we're not cancelling shutdown;
7026 * we'll get a cancelled callback later in which we'll end it.
7027 * Hopefully get around glitchy SMs (like GNOME-1)
7028 */
7029 if (!cancel_shutdown)
7030 {
7031 xsmp.save_yourself = False;
7032 SmcSaveYourselfDone(smc_conn, True);
7033 }
7034}
7035# endif
7036
7037/*
7038 * Callback that starts save-yourself.
7039 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007040 static void
7041xsmp_handle_save_yourself(smc_conn, client_data, save_type,
7042 shutdown, interact_style, fast)
7043 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007044 SmPointer client_data UNUSED;
7045 int save_type UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007046 Bool shutdown;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007047 int interact_style UNUSED;
7048 Bool fast UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007049{
7050 /* Handle already being in saveyourself */
7051 if (xsmp.save_yourself)
7052 SmcSaveYourselfDone(smc_conn, True);
7053 xsmp.save_yourself = True;
7054 xsmp.shutdown = shutdown;
7055
7056 /* First up, preserve all files */
7057 out_flush();
7058 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
7059
7060 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007061 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007062
7063# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7064 /* Now see if we can ask about unsaved files */
7065 if (shutdown && !fast && gui.in_use)
7066 /* Need to interact with user, but need SM's permission */
7067 SmcInteractRequest(smc_conn, SmDialogError,
7068 xsmp_handle_interaction, client_data);
7069 else
7070# endif
7071 {
7072 /* Can stop the cycle here */
7073 SmcSaveYourselfDone(smc_conn, True);
7074 xsmp.save_yourself = False;
7075 }
7076}
7077
7078
7079/*
7080 * Callback to warn us of imminent death.
7081 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007082 static void
7083xsmp_die(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007084 SmcConn smc_conn UNUSED;
7085 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007086{
7087 xsmp_close();
7088
7089 /* quit quickly leaving swapfiles for modified buffers behind */
7090 getout_preserve_modified(0);
7091}
7092
7093
7094/*
7095 * Callback to tell us that save-yourself has completed.
7096 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007097 static void
7098xsmp_save_complete(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007099 SmcConn smc_conn UNUSED;
7100 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007101{
7102 xsmp.save_yourself = False;
7103}
7104
7105
7106/*
7107 * Callback to tell us that an instigated shutdown was cancelled
7108 * (maybe even by us)
7109 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007110 static void
7111xsmp_shutdown_cancelled(smc_conn, client_data)
7112 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007113 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007114{
7115 if (xsmp.save_yourself)
7116 SmcSaveYourselfDone(smc_conn, True);
7117 xsmp.save_yourself = False;
7118 xsmp.shutdown = False;
7119}
7120
7121
7122/*
7123 * Callback to tell us that a new ICE connection has been established.
7124 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007125 static void
7126xsmp_ice_connection(iceConn, clientData, opening, watchData)
7127 IceConn iceConn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007128 IcePointer clientData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007129 Bool opening;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007130 IcePointer *watchData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007131{
7132 /* Intercept creation of ICE connection fd */
7133 if (opening)
7134 {
7135 xsmp_icefd = IceConnectionNumber(iceConn);
7136 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7137 }
7138}
7139
7140
7141/* Handle any ICE processing that's required; return FAIL if SM lost */
7142 int
7143xsmp_handle_requests()
7144{
7145 Bool rep;
7146
7147 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7148 == IceProcessMessagesIOError)
7149 {
7150 /* Lost ICE */
7151 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007152 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007153 xsmp_close();
7154 return FAIL;
7155 }
7156 else
7157 return OK;
7158}
7159
7160static int dummy;
7161
7162/* Set up X Session Management Protocol */
7163 void
7164xsmp_init(void)
7165{
7166 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007167 SmcCallbacks smcallbacks;
7168#if 0
7169 SmPropValue smname;
7170 SmProp smnameprop;
7171 SmProp *smprops[1];
7172#endif
7173
7174 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007175 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007176
7177 xsmp.save_yourself = xsmp.shutdown = False;
7178
7179 /* Set up SM callbacks - must have all, even if they're not used */
7180 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
7181 smcallbacks.save_yourself.client_data = NULL;
7182 smcallbacks.die.callback = xsmp_die;
7183 smcallbacks.die.client_data = NULL;
7184 smcallbacks.save_complete.callback = xsmp_save_complete;
7185 smcallbacks.save_complete.client_data = NULL;
7186 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
7187 smcallbacks.shutdown_cancelled.client_data = NULL;
7188
7189 /* Set up a watch on ICE connection creations. The "dummy" argument is
7190 * apparently required for FreeBSD (we get a BUS error when using NULL). */
7191 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
7192 {
7193 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007194 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007195 return;
7196 }
7197
7198 /* Create an SM connection */
7199 xsmp.smcconn = SmcOpenConnection(
7200 NULL,
7201 NULL,
7202 SmProtoMajor,
7203 SmProtoMinor,
7204 SmcSaveYourselfProcMask | SmcDieProcMask
7205 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
7206 &smcallbacks,
7207 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00007208 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007209 sizeof(errorstring),
7210 errorstring);
7211 if (xsmp.smcconn == NULL)
7212 {
7213 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00007214
Bram Moolenaar071d4272004-06-13 20:20:40 +00007215 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007216 {
7217 vim_snprintf(errorreport, sizeof(errorreport),
7218 _("XSMP SmcOpenConnection failed: %s"), errorstring);
7219 verb_msg((char_u *)errorreport);
7220 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007221 return;
7222 }
7223 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
7224
7225#if 0
7226 /* ID ourselves */
7227 smname.value = "vim";
7228 smname.length = 3;
7229 smnameprop.name = "SmProgram";
7230 smnameprop.type = "SmARRAY8";
7231 smnameprop.num_vals = 1;
7232 smnameprop.vals = &smname;
7233
7234 smprops[0] = &smnameprop;
7235 SmcSetProperties(xsmp.smcconn, 1, smprops);
7236#endif
7237}
7238
7239
7240/* Shut down XSMP comms. */
7241 void
7242xsmp_close()
7243{
7244 if (xsmp_icefd != -1)
7245 {
7246 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00007247 if (xsmp.clientid != NULL)
7248 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00007249 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007250 xsmp_icefd = -1;
7251 }
7252}
7253#endif /* USE_XSMP */
7254
7255
7256#ifdef EBCDIC
7257/* Translate character to its CTRL- value */
7258char CtrlTable[] =
7259{
7260/* 00 - 5E */
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, 0,
7266 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7267/* ^ */ 0x1E,
7268/* - */ 0x1F,
7269/* 61 - 6C */
7270 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7271/* _ */ 0x1F,
7272/* 6E - 80 */
7273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7274/* a */ 0x01,
7275/* b */ 0x02,
7276/* c */ 0x03,
7277/* d */ 0x37,
7278/* e */ 0x2D,
7279/* f */ 0x2E,
7280/* g */ 0x2F,
7281/* h */ 0x16,
7282/* i */ 0x05,
7283/* 8A - 90 */
7284 0, 0, 0, 0, 0, 0, 0,
7285/* j */ 0x15,
7286/* k */ 0x0B,
7287/* l */ 0x0C,
7288/* m */ 0x0D,
7289/* n */ 0x0E,
7290/* o */ 0x0F,
7291/* p */ 0x10,
7292/* q */ 0x11,
7293/* r */ 0x12,
7294/* 9A - A1 */
7295 0, 0, 0, 0, 0, 0, 0, 0,
7296/* s */ 0x13,
7297/* t */ 0x3C,
7298/* u */ 0x3D,
7299/* v */ 0x32,
7300/* w */ 0x26,
7301/* x */ 0x18,
7302/* y */ 0x19,
7303/* z */ 0x3F,
7304/* AA - AC */
7305 0, 0, 0,
7306/* [ */ 0x27,
7307/* AE - BC */
7308 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7309/* ] */ 0x1D,
7310/* BE - C0 */ 0, 0, 0,
7311/* A */ 0x01,
7312/* B */ 0x02,
7313/* C */ 0x03,
7314/* D */ 0x37,
7315/* E */ 0x2D,
7316/* F */ 0x2E,
7317/* G */ 0x2F,
7318/* H */ 0x16,
7319/* I */ 0x05,
7320/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
7321/* J */ 0x15,
7322/* K */ 0x0B,
7323/* L */ 0x0C,
7324/* M */ 0x0D,
7325/* N */ 0x0E,
7326/* O */ 0x0F,
7327/* P */ 0x10,
7328/* Q */ 0x11,
7329/* R */ 0x12,
7330/* DA - DF */ 0, 0, 0, 0, 0, 0,
7331/* \ */ 0x1C,
7332/* E1 */ 0,
7333/* S */ 0x13,
7334/* T */ 0x3C,
7335/* U */ 0x3D,
7336/* V */ 0x32,
7337/* W */ 0x26,
7338/* X */ 0x18,
7339/* Y */ 0x19,
7340/* Z */ 0x3F,
7341/* EA - FF*/ 0, 0, 0, 0, 0, 0,
7342 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7343};
7344
7345char MetaCharTable[]=
7346{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7347 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
7348 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
7349 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
7350 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
7351};
7352
7353
7354/* TODO: Use characters NOT numbers!!! */
7355char CtrlCharTable[]=
7356{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7357 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
7358 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
7359 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
7360 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
7361};
7362
7363
7364#endif