blob: bb97bbe6b19519173d2e8c2eff5d88073198cc99 [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;
135static void xterm_update __ARGS((void));
136# endif
137
138# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
139Window x11_window = 0;
140# endif
141Display *x11_display = NULL;
142
143# ifdef FEAT_TITLE
144static int get_x11_windis __ARGS((void));
145static void set_x11_title __ARGS((char_u *));
146static void set_x11_icon __ARGS((char_u *));
147# endif
148#endif
149
150#ifdef FEAT_TITLE
151static int get_x11_title __ARGS((int));
152static int get_x11_icon __ARGS((int));
153
154static char_u *oldtitle = NULL;
155static int did_set_title = FALSE;
156static char_u *oldicon = NULL;
157static int did_set_icon = FALSE;
158#endif
159
160static void may_core_dump __ARGS((void));
161
Bram Moolenaar205b8862011-09-07 15:04:31 +0200162#ifdef HAVE_UNION_WAIT
163typedef union wait waitstatus;
164#else
165typedef int waitstatus;
166#endif
Bram Moolenaar9f118812011-09-08 23:24:14 +0200167static pid_t wait4pid __ARGS((pid_t, waitstatus *));
Bram Moolenaar205b8862011-09-07 15:04:31 +0200168
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169static int WaitForChar __ARGS((long));
170#if defined(__BEOS__)
171int RealWaitForChar __ARGS((int, long, int *));
172#else
173static int RealWaitForChar __ARGS((int, long, int *));
174#endif
175
176#ifdef FEAT_XCLIPBOARD
177static int do_xterm_trace __ARGS((void));
Bram Moolenaarcf851ce2005-06-16 21:52:47 +0000178# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000179#endif
180
181static void handle_resize __ARGS((void));
182
183#if defined(SIGWINCH)
184static RETSIGTYPE sig_winch __ARGS(SIGPROTOARG);
185#endif
186#if defined(SIGINT)
187static RETSIGTYPE catch_sigint __ARGS(SIGPROTOARG);
188#endif
189#if defined(SIGPWR)
190static RETSIGTYPE catch_sigpwr __ARGS(SIGPROTOARG);
191#endif
192#if defined(SIGALRM) && defined(FEAT_X11) \
193 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
194# define SET_SIG_ALARM
195static RETSIGTYPE sig_alarm __ARGS(SIGPROTOARG);
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000196/* volatile because it is used in signal handler sig_alarm(). */
197static volatile int sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198#endif
199static RETSIGTYPE deathtrap __ARGS(SIGPROTOARG);
200
Bram Moolenaardf177f62005-02-22 08:39:57 +0000201static void catch_int_signal __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000202static void set_signals __ARGS((void));
203static void catch_signals __ARGS((RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)()));
204#ifndef __EMX__
205static int have_wildcard __ARGS((int, char_u **));
206static int have_dollars __ARGS((int, char_u **));
207#endif
208
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209#ifndef __EMX__
210static int save_patterns __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file));
211#endif
212
213#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000214# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000215#endif
216
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000217/* volatile because it is used in signal handler sig_winch(). */
218static volatile int do_resize = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000219#ifndef __EMX__
220static char_u *extra_shell_arg = NULL;
221static int show_shell_mess = TRUE;
222#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000223/* volatile because it is used in signal handler deathtrap(). */
224static volatile int deadly_signal = 0; /* The signal we caught */
225/* volatile because it is used in signal handler deathtrap(). */
226static volatile int in_mch_delay = FALSE; /* sleeping in mch_delay() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227
228static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
229
230#ifdef USE_XSMP
231typedef struct
232{
233 SmcConn smcconn; /* The SM connection ID */
234 IceConn iceconn; /* The ICE connection ID */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200235 char *clientid; /* The client ID for the current smc session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236 Bool save_yourself; /* If we're in the middle of a save_yourself */
237 Bool shutdown; /* If we're in shutdown mode */
238} xsmp_config_T;
239
240static xsmp_config_T xsmp;
241#endif
242
243#ifdef SYS_SIGLIST_DECLARED
244/*
245 * I have seen
246 * extern char *_sys_siglist[NSIG];
247 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
248 * that describe the signals. That is nearly what we want here. But
249 * autoconf does only check for sys_siglist (without the underscore), I
250 * do not want to change everything today.... jw.
251 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.in
252 */
253#endif
254
255static struct signalinfo
256{
257 int sig; /* Signal number, eg. SIGSEGV etc */
258 char *name; /* Signal name (not char_u!). */
259 char deadly; /* Catch as a deadly signal? */
260} signal_info[] =
261{
262#ifdef SIGHUP
263 {SIGHUP, "HUP", TRUE},
264#endif
265#ifdef SIGQUIT
266 {SIGQUIT, "QUIT", TRUE},
267#endif
268#ifdef SIGILL
269 {SIGILL, "ILL", TRUE},
270#endif
271#ifdef SIGTRAP
272 {SIGTRAP, "TRAP", TRUE},
273#endif
274#ifdef SIGABRT
275 {SIGABRT, "ABRT", TRUE},
276#endif
277#ifdef SIGEMT
278 {SIGEMT, "EMT", TRUE},
279#endif
280#ifdef SIGFPE
281 {SIGFPE, "FPE", TRUE},
282#endif
283#ifdef SIGBUS
284 {SIGBUS, "BUS", TRUE},
285#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100286#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
287 /* MzScheme uses SEGV in its garbage collector */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000288 {SIGSEGV, "SEGV", TRUE},
289#endif
290#ifdef SIGSYS
291 {SIGSYS, "SYS", TRUE},
292#endif
293#ifdef SIGALRM
294 {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
295#endif
296#ifdef SIGTERM
297 {SIGTERM, "TERM", TRUE},
298#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100299#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000300 {SIGVTALRM, "VTALRM", TRUE},
301#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000302#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
303 /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
304 * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 {SIGPROF, "PROF", TRUE},
306#endif
307#ifdef SIGXCPU
308 {SIGXCPU, "XCPU", TRUE},
309#endif
310#ifdef SIGXFSZ
311 {SIGXFSZ, "XFSZ", TRUE},
312#endif
313#ifdef SIGUSR1
314 {SIGUSR1, "USR1", TRUE},
315#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000316#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
317 /* Used for sysmouse handling */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000318 {SIGUSR2, "USR2", TRUE},
319#endif
320#ifdef SIGINT
321 {SIGINT, "INT", FALSE},
322#endif
323#ifdef SIGWINCH
324 {SIGWINCH, "WINCH", FALSE},
325#endif
326#ifdef SIGTSTP
327 {SIGTSTP, "TSTP", FALSE},
328#endif
329#ifdef SIGPIPE
330 {SIGPIPE, "PIPE", FALSE},
331#endif
332 {-1, "Unknown!", FALSE}
333};
334
Bram Moolenaar25724922009-07-14 15:38:41 +0000335 int
336mch_chdir(path)
337 char *path;
338{
339 if (p_verbose >= 5)
340 {
341 verbose_enter();
342 smsg((char_u *)"chdir(%s)", path);
343 verbose_leave();
344 }
345# ifdef VMS
346 return chdir(vms_fixfilename(path));
347# else
348 return chdir(path);
349# endif
350}
351
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000352/*
353 * Write s[len] to the screen.
354 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000355 void
356mch_write(s, len)
357 char_u *s;
358 int len;
359{
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000360 ignored = (int)write(1, (char *)s, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000361 if (p_wd) /* Unix is too fast, slow down a bit more */
362 RealWaitForChar(read_cmd_fd, p_wd, NULL);
363}
364
365/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000366 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000367 * Get a characters from the keyboard.
368 * Return the number of characters that are available.
369 * If wtime == 0 do not wait for characters.
370 * If wtime == n wait a short time for characters.
371 * If wtime == -1 wait forever for characters.
372 */
373 int
374mch_inchar(buf, maxlen, wtime, tb_change_cnt)
375 char_u *buf;
376 int maxlen;
377 long wtime; /* don't use "time", MIPS cannot handle it */
378 int tb_change_cnt;
379{
380 int len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000381
Bram Moolenaar67c53842010-05-22 18:28:27 +0200382#ifdef FEAT_NETBEANS_INTG
383 /* Process the queued netbeans messages. */
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200384 netbeans_parse_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200385#endif
386
Bram Moolenaar071d4272004-06-13 20:20:40 +0000387 /* Check if window changed size while we were busy, perhaps the ":set
388 * columns=99" command was used. */
389 while (do_resize)
390 handle_resize();
391
392 if (wtime >= 0)
393 {
394 while (WaitForChar(wtime) == 0) /* no character available */
395 {
396 if (!do_resize) /* return if not interrupted by resize */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000397 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000398 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200399#ifdef FEAT_NETBEANS_INTG
400 /* Process the queued netbeans messages. */
Bram Moolenaarcc448b32010-07-14 16:52:17 +0200401 netbeans_parse_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200402#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000403 }
404 }
405 else /* wtime == -1 */
406 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407 /*
408 * If there is no character available within 'updatetime' seconds
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000409 * flush all the swap files to disk.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410 * Also done when interrupted by SIGWINCH.
411 */
412 if (WaitForChar(p_ut) == 0)
413 {
414#ifdef FEAT_AUTOCMD
Bram Moolenaard35f9712005-12-18 22:02:33 +0000415 if (trigger_cursorhold() && maxlen >= 3
416 && !typebuf_changed(tb_change_cnt))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000417 {
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000418 buf[0] = K_SPECIAL;
419 buf[1] = KS_EXTRA;
420 buf[2] = (int)KE_CURSORHOLD;
421 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423#endif
Bram Moolenaard4098f52005-06-27 22:37:13 +0000424 before_blocking();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000425 }
426 }
427
428 for (;;) /* repeat until we got a character */
429 {
430 while (do_resize) /* window changed size */
431 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200432
433#ifdef FEAT_NETBEANS_INTG
434 /* Process the queued netbeans messages. */
Bram Moolenaarcc448b32010-07-14 16:52:17 +0200435 netbeans_parse_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200436#endif
Bram Moolenaar48bae372010-07-29 23:12:15 +0200437#ifndef VMS /* VMS: must try reading, WaitForChar() does nothing. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000438 /*
Bram Moolenaar48bae372010-07-29 23:12:15 +0200439 * We want to be interrupted by the winch signal
440 * or by an event on the monitored file descriptors.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200442 if (WaitForChar(-1L) == 0)
443 {
444 if (do_resize) /* interrupted by SIGWINCH signal */
445 handle_resize();
446 return 0;
447 }
Bram Moolenaar48bae372010-07-29 23:12:15 +0200448#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000449
450 /* If input was put directly in typeahead buffer bail out here. */
451 if (typebuf_changed(tb_change_cnt))
452 return 0;
453
454 /*
455 * For some terminals we only get one character at a time.
456 * We want the get all available characters, so we could keep on
457 * trying until none is available
458 * For some other terminals this is quite slow, that's why we don't do
459 * it.
460 */
461 len = read_from_input_buf(buf, (long)maxlen);
462 if (len > 0)
463 {
464#ifdef OS2
465 int i;
466
467 for (i = 0; i < len; i++)
468 if (buf[i] == 0)
469 buf[i] = K_NUL;
470#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000471 return len;
472 }
473 }
474}
475
476 static void
477handle_resize()
478{
479 do_resize = FALSE;
480 shell_resized();
481}
482
483/*
484 * return non-zero if a character is available
485 */
486 int
487mch_char_avail()
488{
489 return WaitForChar(0L);
490}
491
492#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
493# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000494# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000495# endif
496# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
497# include <sys/sysctl.h>
498# endif
499# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
500# include <sys/sysinfo.h>
501# endif
502
503/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000504 * Return total amount of memory available in Kbyte.
505 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507 long_u
508mch_total_mem(special)
Bram Moolenaar78a15312009-05-15 19:33:18 +0000509 int special UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510{
511# ifdef __EMX__
Bram Moolenaar914572a2007-05-01 11:37:47 +0000512 return ulimit(3, 0L) >> 10; /* always 32MB? */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513# else
514 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000515 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000516
517# ifdef HAVE_SYSCTL
518 int mib[2], physmem;
519 size_t len;
520
521 /* BSD way of getting the amount of RAM available. */
522 mib[0] = CTL_HW;
523 mib[1] = HW_USERMEM;
524 len = sizeof(physmem);
525 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
526 mem = (long_u)physmem;
527# endif
528
529# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
530 if (mem == 0)
531 {
532 struct sysinfo sinfo;
533
534 /* Linux way of getting amount of RAM available */
535 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000536 {
537# ifdef HAVE_SYSINFO_MEM_UNIT
538 /* avoid overflow as much as possible */
539 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
540 {
541 sinfo.mem_unit = sinfo.mem_unit >> 1;
542 --shiftright;
543 }
544 mem = sinfo.totalram * sinfo.mem_unit;
545# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546 mem = sinfo.totalram;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000547# endif
548 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549 }
550# endif
551
552# ifdef HAVE_SYSCONF
553 if (mem == 0)
554 {
555 long pagesize, pagecount;
556
557 /* Solaris way of getting amount of RAM available */
558 pagesize = sysconf(_SC_PAGESIZE);
559 pagecount = sysconf(_SC_PHYS_PAGES);
560 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000561 {
562 /* avoid overflow as much as possible */
563 while (shiftright > 0 && (pagesize & 1) == 0)
564 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000565 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000566 --shiftright;
567 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000569 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 }
571# endif
572
573 /* Return the minimum of the physical memory and the user limit, because
574 * using more than the user limit may cause Vim to be terminated. */
575# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
576 {
577 struct rlimit rlp;
578
579 if (getrlimit(RLIMIT_DATA, &rlp) == 0
580 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
581# ifdef RLIM_INFINITY
582 && rlp.rlim_cur != RLIM_INFINITY
583# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000584 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000585 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000586 {
587 mem = (long_u)rlp.rlim_cur;
588 shiftright = 10;
589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000590 }
591# endif
592
593 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000594 return mem >> shiftright;
595 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596# endif
597}
598#endif
599
600 void
601mch_delay(msec, ignoreinput)
602 long msec;
603 int ignoreinput;
604{
605 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000606#ifdef FEAT_MZSCHEME
607 long total = msec; /* remember original value */
608#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609
610 if (ignoreinput)
611 {
612 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000613 * here. But we don't want QUIT to kill us (CTRL-\ used in a
614 * shell may produce SIGQUIT). */
615 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000616 old_tmode = curr_tmode;
617 if (curr_tmode == TMODE_RAW)
618 settmode(TMODE_SLEEP);
619
620 /*
621 * Everybody sleeps in a different way...
622 * Prefer nanosleep(), some versions of usleep() can only sleep up to
623 * one second.
624 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000625#ifdef FEAT_MZSCHEME
626 do
627 {
628 /* if total is large enough, wait by portions in p_mzq */
629 if (total > p_mzq)
630 msec = p_mzq;
631 else
632 msec = total;
633 total -= msec;
634#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635#ifdef HAVE_NANOSLEEP
636 {
637 struct timespec ts;
638
639 ts.tv_sec = msec / 1000;
640 ts.tv_nsec = (msec % 1000) * 1000000;
641 (void)nanosleep(&ts, NULL);
642 }
643#else
644# ifdef HAVE_USLEEP
645 while (msec >= 1000)
646 {
647 usleep((unsigned int)(999 * 1000));
648 msec -= 999;
649 }
650 usleep((unsigned int)(msec * 1000));
651# else
652# ifndef HAVE_SELECT
653 poll(NULL, 0, (int)msec);
654# else
655# ifdef __EMX__
656 _sleep2(msec);
657# else
658 {
659 struct timeval tv;
660
661 tv.tv_sec = msec / 1000;
662 tv.tv_usec = (msec % 1000) * 1000;
663 /*
664 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
665 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
666 */
667 select(0, NULL, NULL, NULL, &tv);
668 }
669# endif /* __EMX__ */
670# endif /* HAVE_SELECT */
671# endif /* HAVE_NANOSLEEP */
672#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000673#ifdef FEAT_MZSCHEME
674 }
675 while (total > 0);
676#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677
678 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000679 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680 }
681 else
682 WaitForChar(msec);
683}
684
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000685#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000686 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
687# define HAVE_CHECK_STACK_GROWTH
688/*
689 * Support for checking for an almost-out-of-stack-space situation.
690 */
691
692/*
693 * Return a pointer to an item on the stack. Used to find out if the stack
694 * grows up or down.
695 */
696static void check_stack_growth __ARGS((char *p));
697static int stack_grows_downwards;
698
699/*
700 * Find out if the stack grows upwards or downwards.
701 * "p" points to a variable on the stack of the caller.
702 */
703 static void
704check_stack_growth(p)
705 char *p;
706{
707 int i;
708
709 stack_grows_downwards = (p > (char *)&i);
710}
711#endif
712
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000713#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000714static char *stack_limit = NULL;
715
716#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
717# include <pthread.h>
718# include <pthread_np.h>
719#endif
720
721/*
722 * Find out until how var the stack can grow without getting into trouble.
723 * Called when starting up and when switching to the signal stack in
724 * deathtrap().
725 */
726 static void
727get_stack_limit()
728{
729 struct rlimit rlp;
730 int i;
731 long lim;
732
733 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
734 * limit doesn't fit in a long (rlim_cur might be "long long"). */
735 if (getrlimit(RLIMIT_STACK, &rlp) == 0
736 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
737# ifdef RLIM_INFINITY
738 && rlp.rlim_cur != RLIM_INFINITY
739# endif
740 )
741 {
742 lim = (long)rlp.rlim_cur;
743#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
744 {
745 pthread_attr_t attr;
746 size_t size;
747
748 /* On FreeBSD the initial thread always has a fixed stack size, no
749 * matter what the limits are set to. Normally it's 1 Mbyte. */
750 pthread_attr_init(&attr);
751 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
752 {
753 pthread_attr_getstacksize(&attr, &size);
754 if (lim > (long)size)
755 lim = (long)size;
756 }
757 pthread_attr_destroy(&attr);
758 }
759#endif
760 if (stack_grows_downwards)
761 {
762 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
763 if (stack_limit >= (char *)&i)
764 /* overflow, set to 1/16 of current stack position */
765 stack_limit = (char *)((long)&i / 16L);
766 }
767 else
768 {
769 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
770 if (stack_limit <= (char *)&i)
771 stack_limit = NULL; /* overflow */
772 }
773 }
774}
775
776/*
777 * Return FAIL when running out of stack space.
778 * "p" must point to any variable local to the caller that's on the stack.
779 */
780 int
781mch_stackcheck(p)
782 char *p;
783{
784 if (stack_limit != NULL)
785 {
786 if (stack_grows_downwards)
787 {
788 if (p < stack_limit)
789 return FAIL;
790 }
791 else if (p > stack_limit)
792 return FAIL;
793 }
794 return OK;
795}
796#endif
797
798#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
799/*
800 * Support for using the signal stack.
801 * This helps when we run out of stack space, which causes a SIGSEGV. The
802 * signal handler then must run on another stack, since the normal stack is
803 * completely full.
804 */
805
806#ifndef SIGSTKSZ
807# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
808#endif
809
810# ifdef HAVE_SIGALTSTACK
811static stack_t sigstk; /* for sigaltstack() */
812# else
813static struct sigstack sigstk; /* for sigstack() */
814# endif
815
816static void init_signal_stack __ARGS((void));
817static char *signal_stack;
818
819 static void
820init_signal_stack()
821{
822 if (signal_stack != NULL)
823 {
824# ifdef HAVE_SIGALTSTACK
Bram Moolenaar1a3d0862007-08-30 09:47:38 +0000825# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
826 || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000827 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
828 * "struct sigaltstack" needs to be declared. */
829 extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
830# endif
831
832# ifdef HAVE_SS_BASE
833 sigstk.ss_base = signal_stack;
834# else
835 sigstk.ss_sp = signal_stack;
836# endif
837 sigstk.ss_size = SIGSTKSZ;
838 sigstk.ss_flags = 0;
839 (void)sigaltstack(&sigstk, NULL);
840# else
841 sigstk.ss_sp = signal_stack;
842 if (stack_grows_downwards)
843 sigstk.ss_sp += SIGSTKSZ - 1;
844 sigstk.ss_onstack = 0;
845 (void)sigstack(&sigstk, NULL);
846# endif
847 }
848}
849#endif
850
851/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000852 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853 * will barf when the second argument to signal() is ``wrong''.
854 * Let me try it with a few tricky defines from my own osdef.h (jw).
855 */
856#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857 static RETSIGTYPE
858sig_winch SIGDEFARG(sigarg)
859{
860 /* this is not required on all systems, but it doesn't hurt anybody */
861 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
862 do_resize = TRUE;
863 SIGRETURN;
864}
865#endif
866
867#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000868 static RETSIGTYPE
869catch_sigint SIGDEFARG(sigarg)
870{
871 /* this is not required on all systems, but it doesn't hurt anybody */
872 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
873 got_int = TRUE;
874 SIGRETURN;
875}
876#endif
877
878#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000879 static RETSIGTYPE
880catch_sigpwr SIGDEFARG(sigarg)
881{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000882 /* this is not required on all systems, but it doesn't hurt anybody */
883 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 /*
885 * I'm not sure we get the SIGPWR signal when the system is really going
886 * down or when the batteries are almost empty. Just preserve the swap
887 * files and don't exit, that can't do any harm.
888 */
889 ml_sync_all(FALSE, FALSE);
890 SIGRETURN;
891}
892#endif
893
894#ifdef SET_SIG_ALARM
895/*
896 * signal function for alarm().
897 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000898 static RETSIGTYPE
899sig_alarm SIGDEFARG(sigarg)
900{
901 /* doesn't do anything, just to break a system call */
902 sig_alarm_called = TRUE;
903 SIGRETURN;
904}
905#endif
906
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000907#if (defined(HAVE_SETJMP_H) \
908 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
909 || defined(FEAT_LIBCALL))) \
910 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000911/*
912 * A simplistic version of setjmp() that only allows one level of using.
913 * Don't call twice before calling mch_endjmp()!.
914 * Usage:
915 * mch_startjmp();
916 * if (SETJMP(lc_jump_env) != 0)
917 * {
918 * mch_didjmp();
919 * EMSG("crash!");
920 * }
921 * else
922 * {
923 * do_the_work;
924 * mch_endjmp();
925 * }
926 * Note: Can't move SETJMP() here, because a function calling setjmp() must
927 * not return before the saved environment is used.
928 * Returns OK for normal return, FAIL when the protected code caused a
929 * problem and LONGJMP() was used.
930 */
931 void
932mch_startjmp()
933{
934#ifdef SIGHASARG
935 lc_signal = 0;
936#endif
937 lc_active = TRUE;
938}
939
940 void
941mch_endjmp()
942{
943 lc_active = FALSE;
944}
945
946 void
947mch_didjmp()
948{
949# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
950 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
951 * otherwise catching the signal only works once. */
952 init_signal_stack();
953# endif
954}
955#endif
956
957/*
958 * This function handles deadly signals.
959 * It tries to preserve any swap file and exit properly.
960 * (partly from Elvis).
961 */
962 static RETSIGTYPE
963deathtrap SIGDEFARG(sigarg)
964{
965 static int entered = 0; /* count the number of times we got here.
966 Note: when memory has been corrupted
967 this may get an arbitrary value! */
968#ifdef SIGHASARG
969 int i;
970#endif
971
972#if defined(HAVE_SETJMP_H)
973 /*
974 * Catch a crash in protected code.
975 * Restores the environment saved in lc_jump_env, which looks like
976 * SETJMP() returns 1.
977 */
978 if (lc_active)
979 {
980# if defined(SIGHASARG)
981 lc_signal = sigarg;
982# endif
983 lc_active = FALSE; /* don't jump again */
984 LONGJMP(lc_jump_env, 1);
985 /* NOTREACHED */
986 }
987#endif
988
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000989#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000990# ifdef SIGQUIT
991 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
992 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
993 * pressing CTRL-\, but we don't want Vim to exit then. */
994 if (in_mch_delay && sigarg == SIGQUIT)
995 SIGRETURN;
996# endif
997
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000998 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
999 * here. This avoids that a non-reentrant function is interrupted, e.g.,
1000 * free(). Calling free() again may then cause a crash. */
1001 if (entered == 0
1002 && (0
1003# ifdef SIGHUP
1004 || sigarg == SIGHUP
1005# endif
1006# ifdef SIGQUIT
1007 || sigarg == SIGQUIT
1008# endif
1009# ifdef SIGTERM
1010 || sigarg == SIGTERM
1011# endif
1012# ifdef SIGPWR
1013 || sigarg == SIGPWR
1014# endif
1015# ifdef SIGUSR1
1016 || sigarg == SIGUSR1
1017# endif
1018# ifdef SIGUSR2
1019 || sigarg == SIGUSR2
1020# endif
1021 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001022 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001023 SIGRETURN;
1024#endif
1025
Bram Moolenaar071d4272004-06-13 20:20:40 +00001026 /* Remember how often we have been called. */
1027 ++entered;
1028
1029#ifdef FEAT_EVAL
1030 /* Set the v:dying variable. */
1031 set_vim_var_nr(VV_DYING, (long)entered);
1032#endif
1033
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001034#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001035 /* Since we are now using the signal stack, need to reset the stack
1036 * limit. Otherwise using a regexp will fail. */
1037 get_stack_limit();
1038#endif
1039
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001040#if 0
1041 /* This is for opening gdb the moment Vim crashes.
1042 * You need to manually adjust the file name and Vim executable name.
1043 * Suggested by SungHyun Nam. */
1044 {
1045# define VI_GDB_FILE "/tmp/vimgdb"
1046# define VIM_NAME "/usr/bin/vim"
1047 FILE *fp = fopen(VI_GDB_FILE, "w");
1048 if (fp)
1049 {
1050 fprintf(fp,
1051 "file %s\n"
1052 "attach %d\n"
1053 "set height 1000\n"
1054 "bt full\n"
1055 , VIM_NAME, getpid());
1056 fclose(fp);
1057 system("xterm -e gdb -x "VI_GDB_FILE);
1058 unlink(VI_GDB_FILE);
1059 }
1060 }
1061#endif
1062
Bram Moolenaar071d4272004-06-13 20:20:40 +00001063#ifdef SIGHASARG
1064 /* try to find the name of this signal */
1065 for (i = 0; signal_info[i].sig != -1; i++)
1066 if (sigarg == signal_info[i].sig)
1067 break;
1068 deadly_signal = sigarg;
1069#endif
1070
1071 full_screen = FALSE; /* don't write message to the GUI, it might be
1072 * part of the problem... */
1073 /*
1074 * If something goes wrong after entering here, we may get here again.
1075 * When this happens, give a message and try to exit nicely (resetting the
1076 * terminal mode, etc.)
1077 * When this happens twice, just exit, don't even try to give a message,
1078 * stack may be corrupt or something weird.
1079 * When this still happens again (or memory was corrupted in such a way
1080 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1081 */
1082 if (entered >= 3)
1083 {
1084 reset_signals(); /* don't catch any signals anymore */
1085 may_core_dump();
1086 if (entered >= 4)
1087 _exit(8);
1088 exit(7);
1089 }
1090 if (entered == 2)
1091 {
1092 OUT_STR(_("Vim: Double signal, exiting\n"));
1093 out_flush();
1094 getout(1);
1095 }
1096
1097#ifdef SIGHASARG
1098 sprintf((char *)IObuff, _("Vim: Caught deadly signal %s\n"),
1099 signal_info[i].name);
1100#else
1101 sprintf((char *)IObuff, _("Vim: Caught deadly signal\n"));
1102#endif
1103 preserve_exit(); /* preserve files and exit */
1104
Bram Moolenaar009b2592004-10-24 19:18:58 +00001105#ifdef NBDEBUG
1106 reset_signals();
1107 may_core_dump();
1108 abort();
1109#endif
1110
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 SIGRETURN;
1112}
1113
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001114#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001115/*
1116 * On Solaris with multi-threading, suspending might not work immediately.
1117 * Catch the SIGCONT signal, which will be used as an indication whether the
1118 * suspending has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001119 *
1120 * On Linux, signal is not always handled immediately either.
1121 * See https://bugs.launchpad.net/bugs/291373
1122 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001123 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001124 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001125static volatile int sigcont_received;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1127
1128/*
1129 * signal handler for SIGCONT
1130 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001131 static RETSIGTYPE
1132sigcont_handler SIGDEFARG(sigarg)
1133{
1134 sigcont_received = TRUE;
1135 SIGRETURN;
1136}
1137#endif
1138
Bram Moolenaar62b42182010-09-21 22:09:37 +02001139# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1140static void loose_clipboard __ARGS((void));
1141
1142/*
1143 * Called when Vim is going to sleep or execute a shell command.
1144 * We can't respond to requests for the X selections. Lose them, otherwise
1145 * other applications will hang. But first copy the text to cut buffer 0.
1146 */
1147 static void
1148loose_clipboard()
1149{
1150 if (clip_star.owned || clip_plus.owned)
1151 {
1152 x11_export_final_selection();
1153 if (clip_star.owned)
1154 clip_lose_selection(&clip_star);
1155 if (clip_plus.owned)
1156 clip_lose_selection(&clip_plus);
1157 if (x11_display != NULL)
1158 XFlush(x11_display);
1159 }
1160}
1161#endif
1162
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163/*
1164 * If the machine has job control, use it to suspend the program,
1165 * otherwise fake it by starting a new shell.
1166 */
1167 void
1168mch_suspend()
1169{
1170 /* BeOS does have SIGTSTP, but it doesn't work. */
1171#if defined(SIGTSTP) && !defined(__BEOS__)
1172 out_flush(); /* needed to make cursor visible on some systems */
1173 settmode(TMODE_COOK);
1174 out_flush(); /* needed to disable mouse on some systems */
1175
1176# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001177 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001178# endif
1179
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001180# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181 sigcont_received = FALSE;
1182# endif
1183 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001184# if defined(_REENTRANT) && defined(SIGCONT)
1185 /*
1186 * Wait for the SIGCONT signal to be handled. It generally happens
1187 * immediately, but somehow not all the time. Do not call pause()
1188 * because there would be race condition which would hang Vim if
1189 * signal happened in between the test of sigcont_received and the
1190 * call to pause(). If signal is not yet received, call sleep(0)
1191 * to just yield CPU. Signal should then be received. If somehow
1192 * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
1193 * further if signal is not received after 1+2+3+4 ms (not expected
1194 * to happen).
1195 */
1196 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001197 long wait_time;
1198 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001199 /* Loop is not entered most of the time */
Bram Moolenaar262735e2009-07-14 10:20:22 +00001200 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001201 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202# endif
1203
1204# ifdef FEAT_TITLE
1205 /*
1206 * Set oldtitle to NULL, so the current title is obtained again.
1207 */
1208 vim_free(oldtitle);
1209 oldtitle = NULL;
1210# endif
1211 settmode(TMODE_RAW);
1212 need_check_timestamps = TRUE;
1213 did_check_timestamps = FALSE;
1214#else
1215 suspend_shell();
1216#endif
1217}
1218
1219 void
1220mch_init()
1221{
1222 Columns = 80;
1223 Rows = 24;
1224
1225 out_flush();
1226 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001227
Bram Moolenaar56718732006-03-15 22:53:57 +00001228#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001229 mac_conv_init();
1230#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001231#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1232 win_clip_init();
1233#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001234}
1235
1236 static void
1237set_signals()
1238{
1239#if defined(SIGWINCH)
1240 /*
1241 * WINDOW CHANGE signal is handled with sig_winch().
1242 */
1243 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1244#endif
1245
1246 /*
1247 * We want the STOP signal to work, to make mch_suspend() work.
1248 * For "rvim" the STOP signal is ignored.
1249 */
1250#ifdef SIGTSTP
1251 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1252#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001253#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001254 signal(SIGCONT, sigcont_handler);
1255#endif
1256
1257 /*
1258 * We want to ignore breaking of PIPEs.
1259 */
1260#ifdef SIGPIPE
1261 signal(SIGPIPE, SIG_IGN);
1262#endif
1263
Bram Moolenaar071d4272004-06-13 20:20:40 +00001264#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001265 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001266#endif
1267
1268 /*
1269 * Ignore alarm signals (Perl's alarm() generates it).
1270 */
1271#ifdef SIGALRM
1272 signal(SIGALRM, SIG_IGN);
1273#endif
1274
1275 /*
1276 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1277 * work will be lost.
1278 */
1279#ifdef SIGPWR
1280 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1281#endif
1282
1283 /*
1284 * Arrange for other signals to gracefully shutdown Vim.
1285 */
1286 catch_signals(deathtrap, SIG_ERR);
1287
1288#if defined(FEAT_GUI) && defined(SIGHUP)
1289 /*
1290 * When the GUI is running, ignore the hangup signal.
1291 */
1292 if (gui.in_use)
1293 signal(SIGHUP, SIG_IGN);
1294#endif
1295}
1296
Bram Moolenaardf177f62005-02-22 08:39:57 +00001297#if defined(SIGINT) || defined(PROTO)
1298/*
1299 * Catch CTRL-C (only works while in Cooked mode).
1300 */
1301 static void
1302catch_int_signal()
1303{
1304 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1305}
1306#endif
1307
Bram Moolenaar071d4272004-06-13 20:20:40 +00001308 void
1309reset_signals()
1310{
1311 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001312#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313 /* SIGCONT isn't in the list, because its default action is ignore */
1314 signal(SIGCONT, SIG_DFL);
1315#endif
1316}
1317
1318 static void
1319catch_signals(func_deadly, func_other)
1320 RETSIGTYPE (*func_deadly)();
1321 RETSIGTYPE (*func_other)();
1322{
1323 int i;
1324
1325 for (i = 0; signal_info[i].sig != -1; i++)
1326 if (signal_info[i].deadly)
1327 {
1328#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1329 struct sigaction sa;
1330
1331 /* Setup to use the alternate stack for the signal function. */
1332 sa.sa_handler = func_deadly;
1333 sigemptyset(&sa.sa_mask);
1334# if defined(__linux__) && defined(_REENTRANT)
1335 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1336 * thread handling in combination with using the alternate stack:
1337 * pthread library functions try to use the stack pointer to
1338 * identify the current thread, causing a SEGV signal, which
1339 * recursively calls deathtrap() and hangs. */
1340 sa.sa_flags = 0;
1341# else
1342 sa.sa_flags = SA_ONSTACK;
1343# endif
1344 sigaction(signal_info[i].sig, &sa, NULL);
1345#else
1346# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1347 struct sigvec sv;
1348
1349 /* Setup to use the alternate stack for the signal function. */
1350 sv.sv_handler = func_deadly;
1351 sv.sv_mask = 0;
1352 sv.sv_flags = SV_ONSTACK;
1353 sigvec(signal_info[i].sig, &sv, NULL);
1354# else
1355 signal(signal_info[i].sig, func_deadly);
1356# endif
1357#endif
1358 }
1359 else if (func_other != SIG_ERR)
1360 signal(signal_info[i].sig, func_other);
1361}
1362
1363/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001364 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001365 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1366 * return TRUE
1367 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1368 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001369 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001370 * Returns TRUE when Vim should exit.
1371 */
1372 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001373vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001374 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001375{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001376 static int got_signal = 0;
1377 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001378
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001379 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001380 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001381 case SIGNAL_BLOCK: blocked = TRUE;
1382 break;
1383
1384 case SIGNAL_UNBLOCK: blocked = FALSE;
1385 if (got_signal != 0)
1386 {
1387 kill(getpid(), got_signal);
1388 got_signal = 0;
1389 }
1390 break;
1391
1392 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001393 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001394 got_signal = sig;
1395#ifdef SIGPWR
1396 if (sig != SIGPWR)
1397#endif
1398 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001399 break;
1400 }
1401 return FALSE;
1402}
1403
1404/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001405 * Check_win checks whether we have an interactive stdout.
1406 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001407 int
1408mch_check_win(argc, argv)
Bram Moolenaar78a15312009-05-15 19:33:18 +00001409 int argc UNUSED;
1410 char **argv UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001411{
1412#ifdef OS2
1413 /*
1414 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1415 * name, mostly it's just "vim" and found in the path, which is unusable.
1416 */
1417 if (mch_isFullName(argv[0]))
1418 exe_name = vim_strsave((char_u *)argv[0]);
1419#endif
1420 if (isatty(1))
1421 return OK;
1422 return FAIL;
1423}
1424
1425/*
1426 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1427 */
1428 int
1429mch_input_isatty()
1430{
1431 if (isatty(read_cmd_fd))
1432 return TRUE;
1433 return FALSE;
1434}
1435
1436#ifdef FEAT_X11
1437
1438# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1439 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1440
1441static void xopen_message __ARGS((struct timeval *tvp));
1442
1443/*
1444 * Give a message about the elapsed time for opening the X window.
1445 */
1446 static void
1447xopen_message(tvp)
1448 struct timeval *tvp; /* must contain start time */
1449{
1450 struct timeval end_tv;
1451
1452 /* Compute elapsed time. */
1453 gettimeofday(&end_tv, NULL);
1454 smsg((char_u *)_("Opening the X display took %ld msec"),
1455 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001456 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001457}
1458# endif
1459#endif
1460
1461#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1462/*
1463 * A few functions shared by X11 title and clipboard code.
1464 */
1465static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1466static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1467static int x_connect_to_server __ARGS((void));
1468static int test_x11_window __ARGS((Display *dpy));
1469
1470static int got_x_error = FALSE;
1471
1472/*
1473 * X Error handler, otherwise X just exits! (very rude) -- webb
1474 */
1475 static int
1476x_error_handler(dpy, error_event)
1477 Display *dpy;
1478 XErrorEvent *error_event;
1479{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001480 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001481 STRCAT(IObuff, _("\nVim: Got X error\n"));
1482
1483 /* We cannot print a message and continue, because no X calls are allowed
1484 * here (causes my system to hang). Silently continuing might be an
1485 * alternative... */
1486 preserve_exit(); /* preserve files and exit */
1487
1488 return 0; /* NOTREACHED */
1489}
1490
1491/*
1492 * Another X Error handler, just used to check for errors.
1493 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001494 static int
1495x_error_check(dpy, error_event)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001496 Display *dpy UNUSED;
1497 XErrorEvent *error_event UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498{
1499 got_x_error = TRUE;
1500 return 0;
1501}
1502
1503#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1504# if defined(HAVE_SETJMP_H)
1505/*
1506 * An X IO Error handler, used to catch error while opening the display.
1507 */
1508static int x_IOerror_check __ARGS((Display *dpy));
1509
Bram Moolenaar071d4272004-06-13 20:20:40 +00001510 static int
1511x_IOerror_check(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001512 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001513{
1514 /* This function should not return, it causes exit(). Longjump instead. */
1515 LONGJMP(lc_jump_env, 1);
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001516# ifdef VMS
1517 return 0; /* avoid the compiler complains about missing return value */
1518# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001519}
1520# endif
1521
1522/*
1523 * An X IO Error handler, used to catch terminal errors.
1524 */
1525static int x_IOerror_handler __ARGS((Display *dpy));
1526
Bram Moolenaar071d4272004-06-13 20:20:40 +00001527 static int
1528x_IOerror_handler(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001529 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001530{
1531 xterm_dpy = NULL;
1532 x11_window = 0;
1533 x11_display = NULL;
1534 xterm_Shell = (Widget)0;
1535
1536 /* This function should not return, it causes exit(). Longjump instead. */
1537 LONGJMP(x_jump_env, 1);
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001538# ifdef VMS
1539 return 0; /* avoid the compiler complains about missing return value */
1540# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541}
1542#endif
1543
1544/*
1545 * Return TRUE when connection to the X server is desired.
1546 */
1547 static int
1548x_connect_to_server()
1549{
1550 regmatch_T regmatch;
1551
1552#if defined(FEAT_CLIENTSERVER)
1553 if (x_force_connect)
1554 return TRUE;
1555#endif
1556 if (x_no_connect)
1557 return FALSE;
1558
1559 /* Check for a match with "exclude:" from 'clipboard'. */
1560 if (clip_exclude_prog != NULL)
1561 {
1562 regmatch.rm_ic = FALSE; /* Don't ignore case */
1563 regmatch.regprog = clip_exclude_prog;
1564 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1565 return FALSE;
1566 }
1567 return TRUE;
1568}
1569
1570/*
1571 * Test if "dpy" and x11_window are valid by getting the window title.
1572 * I don't actually want it yet, so there may be a simpler call to use, but
1573 * this will cause the error handler x_error_check() to be called if anything
1574 * is wrong, such as the window pointer being invalid (as can happen when the
1575 * user changes his DISPLAY, but not his WINDOWID) -- webb
1576 */
1577 static int
1578test_x11_window(dpy)
1579 Display *dpy;
1580{
1581 int (*old_handler)();
1582 XTextProperty text_prop;
1583
1584 old_handler = XSetErrorHandler(x_error_check);
1585 got_x_error = FALSE;
1586 if (XGetWMName(dpy, x11_window, &text_prop))
1587 XFree((void *)text_prop.value);
1588 XSync(dpy, False);
1589 (void)XSetErrorHandler(old_handler);
1590
1591 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001592 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593
1594 return (got_x_error ? FAIL : OK);
1595}
1596#endif
1597
1598#ifdef FEAT_TITLE
1599
1600#ifdef FEAT_X11
1601
1602static int get_x11_thing __ARGS((int get_title, int test_only));
1603
1604/*
1605 * try to get x11 window and display
1606 *
1607 * return FAIL for failure, OK otherwise
1608 */
1609 static int
1610get_x11_windis()
1611{
1612 char *winid;
1613 static int result = -1;
1614#define XD_NONE 0 /* x11_display not set here */
1615#define XD_HERE 1 /* x11_display opened here */
1616#define XD_GUI 2 /* x11_display used from gui.dpy */
1617#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1618 static int x11_display_from = XD_NONE;
1619 static int did_set_error_handler = FALSE;
1620
1621 if (!did_set_error_handler)
1622 {
1623 /* X just exits if it finds an error otherwise! */
1624 (void)XSetErrorHandler(x_error_handler);
1625 did_set_error_handler = TRUE;
1626 }
1627
Bram Moolenaar9372a112005-12-06 19:59:18 +00001628#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001629 if (gui.in_use)
1630 {
1631 /*
1632 * If the X11 display was opened here before, for the window where Vim
1633 * was started, close that one now to avoid a memory leak.
1634 */
1635 if (x11_display_from == XD_HERE && x11_display != NULL)
1636 {
1637 XCloseDisplay(x11_display);
1638 x11_display_from = XD_NONE;
1639 }
1640 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1641 {
1642 x11_display_from = XD_GUI;
1643 return OK;
1644 }
1645 x11_display = NULL;
1646 return FAIL;
1647 }
1648 else if (x11_display_from == XD_GUI)
1649 {
1650 /* GUI must have stopped somehow, clear x11_display */
1651 x11_window = 0;
1652 x11_display = NULL;
1653 x11_display_from = XD_NONE;
1654 }
1655#endif
1656
1657 /* When started with the "-X" argument, don't try connecting. */
1658 if (!x_connect_to_server())
1659 return FAIL;
1660
1661 /*
1662 * If WINDOWID not set, should try another method to find out
1663 * what the current window number is. The only code I know for
1664 * this is very complicated.
1665 * We assume that zero is invalid for WINDOWID.
1666 */
1667 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1668 x11_window = (Window)atol(winid);
1669
1670#ifdef FEAT_XCLIPBOARD
1671 if (xterm_dpy != NULL && x11_window != 0)
1672 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001673 /* We may have checked it already, but Gnome terminal can move us to
1674 * another window, so we need to check every time. */
1675 if (x11_display_from != XD_XTERM)
1676 {
1677 /*
1678 * If the X11 display was opened here before, for the window where
1679 * Vim was started, close that one now to avoid a memory leak.
1680 */
1681 if (x11_display_from == XD_HERE && x11_display != NULL)
1682 XCloseDisplay(x11_display);
1683 x11_display = xterm_dpy;
1684 x11_display_from = XD_XTERM;
1685 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001686 if (test_x11_window(x11_display) == FAIL)
1687 {
1688 /* probably bad $WINDOWID */
1689 x11_window = 0;
1690 x11_display = NULL;
1691 x11_display_from = XD_NONE;
1692 return FAIL;
1693 }
1694 return OK;
1695 }
1696#endif
1697
1698 if (x11_window == 0 || x11_display == NULL)
1699 result = -1;
1700
1701 if (result != -1) /* Have already been here and set this */
1702 return result; /* Don't do all these X calls again */
1703
1704 if (x11_window != 0 && x11_display == NULL)
1705 {
1706#ifdef SET_SIG_ALARM
1707 RETSIGTYPE (*sig_save)();
1708#endif
1709#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1710 struct timeval start_tv;
1711
1712 if (p_verbose > 0)
1713 gettimeofday(&start_tv, NULL);
1714#endif
1715
1716#ifdef SET_SIG_ALARM
1717 /*
1718 * Opening the Display may hang if the DISPLAY setting is wrong, or
1719 * the network connection is bad. Set an alarm timer to get out.
1720 */
1721 sig_alarm_called = FALSE;
1722 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1723 (RETSIGTYPE (*)())sig_alarm);
1724 alarm(2);
1725#endif
1726 x11_display = XOpenDisplay(NULL);
1727
1728#ifdef SET_SIG_ALARM
1729 alarm(0);
1730 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1731 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001732 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001733#endif
1734 if (x11_display != NULL)
1735 {
1736# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1737 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001738 {
1739 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001740 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001741 verbose_leave();
1742 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001743# endif
1744 if (test_x11_window(x11_display) == FAIL)
1745 {
1746 /* Maybe window id is bad */
1747 x11_window = 0;
1748 XCloseDisplay(x11_display);
1749 x11_display = NULL;
1750 }
1751 else
1752 x11_display_from = XD_HERE;
1753 }
1754 }
1755 if (x11_window == 0 || x11_display == NULL)
1756 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001757
1758# ifdef FEAT_EVAL
1759 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1760# endif
1761
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762 return (result = OK);
1763}
1764
1765/*
1766 * Determine original x11 Window Title
1767 */
1768 static int
1769get_x11_title(test_only)
1770 int test_only;
1771{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001772 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001773}
1774
1775/*
1776 * Determine original x11 Window icon
1777 */
1778 static int
1779get_x11_icon(test_only)
1780 int test_only;
1781{
1782 int retval = FALSE;
1783
1784 retval = get_x11_thing(FALSE, test_only);
1785
1786 /* could not get old icon, use terminal name */
1787 if (oldicon == NULL && !test_only)
1788 {
1789 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001790 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001792 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793 }
1794
1795 return retval;
1796}
1797
1798 static int
1799get_x11_thing(get_title, test_only)
1800 int get_title; /* get title string */
1801 int test_only;
1802{
1803 XTextProperty text_prop;
1804 int retval = FALSE;
1805 Status status;
1806
1807 if (get_x11_windis() == OK)
1808 {
1809 /* Get window/icon name if any */
1810 if (get_title)
1811 status = XGetWMName(x11_display, x11_window, &text_prop);
1812 else
1813 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1814
1815 /*
1816 * If terminal is xterm, then x11_window may be a child window of the
1817 * outer xterm window that actually contains the window/icon name, so
1818 * keep traversing up the tree until a window with a title/icon is
1819 * found.
1820 */
1821 /* Previously this was only done for xterm and alikes. I don't see a
1822 * reason why it would fail for other terminal emulators.
1823 * if (term_is_xterm) */
1824 {
1825 Window root;
1826 Window parent;
1827 Window win = x11_window;
1828 Window *children;
1829 unsigned int num_children;
1830
1831 while (!status || text_prop.value == NULL)
1832 {
1833 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1834 &num_children))
1835 break;
1836 if (children)
1837 XFree((void *)children);
1838 if (parent == root || parent == 0)
1839 break;
1840
1841 win = parent;
1842 if (get_title)
1843 status = XGetWMName(x11_display, win, &text_prop);
1844 else
1845 status = XGetWMIconName(x11_display, win, &text_prop);
1846 }
1847 }
1848 if (status && text_prop.value != NULL)
1849 {
1850 retval = TRUE;
1851 if (!test_only)
1852 {
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001853#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
1854 if (text_prop.encoding == XA_STRING
1855# ifdef FEAT_MBYTE
1856 && !has_mbyte
1857# endif
1858 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859 {
1860#endif
1861 if (get_title)
1862 oldtitle = vim_strsave((char_u *)text_prop.value);
1863 else
1864 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001865#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001866 }
1867 else
1868 {
1869 char **cl;
1870 Status transform_status;
1871 int n = 0;
1872
1873 transform_status = XmbTextPropertyToTextList(x11_display,
1874 &text_prop,
1875 &cl, &n);
1876 if (transform_status >= Success && n > 0 && cl[0])
1877 {
1878 if (get_title)
1879 oldtitle = vim_strsave((char_u *) cl[0]);
1880 else
1881 oldicon = vim_strsave((char_u *) cl[0]);
1882 XFreeStringList(cl);
1883 }
1884 else
1885 {
1886 if (get_title)
1887 oldtitle = vim_strsave((char_u *)text_prop.value);
1888 else
1889 oldicon = vim_strsave((char_u *)text_prop.value);
1890 }
1891 }
1892#endif
1893 }
1894 XFree((void *)text_prop.value);
1895 }
1896 }
1897 return retval;
1898}
1899
1900/* Are Xutf8 functions available? Avoid error from old compilers. */
1901#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1902# if X_HAVE_UTF8_STRING
1903# define USE_UTF8_STRING
1904# endif
1905#endif
1906
1907/*
1908 * Set x11 Window Title
1909 *
1910 * get_x11_windis() must be called before this and have returned OK
1911 */
1912 static void
1913set_x11_title(title)
1914 char_u *title;
1915{
1916 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1917 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1918 * supported everywhere and STRING doesn't work for multi-byte titles.
1919 */
1920#ifdef USE_UTF8_STRING
1921 if (enc_utf8)
1922 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1923 NULL, NULL, 0, NULL, NULL, NULL);
1924 else
1925#endif
1926 {
1927#if XtSpecificationRelease >= 4
1928# ifdef FEAT_XFONTSET
1929 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1930 NULL, NULL, 0, NULL, NULL, NULL);
1931# else
1932 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001933 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934
1935 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001936 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 XSetWMProperties(x11_display, x11_window, &text_prop,
1938 NULL, NULL, 0, NULL, NULL, NULL);
1939# endif
1940#else
1941 XStoreName(x11_display, x11_window, (char *)title);
1942#endif
1943 }
1944 XFlush(x11_display);
1945}
1946
1947/*
1948 * Set x11 Window icon
1949 *
1950 * get_x11_windis() must be called before this and have returned OK
1951 */
1952 static void
1953set_x11_icon(icon)
1954 char_u *icon;
1955{
1956 /* See above for comments about using X*SetWMProperties(). */
1957#ifdef USE_UTF8_STRING
1958 if (enc_utf8)
1959 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1960 NULL, 0, NULL, NULL, NULL);
1961 else
1962#endif
1963 {
1964#if XtSpecificationRelease >= 4
1965# ifdef FEAT_XFONTSET
1966 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1967 NULL, 0, NULL, NULL, NULL);
1968# else
1969 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001970 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001971
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001972 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001973 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
1974 NULL, 0, NULL, NULL, NULL);
1975# endif
1976#else
1977 XSetIconName(x11_display, x11_window, (char *)icon);
1978#endif
1979 }
1980 XFlush(x11_display);
1981}
1982
1983#else /* FEAT_X11 */
1984
Bram Moolenaar071d4272004-06-13 20:20:40 +00001985 static int
1986get_x11_title(test_only)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001987 int test_only UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001988{
1989 return FALSE;
1990}
1991
1992 static int
1993get_x11_icon(test_only)
1994 int test_only;
1995{
1996 if (!test_only)
1997 {
1998 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001999 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002000 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002001 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002002 }
2003 return FALSE;
2004}
2005
2006#endif /* FEAT_X11 */
2007
2008 int
2009mch_can_restore_title()
2010{
2011 return get_x11_title(TRUE);
2012}
2013
2014 int
2015mch_can_restore_icon()
2016{
2017 return get_x11_icon(TRUE);
2018}
2019
2020/*
2021 * Set the window title and icon.
2022 */
2023 void
2024mch_settitle(title, icon)
2025 char_u *title;
2026 char_u *icon;
2027{
2028 int type = 0;
2029 static int recursive = 0;
2030
2031 if (T_NAME == NULL) /* no terminal name (yet) */
2032 return;
2033 if (title == NULL && icon == NULL) /* nothing to do */
2034 return;
2035
2036 /* When one of the X11 functions causes a deadly signal, we get here again
2037 * recursively. Avoid hanging then (something is probably locked). */
2038 if (recursive)
2039 return;
2040 ++recursive;
2041
2042 /*
2043 * if the window ID and the display is known, we may use X11 calls
2044 */
2045#ifdef FEAT_X11
2046 if (get_x11_windis() == OK)
2047 type = 1;
2048#else
2049# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2050 if (gui.in_use)
2051 type = 1;
2052# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053#endif
2054
2055 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002056 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002057 * than x11 calls, because the x11 calls don't always work
2058 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002059 if ((type || *T_TS != NUL) && title != NULL)
2060 {
2061 if (oldtitle == NULL
2062#ifdef FEAT_GUI
2063 && !gui.in_use
2064#endif
2065 ) /* first call but not in GUI, save title */
2066 (void)get_x11_title(FALSE);
2067
2068 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2069 term_settitle(title);
2070#ifdef FEAT_X11
2071 else
2072# ifdef FEAT_GUI_GTK
2073 if (!gui.in_use) /* don't do this if GTK+ is running */
2074# endif
2075 set_x11_title(title); /* x11 */
2076#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002077#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002078 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2079 else
2080 gui_mch_settitle(title, icon);
2081#endif
2082 did_set_title = TRUE;
2083 }
2084
2085 if ((type || *T_CIS != NUL) && icon != NULL)
2086 {
2087 if (oldicon == NULL
2088#ifdef FEAT_GUI
2089 && !gui.in_use
2090#endif
2091 ) /* first call, save icon */
2092 get_x11_icon(FALSE);
2093
2094 if (*T_CIS != NUL)
2095 {
2096 out_str(T_CIS); /* set icon start */
2097 out_str_nf(icon);
2098 out_str(T_CIE); /* set icon end */
2099 out_flush();
2100 }
2101#ifdef FEAT_X11
2102 else
2103# ifdef FEAT_GUI_GTK
2104 if (!gui.in_use) /* don't do this if GTK+ is running */
2105# endif
2106 set_x11_icon(icon); /* x11 */
2107#endif
2108 did_set_icon = TRUE;
2109 }
2110 --recursive;
2111}
2112
2113/*
2114 * Restore the window/icon title.
2115 * "which" is one of:
2116 * 1 only restore title
2117 * 2 only restore icon
2118 * 3 restore title and icon
2119 */
2120 void
2121mch_restore_title(which)
2122 int which;
2123{
2124 /* only restore the title or icon when it has been set */
2125 mch_settitle(((which & 1) && did_set_title) ?
2126 (oldtitle ? oldtitle : p_titleold) : NULL,
2127 ((which & 2) && did_set_icon) ? oldicon : NULL);
2128}
2129
2130#endif /* FEAT_TITLE */
2131
2132/*
2133 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002134 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002135 */
2136 int
2137vim_is_xterm(name)
2138 char_u *name;
2139{
2140 if (name == NULL)
2141 return FALSE;
2142 return (STRNICMP(name, "xterm", 5) == 0
2143 || STRNICMP(name, "nxterm", 6) == 0
2144 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002145 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002146 || STRNICMP(name, "rxvt", 4) == 0
2147 || STRCMP(name, "builtin_xterm") == 0);
2148}
2149
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002150#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2151/*
2152 * Return TRUE if "name" appears to be that of a terminal
2153 * known to support the xterm-style mouse protocol.
2154 * Relies on term_is_xterm having been set to its correct value.
2155 */
2156 int
2157use_xterm_like_mouse(name)
2158 char_u *name;
2159{
2160 return (name != NULL
2161 && (term_is_xterm || STRNICMP(name, "screen", 6) == 0));
2162}
2163#endif
2164
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2166/*
2167 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2168 * Return 1 for "xterm".
2169 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002170 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002171 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002172 */
2173 int
2174use_xterm_mouse()
2175{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002176 if (ttym_flags == TTYM_SGR)
2177 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002178 if (ttym_flags == TTYM_URXVT)
2179 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180 if (ttym_flags == TTYM_XTERM2)
2181 return 2;
2182 if (ttym_flags == TTYM_XTERM)
2183 return 1;
2184 return 0;
2185}
2186#endif
2187
2188 int
2189vim_is_iris(name)
2190 char_u *name;
2191{
2192 if (name == NULL)
2193 return FALSE;
2194 return (STRNICMP(name, "iris-ansi", 9) == 0
2195 || STRCMP(name, "builtin_iris-ansi") == 0);
2196}
2197
2198 int
2199vim_is_vt300(name)
2200 char_u *name;
2201{
2202 if (name == NULL)
2203 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002204 /* catch VT100 - VT5xx */
2205 return ((STRNICMP(name, "vt", 2) == 0
2206 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002207 || STRCMP(name, "builtin_vt320") == 0);
2208}
2209
2210/*
2211 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2212 * This should include all windowed terminal emulators.
2213 */
2214 int
2215vim_is_fastterm(name)
2216 char_u *name;
2217{
2218 if (name == NULL)
2219 return FALSE;
2220 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2221 return TRUE;
2222 return ( STRNICMP(name, "hpterm", 6) == 0
2223 || STRNICMP(name, "sun-cmd", 7) == 0
2224 || STRNICMP(name, "screen", 6) == 0
2225 || STRNICMP(name, "dtterm", 6) == 0);
2226}
2227
2228/*
2229 * Insert user name in s[len].
2230 * Return OK if a name found.
2231 */
2232 int
2233mch_get_user_name(s, len)
2234 char_u *s;
2235 int len;
2236{
2237#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002238 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002239 return OK;
2240#else
2241 return mch_get_uname(getuid(), s, len);
2242#endif
2243}
2244
2245/*
2246 * Insert user name for "uid" in s[len].
2247 * Return OK if a name found.
2248 */
2249 int
2250mch_get_uname(uid, s, len)
2251 uid_t uid;
2252 char_u *s;
2253 int len;
2254{
2255#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2256 struct passwd *pw;
2257
2258 if ((pw = getpwuid(uid)) != NULL
2259 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2260 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002261 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002262 return OK;
2263 }
2264#endif
2265 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2266 return FAIL; /* a number is not a name */
2267}
2268
2269/*
2270 * Insert host name is s[len].
2271 */
2272
2273#ifdef HAVE_SYS_UTSNAME_H
2274 void
2275mch_get_host_name(s, len)
2276 char_u *s;
2277 int len;
2278{
2279 struct utsname vutsname;
2280
2281 if (uname(&vutsname) < 0)
2282 *s = NUL;
2283 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002284 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002285}
2286#else /* HAVE_SYS_UTSNAME_H */
2287
2288# ifdef HAVE_SYS_SYSTEMINFO_H
2289# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2290# endif
2291
2292 void
2293mch_get_host_name(s, len)
2294 char_u *s;
2295 int len;
2296{
2297# ifdef VAXC
2298 vaxc$gethostname((char *)s, len);
2299# else
2300 gethostname((char *)s, len);
2301# endif
2302 s[len - 1] = NUL; /* make sure it's terminated */
2303}
2304#endif /* HAVE_SYS_UTSNAME_H */
2305
2306/*
2307 * return process ID
2308 */
2309 long
2310mch_get_pid()
2311{
2312 return (long)getpid();
2313}
2314
2315#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2316static char *strerror __ARGS((int));
2317
2318 static char *
2319strerror(err)
2320 int err;
2321{
2322 extern int sys_nerr;
2323 extern char *sys_errlist[];
2324 static char er[20];
2325
2326 if (err > 0 && err < sys_nerr)
2327 return (sys_errlist[err]);
2328 sprintf(er, "Error %d", err);
2329 return er;
2330}
2331#endif
2332
2333/*
2334 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2335 * Return OK for success, FAIL for failure.
2336 */
2337 int
2338mch_dirname(buf, len)
2339 char_u *buf;
2340 int len;
2341{
2342#if defined(USE_GETCWD)
2343 if (getcwd((char *)buf, len) == NULL)
2344 {
2345 STRCPY(buf, strerror(errno));
2346 return FAIL;
2347 }
2348 return OK;
2349#else
2350 return (getwd((char *)buf) != NULL ? OK : FAIL);
2351#endif
2352}
2353
2354#if defined(OS2) || defined(PROTO)
2355/*
2356 * Replace all slashes by backslashes.
2357 * When 'shellslash' set do it the other way around.
2358 */
2359 void
2360slash_adjust(p)
2361 char_u *p;
2362{
2363 while (*p)
2364 {
2365 if (*p == psepcN)
2366 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002367 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002368 }
2369}
2370#endif
2371
2372/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002373 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002374 *
2375 * return FAIL for failure, OK for success
2376 */
2377 int
2378mch_FullName(fname, buf, len, force)
2379 char_u *fname, *buf;
2380 int len;
2381 int force; /* also expand when already absolute path */
2382{
2383 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002384#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002386#endif
2387#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 int fd = -1;
2389 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002390#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002391 char_u olddir[MAXPATHL];
2392 char_u *p;
2393 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002394#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002395 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2396 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002397#endif
2398
Bram Moolenaar38323e42007-03-06 19:22:53 +00002399#ifdef VMS
2400 fname = vms_fixfilename(fname);
2401#endif
2402
Bram Moolenaara2442432007-04-26 14:26:37 +00002403#ifdef __CYGWIN__
2404 /*
2405 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2406 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002407# if CYGWIN_VERSION_DLL_MAJOR >= 1007
2408 cygwin_conv_path(CCP_WIN_A_TO_POSIX, fname, posix_fname, MAXPATHL);
2409# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002410 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002411# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002412 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002413#endif
2414
Bram Moolenaar071d4272004-06-13 20:20:40 +00002415 /* expand it if forced or not an absolute path */
2416 if (force || !mch_isFullName(fname))
2417 {
2418 /*
2419 * If the file name has a path, change to that directory for a moment,
2420 * and then do the getwd() (and get back to where we were).
2421 * This will get the correct path name with "../" things.
2422 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002423#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002424 only_drive = 0;
2425 if (((p = vim_strrchr(fname, '/')) != NULL)
2426 || ((p = vim_strrchr(fname, '\\')) != NULL)
2427 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002428#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002430#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002431 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002432#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002433 /*
2434 * Use fchdir() if possible, it's said to be faster and more
2435 * reliable. But on SunOS 4 it might not work. Check this by
2436 * doing a fchdir() right now.
2437 */
2438 if (!dont_fchdir)
2439 {
2440 fd = open(".", O_RDONLY | O_EXTRA, 0);
2441 if (fd >= 0 && fchdir(fd) < 0)
2442 {
2443 close(fd);
2444 fd = -1;
2445 dont_fchdir = TRUE; /* don't try again */
2446 }
2447 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002448#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002449
2450 /* Only change directory when we are sure we can return to where
2451 * we are now. After doing "su" chdir(".") might not work. */
2452 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002453#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002454 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002455#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 (mch_dirname(olddir, MAXPATHL) == FAIL
2457 || mch_chdir((char *)olddir) != 0))
2458 {
2459 p = NULL; /* can't get current dir: don't chdir */
2460 retval = FAIL;
2461 }
2462 else
2463 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002464#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002465 /*
2466 * compensate for case where ':' from "D:" was the only
2467 * path separator detected in the file name; the _next_
2468 * character has to be removed, and then restored later.
2469 */
2470 if (only_drive)
2471 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002472#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002473 /* The directory is copied into buf[], to be able to remove
2474 * the file name without changing it (could be a string in
2475 * read-only memory) */
2476 if (p - fname >= len)
2477 retval = FAIL;
2478 else
2479 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002480 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002481 if (mch_chdir((char *)buf))
2482 retval = FAIL;
2483 else
2484 fname = p + 1;
2485 *buf = NUL;
2486 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002487#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488 if (only_drive)
2489 {
2490 p--;
2491 if (retval != FAIL)
2492 fname--;
2493 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002494#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002495 }
2496 }
2497 if (mch_dirname(buf, len) == FAIL)
2498 {
2499 retval = FAIL;
2500 *buf = NUL;
2501 }
2502 if (p != NULL)
2503 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002504#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002505 if (fd >= 0)
2506 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002507 if (p_verbose >= 5)
2508 {
2509 verbose_enter();
2510 MSG("fchdir() to previous dir");
2511 verbose_leave();
2512 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002513 l = fchdir(fd);
2514 close(fd);
2515 }
2516 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002517#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518 l = mch_chdir((char *)olddir);
2519 if (l != 0)
2520 EMSG(_(e_prev_dir));
2521 }
2522
2523 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002524 if (l >= len - 1)
2525 retval = FAIL; /* no space for trailing "/" */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002526#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002527 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002528 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002529 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002530#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002531 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002532
Bram Moolenaar071d4272004-06-13 20:20:40 +00002533 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002534 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002535 return FAIL;
2536
2537 /* Do not append ".", "/dir/." is equal to "/dir". */
2538 if (STRCMP(fname, ".") != 0)
2539 STRCAT(buf, fname);
2540
2541 return OK;
2542}
2543
2544/*
2545 * Return TRUE if "fname" does not depend on the current directory.
2546 */
2547 int
2548mch_isFullName(fname)
2549 char_u *fname;
2550{
2551#ifdef __EMX__
2552 return _fnisabs(fname);
2553#else
2554# ifdef VMS
2555 return ( fname[0] == '/' || fname[0] == '.' ||
2556 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2557 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2558 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2559# else
2560 return (*fname == '/' || *fname == '~');
2561# endif
2562#endif
2563}
2564
Bram Moolenaar24552be2005-12-10 20:17:30 +00002565#if defined(USE_FNAME_CASE) || defined(PROTO)
2566/*
2567 * Set the case of the file name, if it already exists. This will cause the
2568 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002569 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002570 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002571 void
2572fname_case(name, len)
2573 char_u *name;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002574 int len UNUSED; /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002575{
2576 struct stat st;
2577 char_u *slash, *tail;
2578 DIR *dirp;
2579 struct dirent *dp;
2580
2581 if (lstat((char *)name, &st) >= 0)
2582 {
2583 /* Open the directory where the file is located. */
2584 slash = vim_strrchr(name, '/');
2585 if (slash == NULL)
2586 {
2587 dirp = opendir(".");
2588 tail = name;
2589 }
2590 else
2591 {
2592 *slash = NUL;
2593 dirp = opendir((char *)name);
2594 *slash = '/';
2595 tail = slash + 1;
2596 }
2597
2598 if (dirp != NULL)
2599 {
2600 while ((dp = readdir(dirp)) != NULL)
2601 {
2602 /* Only accept names that differ in case and are the same byte
2603 * length. TODO: accept different length name. */
2604 if (STRICMP(tail, dp->d_name) == 0
2605 && STRLEN(tail) == STRLEN(dp->d_name))
2606 {
2607 char_u newname[MAXPATHL + 1];
2608 struct stat st2;
2609
2610 /* Verify the inode is equal. */
2611 vim_strncpy(newname, name, MAXPATHL);
2612 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2613 MAXPATHL - (tail - name));
2614 if (lstat((char *)newname, &st2) >= 0
2615 && st.st_ino == st2.st_ino
2616 && st.st_dev == st2.st_dev)
2617 {
2618 STRCPY(tail, dp->d_name);
2619 break;
2620 }
2621 }
2622 }
2623
2624 closedir(dirp);
2625 }
2626 }
2627}
2628#endif
2629
Bram Moolenaar071d4272004-06-13 20:20:40 +00002630/*
2631 * Get file permissions for 'name'.
2632 * Returns -1 when it doesn't exist.
2633 */
2634 long
2635mch_getperm(name)
2636 char_u *name;
2637{
2638 struct stat statb;
2639
2640 /* Keep the #ifdef outside of stat(), it may be a macro. */
2641#ifdef VMS
2642 if (stat((char *)vms_fixfilename(name), &statb))
2643#else
2644 if (stat((char *)name, &statb))
2645#endif
2646 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002647#ifdef __INTERIX
2648 /* The top bit makes the value negative, which means the file doesn't
2649 * exist. Remove the bit, we don't use it. */
2650 return statb.st_mode & ~S_ADDACE;
2651#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002653#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002654}
2655
2656/*
2657 * set file permission for 'name' to 'perm'
2658 *
2659 * return FAIL for failure, OK otherwise
2660 */
2661 int
2662mch_setperm(name, perm)
2663 char_u *name;
2664 long perm;
2665{
2666 return (chmod((char *)
2667#ifdef VMS
2668 vms_fixfilename(name),
2669#else
2670 name,
2671#endif
2672 (mode_t)perm) == 0 ? OK : FAIL);
2673}
2674
2675#if defined(HAVE_ACL) || defined(PROTO)
2676# ifdef HAVE_SYS_ACL_H
2677# include <sys/acl.h>
2678# endif
2679# ifdef HAVE_SYS_ACCESS_H
2680# include <sys/access.h>
2681# endif
2682
2683# ifdef HAVE_SOLARIS_ACL
2684typedef struct vim_acl_solaris_T {
2685 int acl_cnt;
2686 aclent_t *acl_entry;
2687} vim_acl_solaris_T;
2688# endif
2689
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002690#if defined(HAVE_SELINUX) || defined(PROTO)
2691/*
2692 * Copy security info from "from_file" to "to_file".
2693 */
2694 void
2695mch_copy_sec(from_file, to_file)
2696 char_u *from_file;
2697 char_u *to_file;
2698{
2699 if (from_file == NULL)
2700 return;
2701
2702 if (selinux_enabled == -1)
2703 selinux_enabled = is_selinux_enabled();
2704
2705 if (selinux_enabled > 0)
2706 {
2707 security_context_t from_context = NULL;
2708 security_context_t to_context = NULL;
2709
2710 if (getfilecon((char *)from_file, &from_context) < 0)
2711 {
2712 /* If the filesystem doesn't support extended attributes,
2713 the original had no special security context and the
2714 target cannot have one either. */
2715 if (errno == EOPNOTSUPP)
2716 return;
2717
2718 MSG_PUTS(_("\nCould not get security context for "));
2719 msg_outtrans(from_file);
2720 msg_putchar('\n');
2721 return;
2722 }
2723 if (getfilecon((char *)to_file, &to_context) < 0)
2724 {
2725 MSG_PUTS(_("\nCould not get security context for "));
2726 msg_outtrans(to_file);
2727 msg_putchar('\n');
2728 freecon (from_context);
2729 return ;
2730 }
2731 if (strcmp(from_context, to_context) != 0)
2732 {
2733 if (setfilecon((char *)to_file, from_context) < 0)
2734 {
2735 MSG_PUTS(_("\nCould not set security context for "));
2736 msg_outtrans(to_file);
2737 msg_putchar('\n');
2738 }
2739 }
2740 freecon(to_context);
2741 freecon(from_context);
2742 }
2743}
2744#endif /* HAVE_SELINUX */
2745
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746/*
2747 * Return a pointer to the ACL of file "fname" in allocated memory.
2748 * Return NULL if the ACL is not available for whatever reason.
2749 */
2750 vim_acl_T
2751mch_get_acl(fname)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002752 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753{
2754 vim_acl_T ret = NULL;
2755#ifdef HAVE_POSIX_ACL
2756 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2757#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002758#ifdef HAVE_SOLARIS_ZFS_ACL
2759 acl_t *aclent;
2760
2761 if (acl_get((char *)fname, 0, &aclent) < 0)
2762 return NULL;
2763 ret = (vim_acl_T)aclent;
2764#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002765#ifdef HAVE_SOLARIS_ACL
2766 vim_acl_solaris_T *aclent;
2767
2768 aclent = malloc(sizeof(vim_acl_solaris_T));
2769 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2770 {
2771 free(aclent);
2772 return NULL;
2773 }
2774 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2775 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2776 {
2777 free(aclent->acl_entry);
2778 free(aclent);
2779 return NULL;
2780 }
2781 ret = (vim_acl_T)aclent;
2782#else
2783#if defined(HAVE_AIX_ACL)
2784 int aclsize;
2785 struct acl *aclent;
2786
2787 aclsize = sizeof(struct acl);
2788 aclent = malloc(aclsize);
2789 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2790 {
2791 if (errno == ENOSPC)
2792 {
2793 aclsize = aclent->acl_len;
2794 aclent = realloc(aclent, aclsize);
2795 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2796 {
2797 free(aclent);
2798 return NULL;
2799 }
2800 }
2801 else
2802 {
2803 free(aclent);
2804 return NULL;
2805 }
2806 }
2807 ret = (vim_acl_T)aclent;
2808#endif /* HAVE_AIX_ACL */
2809#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002810#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002811#endif /* HAVE_POSIX_ACL */
2812 return ret;
2813}
2814
2815/*
2816 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2817 */
2818 void
2819mch_set_acl(fname, aclent)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002820 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002821 vim_acl_T aclent;
2822{
2823 if (aclent == NULL)
2824 return;
2825#ifdef HAVE_POSIX_ACL
2826 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2827#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002828#ifdef HAVE_SOLARIS_ZFS_ACL
2829 acl_set((char *)fname, (acl_t *)aclent);
2830#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002831#ifdef HAVE_SOLARIS_ACL
2832 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2833 ((vim_acl_solaris_T *)aclent)->acl_entry);
2834#else
2835#ifdef HAVE_AIX_ACL
2836 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2837#endif /* HAVE_AIX_ACL */
2838#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002839#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840#endif /* HAVE_POSIX_ACL */
2841}
2842
2843 void
2844mch_free_acl(aclent)
2845 vim_acl_T aclent;
2846{
2847 if (aclent == NULL)
2848 return;
2849#ifdef HAVE_POSIX_ACL
2850 acl_free((acl_t)aclent);
2851#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002852#ifdef HAVE_SOLARIS_ZFS_ACL
2853 acl_free((acl_t *)aclent);
2854#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002855#ifdef HAVE_SOLARIS_ACL
2856 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2857 free(aclent);
2858#else
2859#ifdef HAVE_AIX_ACL
2860 free(aclent);
2861#endif /* HAVE_AIX_ACL */
2862#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002863#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002864#endif /* HAVE_POSIX_ACL */
2865}
2866#endif
2867
2868/*
2869 * Set hidden flag for "name".
2870 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002871 void
2872mch_hide(name)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002873 char_u *name UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002874{
2875 /* can't hide a file */
2876}
2877
2878/*
2879 * return TRUE if "name" is a directory
2880 * return FALSE if "name" is not a directory
2881 * return FALSE for error
2882 */
2883 int
2884mch_isdir(name)
2885 char_u *name;
2886{
2887 struct stat statb;
2888
2889 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2890 return FALSE;
2891 if (stat((char *)name, &statb))
2892 return FALSE;
2893#ifdef _POSIX_SOURCE
2894 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2895#else
2896 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2897#endif
2898}
2899
Bram Moolenaar071d4272004-06-13 20:20:40 +00002900static int executable_file __ARGS((char_u *name));
2901
2902/*
2903 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2904 */
2905 static int
2906executable_file(name)
2907 char_u *name;
2908{
2909 struct stat st;
2910
2911 if (stat((char *)name, &st))
2912 return 0;
2913 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2914}
2915
2916/*
2917 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2918 * Return -1 if unknown.
2919 */
2920 int
2921mch_can_exe(name)
2922 char_u *name;
2923{
2924 char_u *buf;
2925 char_u *p, *e;
2926 int retval;
2927
2928 /* If it's an absolute or relative path don't need to use $PATH. */
2929 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2930 || (name[1] == '.' && name[2] == '/'))))
2931 return executable_file(name);
2932
2933 p = (char_u *)getenv("PATH");
2934 if (p == NULL || *p == NUL)
2935 return -1;
2936 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2937 if (buf == NULL)
2938 return -1;
2939
2940 /*
2941 * Walk through all entries in $PATH to check if "name" exists there and
2942 * is an executable file.
2943 */
2944 for (;;)
2945 {
2946 e = (char_u *)strchr((char *)p, ':');
2947 if (e == NULL)
2948 e = p + STRLEN(p);
2949 if (e - p <= 1) /* empty entry means current dir */
2950 STRCPY(buf, "./");
2951 else
2952 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002953 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954 add_pathsep(buf);
2955 }
2956 STRCAT(buf, name);
2957 retval = executable_file(buf);
2958 if (retval == 1)
2959 break;
2960
2961 if (*e != ':')
2962 break;
2963 p = e + 1;
2964 }
2965
2966 vim_free(buf);
2967 return retval;
2968}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002969
2970/*
2971 * Check what "name" is:
2972 * NODE_NORMAL: file or directory (or doesn't exist)
2973 * NODE_WRITABLE: writable device, socket, fifo, etc.
2974 * NODE_OTHER: non-writable things
2975 */
2976 int
2977mch_nodetype(name)
2978 char_u *name;
2979{
2980 struct stat st;
2981
2982 if (stat((char *)name, &st))
2983 return NODE_NORMAL;
2984 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2985 return NODE_NORMAL;
2986#ifndef OS2
2987 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2988 return NODE_OTHER;
2989#endif
2990 /* Everything else is writable? */
2991 return NODE_WRITABLE;
2992}
2993
2994 void
2995mch_early_init()
2996{
2997#ifdef HAVE_CHECK_STACK_GROWTH
2998 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002999
Bram Moolenaar071d4272004-06-13 20:20:40 +00003000 check_stack_growth((char *)&i);
3001
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003002# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003003 get_stack_limit();
3004# endif
3005
3006#endif
3007
3008 /*
3009 * Setup an alternative stack for signals. Helps to catch signals when
3010 * running out of stack space.
3011 * Use of sigaltstack() is preferred, it's more portable.
3012 * Ignore any errors.
3013 */
3014#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00003015 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003016 init_signal_stack();
3017#endif
3018}
3019
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003020#if defined(EXITFREE) || defined(PROTO)
3021 void
3022mch_free_mem()
3023{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003024# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3025 if (clip_star.owned)
3026 clip_lose_selection(&clip_star);
3027 if (clip_plus.owned)
3028 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003029# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003030# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003031 if (xterm_Shell != (Widget)0)
3032 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003033# ifndef LESSTIF_VERSION
3034 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003035 if (xterm_dpy != NULL)
3036 XtCloseDisplay(xterm_dpy);
3037 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003038 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003039 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003040# ifdef FEAT_X11
3041 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
3042# endif
3043 }
3044# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003045# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003046# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003047 if (x11_display != NULL
3048# ifdef FEAT_XCLIPBOARD
3049 && x11_display != xterm_dpy
3050# endif
3051 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003052 XCloseDisplay(x11_display);
3053# endif
3054# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
3055 vim_free(signal_stack);
3056 signal_stack = NULL;
3057# endif
3058# ifdef FEAT_TITLE
3059 vim_free(oldtitle);
3060 vim_free(oldicon);
3061# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003062}
3063#endif
3064
Bram Moolenaar071d4272004-06-13 20:20:40 +00003065static void exit_scroll __ARGS((void));
3066
3067/*
3068 * Output a newline when exiting.
3069 * Make sure the newline goes to the same stream as the text.
3070 */
3071 static void
3072exit_scroll()
3073{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003074 if (silent_mode)
3075 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003076 if (newline_on_exit || msg_didout)
3077 {
3078 if (msg_use_printf())
3079 {
3080 if (info_message)
3081 mch_msg("\n");
3082 else
3083 mch_errmsg("\r\n");
3084 }
3085 else
3086 out_char('\n');
3087 }
3088 else
3089 {
3090 restore_cterm_colors(); /* get original colors back */
3091 msg_clr_eos_force(); /* clear the rest of the display */
3092 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3093 }
3094}
3095
3096 void
3097mch_exit(r)
3098 int r;
3099{
3100 exiting = TRUE;
3101
3102#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3103 x11_export_final_selection();
3104#endif
3105
3106#ifdef FEAT_GUI
3107 if (!gui.in_use)
3108#endif
3109 {
3110 settmode(TMODE_COOK);
3111#ifdef FEAT_TITLE
3112 mch_restore_title(3); /* restore xterm title and icon name */
3113#endif
3114 /*
3115 * When t_ti is not empty but it doesn't cause swapping terminal
3116 * pages, need to output a newline when msg_didout is set. But when
3117 * t_ti does swap pages it should not go to the shell page. Do this
3118 * before stoptermcap().
3119 */
3120 if (swapping_screen() && !newline_on_exit)
3121 exit_scroll();
3122
3123 /* Stop termcap: May need to check for T_CRV response, which
3124 * requires RAW mode. */
3125 stoptermcap();
3126
3127 /*
3128 * A newline is only required after a message in the alternate screen.
3129 * This is set to TRUE by wait_return().
3130 */
3131 if (!swapping_screen() || newline_on_exit)
3132 exit_scroll();
3133
3134 /* Cursor may have been switched off without calling starttermcap()
3135 * when doing "vim -u vimrc" and vimrc contains ":q". */
3136 if (full_screen)
3137 cursor_on();
3138 }
3139 out_flush();
3140 ml_close_all(TRUE); /* remove all memfiles */
3141 may_core_dump();
3142#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003143 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003144 gui_exit(r);
3145#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003146
Bram Moolenaar56718732006-03-15 22:53:57 +00003147#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003148 mac_conv_cleanup();
3149#endif
3150
Bram Moolenaar071d4272004-06-13 20:20:40 +00003151#ifdef __QNX__
3152 /* A core dump won't be created if the signal handler
3153 * doesn't return, so we can't call exit() */
3154 if (deadly_signal != 0)
3155 return;
3156#endif
3157
Bram Moolenaar009b2592004-10-24 19:18:58 +00003158#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003159 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003160#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003161
3162#ifdef EXITFREE
3163 free_all_mem();
3164#endif
3165
Bram Moolenaar071d4272004-06-13 20:20:40 +00003166 exit(r);
3167}
3168
3169 static void
3170may_core_dump()
3171{
3172 if (deadly_signal != 0)
3173 {
3174 signal(deadly_signal, SIG_DFL);
3175 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3176 }
3177}
3178
3179#ifndef VMS
3180
3181 void
3182mch_settmode(tmode)
3183 int tmode;
3184{
3185 static int first = TRUE;
3186
3187 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3188#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3189 /*
3190 * for "new" tty systems
3191 */
3192# ifdef HAVE_TERMIOS_H
3193 static struct termios told;
3194 struct termios tnew;
3195# else
3196 static struct termio told;
3197 struct termio tnew;
3198# endif
3199
3200 if (first)
3201 {
3202 first = FALSE;
3203# if defined(HAVE_TERMIOS_H)
3204 tcgetattr(read_cmd_fd, &told);
3205# else
3206 ioctl(read_cmd_fd, TCGETA, &told);
3207# endif
3208 }
3209
3210 tnew = told;
3211 if (tmode == TMODE_RAW)
3212 {
3213 /*
3214 * ~ICRNL enables typing ^V^M
3215 */
3216 tnew.c_iflag &= ~ICRNL;
3217 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3218# if defined(IEXTEN) && !defined(__MINT__)
3219 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3220 /* but it breaks function keys on MINT */
3221# endif
3222 );
3223# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3224 tnew.c_oflag &= ~ONLCR;
3225# endif
3226 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3227 tnew.c_cc[VTIME] = 0; /* don't wait */
3228 }
3229 else if (tmode == TMODE_SLEEP)
3230 tnew.c_lflag &= ~(ECHO);
3231
3232# if defined(HAVE_TERMIOS_H)
3233 {
3234 int n = 10;
3235
3236 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3237 * few times. */
3238 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3239 && errno == EINTR && n > 0)
3240 --n;
3241 }
3242# else
3243 ioctl(read_cmd_fd, TCSETA, &tnew);
3244# endif
3245
3246#else
3247
3248 /*
3249 * for "old" tty systems
3250 */
3251# ifndef TIOCSETN
3252# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3253# endif
3254 static struct sgttyb ttybold;
3255 struct sgttyb ttybnew;
3256
3257 if (first)
3258 {
3259 first = FALSE;
3260 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3261 }
3262
3263 ttybnew = ttybold;
3264 if (tmode == TMODE_RAW)
3265 {
3266 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3267 ttybnew.sg_flags |= RAW;
3268 }
3269 else if (tmode == TMODE_SLEEP)
3270 ttybnew.sg_flags &= ~(ECHO);
3271 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3272#endif
3273 curr_tmode = tmode;
3274}
3275
3276/*
3277 * Try to get the code for "t_kb" from the stty setting
3278 *
3279 * Even if termcap claims a backspace key, the user's setting *should*
3280 * prevail. stty knows more about reality than termcap does, and if
3281 * somebody's usual erase key is DEL (which, for most BSD users, it will
3282 * be), they're going to get really annoyed if their erase key starts
3283 * doing forward deletes for no reason. (Eric Fischer)
3284 */
3285 void
3286get_stty()
3287{
3288 char_u buf[2];
3289 char_u *p;
3290
3291 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3292#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3293 /* for "new" tty systems */
3294# ifdef HAVE_TERMIOS_H
3295 struct termios keys;
3296# else
3297 struct termio keys;
3298# endif
3299
3300# if defined(HAVE_TERMIOS_H)
3301 if (tcgetattr(read_cmd_fd, &keys) != -1)
3302# else
3303 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3304# endif
3305 {
3306 buf[0] = keys.c_cc[VERASE];
3307 intr_char = keys.c_cc[VINTR];
3308#else
3309 /* for "old" tty systems */
3310 struct sgttyb keys;
3311
3312 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3313 {
3314 buf[0] = keys.sg_erase;
3315 intr_char = keys.sg_kill;
3316#endif
3317 buf[1] = NUL;
3318 add_termcode((char_u *)"kb", buf, FALSE);
3319
3320 /*
3321 * If <BS> and <DEL> are now the same, redefine <DEL>.
3322 */
3323 p = find_termcode((char_u *)"kD");
3324 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3325 do_fixdel(NULL);
3326 }
3327#if 0
3328 } /* to keep cindent happy */
3329#endif
3330}
3331
3332#endif /* VMS */
3333
3334#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3335/*
3336 * Set mouse clicks on or off.
3337 */
3338 void
3339mch_setmouse(on)
3340 int on;
3341{
3342 static int ison = FALSE;
3343 int xterm_mouse_vers;
3344
3345 if (on == ison) /* return quickly if nothing to do */
3346 return;
3347
3348 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003349
3350# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003351 if (ttym_flags == TTYM_URXVT)
3352 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003353 out_str_nf((char_u *)
3354 (on
3355 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3356 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
3357 ison = on;
3358 }
3359# endif
3360
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003361# ifdef FEAT_MOUSE_SGR
3362 if (ttym_flags == TTYM_SGR)
3363 {
3364 out_str_nf((char_u *)
3365 (on
3366 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3367 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
3368 ison = on;
3369 }
3370# endif
3371
Bram Moolenaar071d4272004-06-13 20:20:40 +00003372 if (xterm_mouse_vers > 0)
3373 {
3374 if (on) /* enable mouse events, use mouse tracking if available */
3375 out_str_nf((char_u *)
3376 (xterm_mouse_vers > 1
3377 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3378 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3379 else /* disable mouse events, could probably always send the same */
3380 out_str_nf((char_u *)
3381 (xterm_mouse_vers > 1
3382 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3383 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3384 ison = on;
3385 }
3386
3387# ifdef FEAT_MOUSE_DEC
3388 else if (ttym_flags == TTYM_DEC)
3389 {
3390 if (on) /* enable mouse events */
3391 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3392 else /* disable mouse events */
3393 out_str_nf((char_u *)"\033['z");
3394 ison = on;
3395 }
3396# endif
3397
3398# ifdef FEAT_MOUSE_GPM
3399 else
3400 {
3401 if (on)
3402 {
3403 if (gpm_open())
3404 ison = TRUE;
3405 }
3406 else
3407 {
3408 gpm_close();
3409 ison = FALSE;
3410 }
3411 }
3412# endif
3413
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003414# ifdef FEAT_SYSMOUSE
3415 else
3416 {
3417 if (on)
3418 {
3419 if (sysmouse_open() == OK)
3420 ison = TRUE;
3421 }
3422 else
3423 {
3424 sysmouse_close();
3425 ison = FALSE;
3426 }
3427 }
3428# endif
3429
Bram Moolenaar071d4272004-06-13 20:20:40 +00003430# ifdef FEAT_MOUSE_JSB
3431 else
3432 {
3433 if (on)
3434 {
3435 /* D - Enable Mouse up/down messages
3436 * L - Enable Left Button Reporting
3437 * M - Enable Middle Button Reporting
3438 * R - Enable Right Button Reporting
3439 * K - Enable SHIFT and CTRL key Reporting
3440 * + - Enable Advanced messaging of mouse moves and up/down messages
3441 * Q - Quiet No Ack
3442 * # - Numeric value of mouse pointer required
3443 * 0 = Multiview 2000 cursor, used as standard
3444 * 1 = Windows Arrow
3445 * 2 = Windows I Beam
3446 * 3 = Windows Hour Glass
3447 * 4 = Windows Cross Hair
3448 * 5 = Windows UP Arrow
3449 */
3450#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3451 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3452 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3453#else
3454 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3455 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3456#endif
3457 ison = TRUE;
3458 }
3459 else
3460 {
3461 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3462 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3463 ison = FALSE;
3464 }
3465 }
3466# endif
3467# ifdef FEAT_MOUSE_PTERM
3468 else
3469 {
3470 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3471 if (on)
3472 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3473 else
3474 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3475 ison = on;
3476 }
3477# endif
3478}
3479
3480/*
3481 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3482 */
3483 void
3484check_mouse_termcode()
3485{
3486# ifdef FEAT_MOUSE_XTERM
3487 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003488# ifdef FEAT_MOUSE_URXVT
3489 && use_xterm_mouse() != 3
3490# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003491# ifdef FEAT_GUI
3492 && !gui.in_use
3493# endif
3494 )
3495 {
3496 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003497 ? IF_EB("\233M", CSI_STR "M")
3498 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003499 if (*p_mouse != NUL)
3500 {
3501 /* force mouse off and maybe on to send possibly new mouse
3502 * activation sequence to the xterm, with(out) drag tracing. */
3503 mch_setmouse(FALSE);
3504 setmouse();
3505 }
3506 }
3507 else
3508 del_mouse_termcode(KS_MOUSE);
3509# endif
3510
3511# ifdef FEAT_MOUSE_GPM
3512 if (!use_xterm_mouse()
3513# ifdef FEAT_GUI
3514 && !gui.in_use
3515# endif
3516 )
3517 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3518# endif
3519
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003520# ifdef FEAT_SYSMOUSE
3521 if (!use_xterm_mouse()
3522# ifdef FEAT_GUI
3523 && !gui.in_use
3524# endif
3525 )
3526 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3527# endif
3528
Bram Moolenaar071d4272004-06-13 20:20:40 +00003529# ifdef FEAT_MOUSE_JSB
3530 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3531 if (!use_xterm_mouse()
3532# ifdef FEAT_GUI
3533 && !gui.in_use
3534# endif
3535 )
3536 set_mouse_termcode(KS_JSBTERM_MOUSE,
3537 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3538 else
3539 del_mouse_termcode(KS_JSBTERM_MOUSE);
3540# endif
3541
3542# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003543 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003544 * define it in the GUI or when using an xterm. */
3545 if (!use_xterm_mouse()
3546# ifdef FEAT_GUI
3547 && !gui.in_use
3548# endif
3549 )
3550 set_mouse_termcode(KS_NETTERM_MOUSE,
3551 (char_u *)IF_EB("\033}", ESC_STR "}"));
3552 else
3553 del_mouse_termcode(KS_NETTERM_MOUSE);
3554# endif
3555
3556# ifdef FEAT_MOUSE_DEC
3557 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3558 if (!use_xterm_mouse()
3559# ifdef FEAT_GUI
3560 && !gui.in_use
3561# endif
3562 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003563 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3564 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565 else
3566 del_mouse_termcode(KS_DEC_MOUSE);
3567# endif
3568# ifdef FEAT_MOUSE_PTERM
3569 /* same as the dec mouse */
3570 if (!use_xterm_mouse()
3571# ifdef FEAT_GUI
3572 && !gui.in_use
3573# endif
3574 )
3575 set_mouse_termcode(KS_PTERM_MOUSE,
3576 (char_u *) IF_EB("\033[", ESC_STR "["));
3577 else
3578 del_mouse_termcode(KS_PTERM_MOUSE);
3579# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003580# ifdef FEAT_MOUSE_URXVT
3581 /* same as the dec mouse */
3582 if (use_xterm_mouse() == 3
3583# ifdef FEAT_GUI
3584 && !gui.in_use
3585# endif
3586 )
3587 {
3588 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3589 ? IF_EB("\233", CSI_STR)
3590 : IF_EB("\033[", ESC_STR "[")));
3591
3592 if (*p_mouse != NUL)
3593 {
3594 mch_setmouse(FALSE);
3595 setmouse();
3596 }
3597 }
3598 else
3599 del_mouse_termcode(KS_URXVT_MOUSE);
3600# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003601# ifdef FEAT_MOUSE_SGR
3602 /* same as the dec mouse */
3603 if (use_xterm_mouse() == 4
3604# ifdef FEAT_GUI
3605 && !gui.in_use
3606# endif
3607 )
3608 {
3609 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3610 ? IF_EB("\233<", CSI_STR "<")
3611 : IF_EB("\033[<", ESC_STR "[<")));
3612
3613 if (*p_mouse != NUL)
3614 {
3615 mch_setmouse(FALSE);
3616 setmouse();
3617 }
3618 }
3619 else
3620 del_mouse_termcode(KS_SGR_MOUSE);
3621# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003622}
3623#endif
3624
3625/*
3626 * set screen mode, always fails.
3627 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003628 int
3629mch_screenmode(arg)
Bram Moolenaar78a15312009-05-15 19:33:18 +00003630 char_u *arg UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003631{
3632 EMSG(_(e_screenmode));
3633 return FAIL;
3634}
3635
3636#ifndef VMS
3637
3638/*
3639 * Try to get the current window size:
3640 * 1. with an ioctl(), most accurate method
3641 * 2. from the environment variables LINES and COLUMNS
3642 * 3. from the termcap
3643 * 4. keep using the old values
3644 * Return OK when size could be determined, FAIL otherwise.
3645 */
3646 int
3647mch_get_shellsize()
3648{
3649 long rows = 0;
3650 long columns = 0;
3651 char_u *p;
3652
3653 /*
3654 * For OS/2 use _scrsize().
3655 */
3656# ifdef __EMX__
3657 {
3658 int s[2];
3659
3660 _scrsize(s);
3661 columns = s[0];
3662 rows = s[1];
3663 }
3664# endif
3665
3666 /*
3667 * 1. try using an ioctl. It is the most accurate method.
3668 *
3669 * Try using TIOCGWINSZ first, some systems that have it also define
3670 * TIOCGSIZE but don't have a struct ttysize.
3671 */
3672# ifdef TIOCGWINSZ
3673 {
3674 struct winsize ws;
3675 int fd = 1;
3676
3677 /* When stdout is not a tty, use stdin for the ioctl(). */
3678 if (!isatty(fd) && isatty(read_cmd_fd))
3679 fd = read_cmd_fd;
3680 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3681 {
3682 columns = ws.ws_col;
3683 rows = ws.ws_row;
3684 }
3685 }
3686# else /* TIOCGWINSZ */
3687# ifdef TIOCGSIZE
3688 {
3689 struct ttysize ts;
3690 int fd = 1;
3691
3692 /* When stdout is not a tty, use stdin for the ioctl(). */
3693 if (!isatty(fd) && isatty(read_cmd_fd))
3694 fd = read_cmd_fd;
3695 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3696 {
3697 columns = ts.ts_cols;
3698 rows = ts.ts_lines;
3699 }
3700 }
3701# endif /* TIOCGSIZE */
3702# endif /* TIOCGWINSZ */
3703
3704 /*
3705 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003706 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3707 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003709 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710 {
3711 if ((p = (char_u *)getenv("LINES")))
3712 rows = atoi((char *)p);
3713 if ((p = (char_u *)getenv("COLUMNS")))
3714 columns = atoi((char *)p);
3715 }
3716
3717#ifdef HAVE_TGETENT
3718 /*
3719 * 3. try reading "co" and "li" entries from termcap
3720 */
3721 if (columns == 0 || rows == 0)
3722 getlinecol(&columns, &rows);
3723#endif
3724
3725 /*
3726 * 4. If everything fails, use the old values
3727 */
3728 if (columns <= 0 || rows <= 0)
3729 return FAIL;
3730
3731 Rows = rows;
3732 Columns = columns;
3733 return OK;
3734}
3735
3736/*
3737 * Try to set the window size to Rows and Columns.
3738 */
3739 void
3740mch_set_shellsize()
3741{
3742 if (*T_CWS)
3743 {
3744 /*
3745 * NOTE: if you get an error here that term_set_winsize() is
3746 * undefined, check the output of configure. It could probably not
3747 * find a ncurses, termcap or termlib library.
3748 */
3749 term_set_winsize((int)Rows, (int)Columns);
3750 out_flush();
3751 screen_start(); /* don't know where cursor is now */
3752 }
3753}
3754
3755#endif /* VMS */
3756
3757/*
3758 * Rows and/or Columns has changed.
3759 */
3760 void
3761mch_new_shellsize()
3762{
3763 /* Nothing to do. */
3764}
3765
Bram Moolenaar205b8862011-09-07 15:04:31 +02003766/*
3767 * Wait for process "child" to end.
3768 * Return "child" if it exited properly, <= 0 on error.
3769 */
3770 static pid_t
3771wait4pid(child, status)
3772 pid_t child;
3773 waitstatus *status;
3774{
3775 pid_t wait_pid = 0;
3776
3777 while (wait_pid != child)
3778 {
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003779 /* When compiled with Python threads are probably used, in which case
3780 * wait() sometimes hangs for no obvious reason. Use waitpid()
3781 * instead and loop (like the GUI). Also needed for other interfaces,
3782 * they might call system(). */
3783# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02003784 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003785# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02003786 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003787# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02003788 if (wait_pid == 0)
3789 {
Bram Moolenaar75676462013-01-30 14:55:42 +01003790 /* Wait for 10 msec before trying again. */
Bram Moolenaar205b8862011-09-07 15:04:31 +02003791 mch_delay(10L, TRUE);
3792 continue;
3793 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02003794 if (wait_pid <= 0
3795# ifdef ECHILD
3796 && errno == ECHILD
3797# endif
3798 )
3799 break;
3800 }
3801 return wait_pid;
3802}
3803
Bram Moolenaar071d4272004-06-13 20:20:40 +00003804 int
3805mch_call_shell(cmd, options)
3806 char_u *cmd;
3807 int options; /* SHELL_*, see vim.h */
3808{
3809#ifdef VMS
3810 char *ifn = NULL;
3811 char *ofn = NULL;
3812#endif
3813 int tmode = cur_tmode;
3814#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3815 int x;
3816# ifndef __EMX__
3817 char_u *newcmd; /* only needed for unix */
3818# else
3819 /*
3820 * Set the preferred shell in the EMXSHELL environment variable (but
3821 * only if it is different from what is already in the environment).
3822 * Emx then takes care of whether to use "/c" or "-c" in an
3823 * intelligent way. Simply pass the whole thing to emx's system() call.
3824 * Emx also starts an interactive shell if system() is passed an empty
3825 * string.
3826 */
3827 char_u *p, *old;
3828
3829 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3830 {
3831 /* should check HAVE_SETENV, but I know we don't have it. */
3832 p = alloc(10 + strlen(p_sh));
3833 if (p)
3834 {
3835 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3836 putenv((char *)p); /* don't free the pointer! */
3837 }
3838 }
3839# endif
3840
3841 out_flush();
3842
3843 if (options & SHELL_COOKED)
3844 settmode(TMODE_COOK); /* set to normal mode */
3845
Bram Moolenaar62b42182010-09-21 22:09:37 +02003846# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3847 loose_clipboard();
3848# endif
3849
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850# ifdef __EMX__
3851 if (cmd == NULL)
3852 x = system(""); /* this starts an interactive shell in emx */
3853 else
3854 x = system((char *)cmd);
3855 /* system() returns -1 when error occurs in starting shell */
3856 if (x == -1 && !emsg_silent)
3857 {
3858 MSG_PUTS(_("\nCannot execute shell "));
3859 msg_outtrans(p_sh);
3860 msg_putchar('\n');
3861 }
3862# else /* not __EMX__ */
3863 if (cmd == NULL)
3864 x = system((char *)p_sh);
3865 else
3866 {
3867# ifdef VMS
3868 if (ofn = strchr((char *)cmd, '>'))
3869 *ofn++ = '\0';
3870 if (ifn = strchr((char *)cmd, '<'))
3871 {
3872 char *p;
3873
3874 *ifn++ = '\0';
3875 p = strchr(ifn,' '); /* chop off any trailing spaces */
3876 if (p)
3877 *p = '\0';
3878 }
3879 if (ofn)
3880 x = vms_sys((char *)cmd, ofn, ifn);
3881 else
3882 x = system((char *)cmd);
3883# else
3884 newcmd = lalloc(STRLEN(p_sh)
3885 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3886 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3887 if (newcmd == NULL)
3888 x = 0;
3889 else
3890 {
3891 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3892 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3893 (char *)p_shcf,
3894 (char *)cmd);
3895 x = system((char *)newcmd);
3896 vim_free(newcmd);
3897 }
3898# endif
3899 }
3900# ifdef VMS
3901 x = vms_sys_status(x);
3902# endif
3903 if (emsg_silent)
3904 ;
3905 else if (x == 127)
3906 MSG_PUTS(_("\nCannot execute shell sh\n"));
3907# endif /* __EMX__ */
3908 else if (x && !(options & SHELL_SILENT))
3909 {
3910 MSG_PUTS(_("\nshell returned "));
3911 msg_outnum((long)x);
3912 msg_putchar('\n');
3913 }
3914
3915 if (tmode == TMODE_RAW)
3916 settmode(TMODE_RAW); /* set to raw mode */
3917# ifdef FEAT_TITLE
3918 resettitle();
3919# endif
3920 return x;
3921
3922#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3923
Bram Moolenaardf177f62005-02-22 08:39:57 +00003924# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3925 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003926
3927 char_u *newcmd = NULL;
3928 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003929 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003930 pid_t wait_pid = 0;
3931# ifdef HAVE_UNION_WAIT
3932 union wait status;
3933# else
3934 int status = -1;
3935# endif
3936 int retval = -1;
3937 char **argv = NULL;
3938 int argc;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02003939 char_u *p_shcf_copy = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003940 int i;
3941 char_u *p;
3942 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003943 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003944# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003945 int pty_slave_fd = -1;
3946 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003947# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003948 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003949 int fd_fromshell[2];
3950 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003951# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003952 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003953# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003954 static char envbuf_Rows[20];
3955 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003956# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003957 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003958
Bram Moolenaar62b42182010-09-21 22:09:37 +02003959 newcmd = vim_strsave(p_sh);
3960 if (newcmd == NULL) /* out of memory */
3961 goto error;
3962
Bram Moolenaar071d4272004-06-13 20:20:40 +00003963 out_flush();
3964 if (options & SHELL_COOKED)
3965 settmode(TMODE_COOK); /* set to normal mode */
3966
Bram Moolenaar62b42182010-09-21 22:09:37 +02003967# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3968 loose_clipboard();
3969# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003970
3971 /*
3972 * Do this loop twice:
3973 * 1: find number of arguments
3974 * 2: separate them and build argv[]
3975 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003976 for (i = 0; i < 2; ++i)
3977 {
3978 p = newcmd;
3979 inquote = FALSE;
3980 argc = 0;
3981 for (;;)
3982 {
3983 if (i == 1)
3984 argv[argc] = (char *)p;
3985 ++argc;
3986 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3987 {
3988 if (*p == '"')
3989 inquote = !inquote;
3990 ++p;
3991 }
3992 if (*p == NUL)
3993 break;
3994 if (i == 1)
3995 *p++ = NUL;
3996 p = skipwhite(p);
3997 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003998 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003999 {
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004000 /*
4001 * Account for possible multiple args in p_shcf.
4002 */
4003 p = p_shcf;
4004 for (;;)
4005 {
4006 p = skiptowhite(p);
4007 if (*p == NUL)
4008 break;
4009 ++argc;
4010 p = skipwhite(p);
4011 }
4012
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
4014 if (argv == NULL) /* out of memory */
4015 goto error;
4016 }
4017 }
4018 if (cmd != NULL)
4019 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004020 char_u *s;
4021
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022 if (extra_shell_arg != NULL)
4023 argv[argc++] = (char *)extra_shell_arg;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004024
4025 /* Break 'shellcmdflag' into white separated parts. This doesn't
4026 * handle quoted strings, they are very unlikely to appear. */
4027 p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
4028 if (p_shcf_copy == NULL) /* out of memory */
4029 goto error;
4030 s = p_shcf_copy;
4031 p = p_shcf;
4032 while (*p != NUL)
4033 {
4034 argv[argc++] = (char *)s;
4035 while (*p && *p != ' ' && *p != TAB)
4036 *s++ = *p++;
4037 *s++ = NUL;
4038 p = skipwhite(p);
4039 }
4040
Bram Moolenaar071d4272004-06-13 20:20:40 +00004041 argv[argc++] = (char *)cmd;
4042 }
4043 argv[argc] = NULL;
4044
Bram Moolenaar071d4272004-06-13 20:20:40 +00004045 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004046 * For the GUI, when writing the output into the buffer and when reading
4047 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4048 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004049 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004050 if ((options & (SHELL_READ|SHELL_WRITE))
4051# ifdef FEAT_GUI
4052 || (gui.in_use && show_shell_mess)
4053# endif
4054 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004055 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004056# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004057 /*
4058 * Try to open a master pty.
4059 * If this works, open the slave pty.
4060 * If the slave can't be opened, close the master pty.
4061 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004062 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004063 {
4064 pty_master_fd = OpenPTY(&tty_name); /* open pty */
Bram Moolenaare70172e2011-08-04 19:36:52 +02004065 if (pty_master_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004066 {
Bram Moolenaare70172e2011-08-04 19:36:52 +02004067 /* Leaving out O_NOCTTY may lead to waitpid() always returning
4068 * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4069 * adding O_NOCTTY always works when defined. */
4070#ifdef O_NOCTTY
4071 pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4072#else
4073 pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4074#endif
4075 if (pty_slave_fd < 0)
4076 {
4077 close(pty_master_fd);
4078 pty_master_fd = -1;
4079 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004080 }
4081 }
4082 /*
4083 * If not opening a pty or it didn't work, try using pipes.
4084 */
4085 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004086# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004087 {
4088 pipe_error = (pipe(fd_toshell) < 0);
4089 if (!pipe_error) /* pipe create OK */
4090 {
4091 pipe_error = (pipe(fd_fromshell) < 0);
4092 if (pipe_error) /* pipe create failed */
4093 {
4094 close(fd_toshell[0]);
4095 close(fd_toshell[1]);
4096 }
4097 }
4098 if (pipe_error)
4099 {
4100 MSG_PUTS(_("\nCannot create pipes\n"));
4101 out_flush();
4102 }
4103 }
4104 }
4105
4106 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004107 {
4108# ifdef __BEOS__
4109 beos_cleanup_read_thread();
4110# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004111
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 if ((pid = fork()) == -1) /* maybe we should use vfork() */
4113 {
4114 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004115 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004116# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004117 || (gui.in_use && show_shell_mess)
4118# endif
4119 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004120 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004121# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122 if (pty_master_fd >= 0) /* close the pseudo tty */
4123 {
4124 close(pty_master_fd);
4125 close(pty_slave_fd);
4126 }
4127 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004128# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004129 {
4130 close(fd_toshell[0]);
4131 close(fd_toshell[1]);
4132 close(fd_fromshell[0]);
4133 close(fd_fromshell[1]);
4134 }
4135 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004136 }
4137 else if (pid == 0) /* child */
4138 {
4139 reset_signals(); /* handle signals normally */
4140
4141 if (!show_shell_mess || (options & SHELL_EXPAND))
4142 {
4143 int fd;
4144
4145 /*
4146 * Don't want to show any message from the shell. Can't just
4147 * close stdout and stderr though, because some systems will
4148 * break if you try to write to them after that, so we must
4149 * use dup() to replace them with something else -- webb
4150 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4151 * waiting for input.
4152 */
4153 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4154 fclose(stdin);
4155 fclose(stdout);
4156 fclose(stderr);
4157
4158 /*
4159 * If any of these open()'s and dup()'s fail, we just continue
4160 * anyway. It's not fatal, and on most systems it will make
4161 * no difference at all. On a few it will cause the execvp()
4162 * to exit with a non-zero status even when the completion
4163 * could be done, which is nothing too serious. If the open()
4164 * or dup() failed we'd just do the same thing ourselves
4165 * anyway -- webb
4166 */
4167 if (fd >= 0)
4168 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004169 ignored = dup(fd); /* To replace stdin (fd 0) */
4170 ignored = dup(fd); /* To replace stdout (fd 1) */
4171 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172
4173 /* Don't need this now that we've duplicated it */
4174 close(fd);
4175 }
4176 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004177 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004179 || gui.in_use
4180# endif
4181 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004182 {
4183
Bram Moolenaardf177f62005-02-22 08:39:57 +00004184# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004185 /* Create our own process group, so that the child and all its
4186 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004187 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004188 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004189 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004190 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004191# if defined(SIGHUP)
4192 /* When doing "!xterm&" and 'shell' is bash: the shell
4193 * will exit and send SIGHUP to all processes in its
4194 * group, killing the just started process. Ignore SIGHUP
4195 * to avoid that. (suggested by Simon Schubert)
4196 */
4197 signal(SIGHUP, SIG_IGN);
4198# endif
4199 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004200# endif
4201# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004202 if (pty_slave_fd >= 0)
4203 {
4204 /* push stream discipline modules */
4205 if (options & SHELL_COOKED)
4206 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004207# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004208 /* Try to become controlling tty (probably doesn't work,
4209 * unless run by root) */
4210 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004211# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004212 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004213# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004214 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004215# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004216 setenv("TERM", "dumb", 1);
4217 sprintf((char *)envbuf, "%ld", Rows);
4218 setenv("ROWS", (char *)envbuf, 1);
4219 sprintf((char *)envbuf, "%ld", Rows);
4220 setenv("LINES", (char *)envbuf, 1);
4221 sprintf((char *)envbuf, "%ld", Columns);
4222 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004223# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004224 /*
4225 * Putenv does not copy the string, it has to remain valid.
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004226 * Use a static array to avoid losing allocated memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004227 */
4228 putenv("TERM=dumb");
4229 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
4230 putenv(envbuf_Rows);
4231 sprintf(envbuf_Rows, "LINES=%ld", Rows);
4232 putenv(envbuf_Rows);
4233 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
4234 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004235# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004236
Bram Moolenaara5792f52005-11-23 21:25:05 +00004237 /*
4238 * stderr is only redirected when using the GUI, so that a
4239 * program like gpg can still access the terminal to get a
4240 * passphrase using stderr.
4241 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004242# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004243 if (pty_master_fd >= 0)
4244 {
4245 close(pty_master_fd); /* close master side of pty */
4246
4247 /* set up stdin/stdout/stderr for the child */
4248 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004249 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004250 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004251 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004252 if (gui.in_use)
4253 {
4254 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004255 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004256 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257
4258 close(pty_slave_fd); /* has been dupped, close it now */
4259 }
4260 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004261# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262 {
4263 /* set up stdin for the child */
4264 close(fd_toshell[1]);
4265 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004266 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004267 close(fd_toshell[0]);
4268
4269 /* set up stdout for the child */
4270 close(fd_fromshell[0]);
4271 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004272 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004273 close(fd_fromshell[1]);
4274
Bram Moolenaara5792f52005-11-23 21:25:05 +00004275# ifdef FEAT_GUI
4276 if (gui.in_use)
4277 {
4278 /* set up stderr for the child */
4279 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004280 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004281 }
4282# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004283 }
4284 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004285
Bram Moolenaar071d4272004-06-13 20:20:40 +00004286 /*
4287 * There is no type cast for the argv, because the type may be
4288 * different on different machines. This may cause a warning
4289 * message with strict compilers, don't worry about it.
4290 * Call _exit() instead of exit() to avoid closing the connection
4291 * to the X server (esp. with GTK, which uses atexit()).
4292 */
4293 execvp(argv[0], argv);
4294 _exit(EXEC_FAILED); /* exec failed, return failure code */
4295 }
4296 else /* parent */
4297 {
4298 /*
4299 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004300 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301 */
4302 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004303 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004304
4305 /*
4306 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004307 * This is also used to pipe stdin/stdout to/from the external
4308 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004310 if ((options & (SHELL_READ|SHELL_WRITE))
4311# ifdef FEAT_GUI
4312 || (gui.in_use && show_shell_mess)
4313# endif
4314 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004315 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004316# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004317 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004318# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004320# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4322 int ta_len = 0; /* valid bytes in ta_buf[] */
4323 int len;
4324 int p_more_save;
4325 int old_State;
4326 int c;
4327 int toshell_fd;
4328 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004329 garray_T ga;
4330 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004331# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4332 struct timeval start_tv;
4333# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334
Bram Moolenaardf177f62005-02-22 08:39:57 +00004335# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004336 if (pty_master_fd >= 0)
4337 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004338 fromshell_fd = pty_master_fd;
4339 toshell_fd = dup(pty_master_fd);
4340 }
4341 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004342# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004343 {
4344 close(fd_toshell[0]);
4345 close(fd_fromshell[1]);
4346 toshell_fd = fd_toshell[1];
4347 fromshell_fd = fd_fromshell[0];
4348 }
4349
4350 /*
4351 * Write to the child if there are typed characters.
4352 * Read from the child if there are characters available.
4353 * Repeat the reading a few times if more characters are
4354 * available. Need to check for typed keys now and then, but
4355 * not too often (delays when no chars are available).
4356 * This loop is quit if no characters can be read from the pty
4357 * (WaitForChar detected special condition), or there are no
4358 * characters available and the child has exited.
4359 * Only check if the child has exited when there is no more
4360 * output. The child may exit before all the output has
4361 * been printed.
4362 *
4363 * Currently this busy loops!
4364 * This can probably dead-lock when the write blocks!
4365 */
4366 p_more_save = p_more;
4367 p_more = FALSE;
4368 old_State = State;
4369 State = EXTERNCMD; /* don't redraw at window resize */
4370
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004371 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004372 {
4373 /* Fork a process that will write the lines to the
4374 * external program. */
4375 if ((wpid = fork()) == -1)
4376 {
4377 MSG_PUTS(_("\nCannot fork\n"));
4378 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004379 else if (wpid == 0) /* child */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004380 {
4381 linenr_T lnum = curbuf->b_op_start.lnum;
4382 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004383 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004384 size_t l;
4385
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004386 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004387 for (;;)
4388 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004389 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004390 if (l == 0)
4391 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004392 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004393 /* NL -> NUL translation */
4394 len = write(toshell_fd, "", (size_t)1);
4395 else
4396 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004397 char_u *s = vim_strchr(lp + written, NL);
4398
Bram Moolenaar89d40322006-08-29 15:30:07 +00004399 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004400 s == NULL ? l
4401 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004402 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004403 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004404 {
4405 /* Finished a line, add a NL, unless this line
4406 * should not have one. */
4407 if (lnum != curbuf->b_op_end.lnum
4408 || !curbuf->b_p_bin
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004409 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004410 && (lnum !=
4411 curbuf->b_ml.ml_line_count
4412 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004413 ignored = write(toshell_fd, "\n",
4414 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004415 ++lnum;
4416 if (lnum > curbuf->b_op_end.lnum)
4417 {
4418 /* finished all the lines, close pipe */
4419 close(toshell_fd);
4420 toshell_fd = -1;
4421 break;
4422 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004423 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004424 written = 0;
4425 }
4426 else if (len > 0)
4427 written += len;
4428 }
4429 _exit(0);
4430 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004431 else /* parent */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004432 {
4433 close(toshell_fd);
4434 toshell_fd = -1;
4435 }
4436 }
4437
4438 if (options & SHELL_READ)
4439 ga_init2(&ga, 1, BUFLEN);
4440
4441 noread_cnt = 0;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004442# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4443 gettimeofday(&start_tv, NULL);
4444# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445 for (;;)
4446 {
4447 /*
4448 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004449 * if there are any.
4450 * Don't do this if we are expanding wild cards (would eat
4451 * typeahead).
4452 * Don't do this when filtering and terminal is in cooked
4453 * mode, the shell command will handle the I/O. Avoids
4454 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004455 * Don't get characters when the child has already
4456 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004457 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004458 * while (noread_cnt > 4), avoids that ":r !ls" eats
4459 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004460 */
4461 len = 0;
4462 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004463 && ((options &
4464 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4465 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004466# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004467 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004468# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004469 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004470 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004471 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004472 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004473 if (ta_len == 0)
4474 {
4475 /* Get extra characters when we don't have any.
4476 * Reset the counter and timer. */
4477 noread_cnt = 0;
4478# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4479 gettimeofday(&start_tv, NULL);
4480# endif
4481 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4482 }
4483 if (ta_len > 0 || len > 0)
4484 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004485 /*
4486 * For pipes:
4487 * Check for CTRL-C: send interrupt signal to child.
4488 * Check for CTRL-D: EOF, close pipe to child.
4489 */
4490 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4491 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004492# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004493 /*
4494 * Send SIGINT to the child's group or all
4495 * processes in our group.
4496 */
4497 if (ta_buf[ta_len] == Ctrl_C
4498 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004499 {
4500# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004501 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004502# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004504# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004505 if (wpid > 0)
4506 kill(wpid, SIGINT);
4507 }
4508# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004509 if (pty_master_fd < 0 && toshell_fd >= 0
4510 && ta_buf[ta_len] == Ctrl_D)
4511 {
4512 close(toshell_fd);
4513 toshell_fd = -1;
4514 }
4515 }
4516
4517 /* replace K_BS by <BS> and K_DEL by <DEL> */
4518 for (i = ta_len; i < ta_len + len; ++i)
4519 {
4520 if (ta_buf[i] == CSI && len - i > 2)
4521 {
4522 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4523 if (c == K_DEL || c == K_KDEL || c == K_BS)
4524 {
4525 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4526 (size_t)(len - i - 2));
4527 if (c == K_DEL || c == K_KDEL)
4528 ta_buf[i] = DEL;
4529 else
4530 ta_buf[i] = Ctrl_H;
4531 len -= 2;
4532 }
4533 }
4534 else if (ta_buf[i] == '\r')
4535 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004536# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00004538 i += (*mb_ptr2len_len)(ta_buf + i,
4539 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004540# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004541 }
4542
4543 /*
4544 * For pipes: echo the typed characters.
4545 * For a pty this does not seem to work.
4546 */
4547 if (pty_master_fd < 0)
4548 {
4549 for (i = ta_len; i < ta_len + len; ++i)
4550 {
4551 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4552 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004553# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004554 else if (has_mbyte)
4555 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004556 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557
4558 msg_outtrans_len(ta_buf + i, l);
4559 i += l - 1;
4560 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004561# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562 else
4563 msg_outtrans_len(ta_buf + i, 1);
4564 }
4565 windgoto(msg_row, msg_col);
4566 out_flush();
4567 }
4568
4569 ta_len += len;
4570
4571 /*
4572 * Write the characters to the child, unless EOF has
4573 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004574 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004575 * When writing buffer lines, drop the typed
4576 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004577 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004578 if (options & SHELL_WRITE)
4579 ta_len = 0;
4580 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004581 {
4582 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4583 if (len > 0)
4584 {
4585 ta_len -= len;
4586 mch_memmove(ta_buf, ta_buf + len, ta_len);
4587 }
4588 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004590 }
4591
Bram Moolenaardf177f62005-02-22 08:39:57 +00004592 if (got_int)
4593 {
4594 /* CTRL-C sends a signal to the child, we ignore it
4595 * ourselves */
4596# ifdef HAVE_SETSID
4597 kill(-pid, SIGINT);
4598# else
4599 kill(0, SIGINT);
4600# endif
4601 if (wpid > 0)
4602 kill(wpid, SIGINT);
4603 got_int = FALSE;
4604 }
4605
Bram Moolenaar071d4272004-06-13 20:20:40 +00004606 /*
4607 * Check if the child has any characters to be printed.
4608 * Read them and write them to our window. Repeat this as
4609 * long as there is something to do, avoid the 10ms wait
4610 * for mch_inchar(), or sending typeahead characters to
4611 * the external process.
4612 * TODO: This should handle escape sequences, compatible
4613 * to some terminal (vt52?).
4614 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004615 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4617 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004618 len = read_eintr(fromshell_fd, buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004619# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004620 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004621# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004622 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004623# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004624 );
4625 if (len <= 0) /* end of file or error */
4626 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004627
4628 noread_cnt = 0;
4629 if (options & SHELL_READ)
4630 {
4631 /* Do NUL -> NL translation, append NL separated
4632 * lines to the current buffer. */
4633 for (i = 0; i < len; ++i)
4634 {
4635 if (buffer[i] == NL)
4636 append_ga_line(&ga);
4637 else if (buffer[i] == NUL)
4638 ga_append(&ga, NL);
4639 else
4640 ga_append(&ga, buffer[i]);
4641 }
4642 }
4643# ifdef FEAT_MBYTE
4644 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004645 {
4646 int l;
4647
Bram Moolenaardf177f62005-02-22 08:39:57 +00004648 len += buffer_off;
4649 buffer[len] = NUL;
4650
Bram Moolenaar071d4272004-06-13 20:20:40 +00004651 /* Check if the last character in buffer[] is
4652 * incomplete, keep these bytes for the next
4653 * round. */
4654 for (p = buffer; p < buffer + len; p += l)
4655 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004656 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657 if (l == 0)
4658 l = 1; /* NUL byte? */
4659 else if (MB_BYTE2LEN(*p) != l)
4660 break;
4661 }
4662 if (p == buffer) /* no complete character */
4663 {
4664 /* avoid getting stuck at an illegal byte */
4665 if (len >= 12)
4666 ++p;
4667 else
4668 {
4669 buffer_off = len;
4670 continue;
4671 }
4672 }
4673 c = *p;
4674 *p = NUL;
4675 msg_puts(buffer);
4676 if (p < buffer + len)
4677 {
4678 *p = c;
4679 buffer_off = (buffer + len) - p;
4680 mch_memmove(buffer, p, buffer_off);
4681 continue;
4682 }
4683 buffer_off = 0;
4684 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004685# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004686 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004687 {
4688 buffer[len] = NUL;
4689 msg_puts(buffer);
4690 }
4691
4692 windgoto(msg_row, msg_col);
4693 cursor_on();
4694 out_flush();
4695 if (got_int)
4696 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004697
4698# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4699 {
4700 struct timeval now_tv;
4701 long msec;
4702
4703 /* Avoid that we keep looping here without
4704 * checking for a CTRL-C for a long time. Don't
4705 * break out too often to avoid losing typeahead. */
4706 gettimeofday(&now_tv, NULL);
4707 msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
4708 + (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
4709 if (msec > 2000)
4710 {
4711 noread_cnt = 5;
4712 break;
4713 }
4714 }
4715# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004716 }
4717
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004718 /* If we already detected the child has finished break the
4719 * loop now. */
4720 if (wait_pid == pid)
4721 break;
4722
Bram Moolenaar071d4272004-06-13 20:20:40 +00004723 /*
4724 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004725 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004726 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004727# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004728 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004729# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004731# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004732 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4733 || (wait_pid == pid && WIFEXITED(status)))
4734 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004735 /* Don't break the loop yet, try reading more
4736 * characters from "fromshell_fd" first. When using
4737 * pipes there might still be something to read and
4738 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004739 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004740 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004741 else
4742 wait_pid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004743 }
4744finished:
4745 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004746 if (options & SHELL_READ)
4747 {
4748 if (ga.ga_len > 0)
4749 {
4750 append_ga_line(&ga);
4751 /* remember that the NL was missing */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004752 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004753 }
4754 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004755 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004756 ga_clear(&ga);
4757 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004758
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759 /*
4760 * Give all typeahead that wasn't used back to ui_inchar().
4761 */
4762 if (ta_len)
4763 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004764 State = old_State;
4765 if (toshell_fd >= 0)
4766 close(toshell_fd);
4767 close(fromshell_fd);
4768 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004769
4770 /*
4771 * Wait until our child has exited.
4772 * Ignore wait() returning pids of other children and returning
4773 * because of some signal like SIGWINCH.
4774 * Don't wait if wait_pid was already set above, indicating the
4775 * child already exited.
4776 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02004777 if (wait_pid != pid)
4778 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779
Bram Moolenaar624891f2010-10-13 16:22:09 +02004780# ifdef FEAT_GUI
4781 /* Close slave side of pty. Only do this after the child has
4782 * exited, otherwise the child may hang when it tries to write on
4783 * the pty. */
4784 if (pty_master_fd >= 0)
4785 close(pty_slave_fd);
4786# endif
4787
Bram Moolenaardf177f62005-02-22 08:39:57 +00004788 /* Make sure the child that writes to the external program is
4789 * dead. */
4790 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004791 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004792 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02004793 wait4pid(wpid, NULL);
4794 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004795
Bram Moolenaar071d4272004-06-13 20:20:40 +00004796 /*
4797 * Set to raw mode right now, otherwise a CTRL-C after
4798 * catch_signals() will kill Vim.
4799 */
4800 if (tmode == TMODE_RAW)
4801 settmode(TMODE_RAW);
4802 did_settmode = TRUE;
4803 set_signals();
4804
4805 if (WIFEXITED(status))
4806 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004807 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004808 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01004809 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004810 {
4811 if (retval == EXEC_FAILED)
4812 {
4813 MSG_PUTS(_("\nCannot execute shell "));
4814 msg_outtrans(p_sh);
4815 msg_putchar('\n');
4816 }
4817 else if (!(options & SHELL_SILENT))
4818 {
4819 MSG_PUTS(_("\nshell returned "));
4820 msg_outnum((long)retval);
4821 msg_putchar('\n');
4822 }
4823 }
4824 }
4825 else
4826 MSG_PUTS(_("\nCommand terminated\n"));
4827 }
4828 }
4829 vim_free(argv);
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004830 vim_free(p_shcf_copy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004831
4832error:
4833 if (!did_settmode)
4834 if (tmode == TMODE_RAW)
4835 settmode(TMODE_RAW); /* set to raw mode */
4836# ifdef FEAT_TITLE
4837 resettitle();
4838# endif
4839 vim_free(newcmd);
4840
4841 return retval;
4842
4843#endif /* USE_SYSTEM */
4844}
4845
4846/*
4847 * Check for CTRL-C typed by reading all available characters.
4848 * In cooked mode we should get SIGINT, no need to check.
4849 */
4850 void
4851mch_breakcheck()
4852{
4853 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4854 fill_input_buf(FALSE);
4855}
4856
4857/*
4858 * Wait "msec" msec until a character is available from the keyboard or from
4859 * inbuf[]. msec == -1 will block forever.
4860 * When a GUI is being used, this will never get called -- webb
4861 */
4862 static int
4863WaitForChar(msec)
4864 long msec;
4865{
4866#ifdef FEAT_MOUSE_GPM
4867 int gpm_process_wanted;
4868#endif
4869#ifdef FEAT_XCLIPBOARD
4870 int rest;
4871#endif
4872 int avail;
4873
4874 if (input_available()) /* something in inbuf[] */
4875 return 1;
4876
4877#if defined(FEAT_MOUSE_DEC)
4878 /* May need to query the mouse position. */
4879 if (WantQueryMouse)
4880 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004881 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004882 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4883 }
4884#endif
4885
4886 /*
4887 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4888 * events. This is a bit complicated, because they might both be defined.
4889 */
4890#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4891# ifdef FEAT_XCLIPBOARD
4892 rest = 0;
4893 if (do_xterm_trace())
4894 rest = msec;
4895# endif
4896 do
4897 {
4898# ifdef FEAT_XCLIPBOARD
4899 if (rest != 0)
4900 {
4901 msec = XT_TRACE_DELAY;
4902 if (rest >= 0 && rest < XT_TRACE_DELAY)
4903 msec = rest;
4904 if (rest >= 0)
4905 rest -= msec;
4906 }
4907# endif
4908# ifdef FEAT_MOUSE_GPM
4909 gpm_process_wanted = 0;
4910 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4911# else
4912 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4913# endif
4914 if (!avail)
4915 {
4916 if (input_available())
4917 return 1;
4918# ifdef FEAT_XCLIPBOARD
4919 if (rest == 0 || !do_xterm_trace())
4920# endif
4921 break;
4922 }
4923 }
4924 while (FALSE
4925# ifdef FEAT_MOUSE_GPM
4926 || (gpm_process_wanted && mch_gpm_process() == 0)
4927# endif
4928# ifdef FEAT_XCLIPBOARD
4929 || (!avail && rest != 0)
4930# endif
4931 );
4932
4933#else
4934 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4935#endif
4936 return avail;
4937}
4938
4939/*
4940 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02004941 * "msec" == 0 will check for characters once.
4942 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004943 * When a GUI is being used, this will not be used for input -- webb
4944 * Returns also, when a request from Sniff is waiting -- toni.
4945 * Or when a Linux GPM mouse event is waiting.
4946 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004947#if defined(__BEOS__)
4948 int
4949#else
4950 static int
4951#endif
4952RealWaitForChar(fd, msec, check_for_gpm)
4953 int fd;
4954 long msec;
Bram Moolenaar78a15312009-05-15 19:33:18 +00004955 int *check_for_gpm UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004956{
4957 int ret;
Bram Moolenaar67c53842010-05-22 18:28:27 +02004958#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02004959 int nb_fd = netbeans_filedesc();
Bram Moolenaar67c53842010-05-22 18:28:27 +02004960#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004961#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004962 static int busy = FALSE;
4963
4964 /* May retry getting characters after an event was handled. */
4965# define MAY_LOOP
4966
4967# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4968 /* Remember at what time we started, so that we know how much longer we
4969 * should wait after being interrupted. */
4970# define USE_START_TV
4971 struct timeval start_tv;
4972
4973 if (msec > 0 && (
4974# ifdef FEAT_XCLIPBOARD
4975 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004976# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004977 ||
4978# endif
4979# endif
4980# ifdef USE_XSMP
4981 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004982# ifdef FEAT_MZSCHEME
4983 ||
4984# endif
4985# endif
4986# ifdef FEAT_MZSCHEME
4987 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004988# endif
4989 ))
4990 gettimeofday(&start_tv, NULL);
4991# endif
4992
4993 /* Handle being called recursively. This may happen for the session
4994 * manager stuff, it may save the file, which does a breakcheck. */
4995 if (busy)
4996 return 0;
4997#endif
4998
4999#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00005000 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005001#endif
5002 {
5003#ifdef MAY_LOOP
5004 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005005# ifdef FEAT_MZSCHEME
5006 int mzquantum_used = FALSE;
5007# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005008#endif
5009#ifndef HAVE_SELECT
Bram Moolenaar67c53842010-05-22 18:28:27 +02005010 struct pollfd fds[6];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005011 int nfd;
5012# ifdef FEAT_XCLIPBOARD
5013 int xterm_idx = -1;
5014# endif
5015# ifdef FEAT_MOUSE_GPM
5016 int gpm_idx = -1;
5017# endif
5018# ifdef USE_XSMP
5019 int xsmp_idx = -1;
5020# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005021# ifdef FEAT_NETBEANS_INTG
5022 int nb_idx = -1;
5023# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005024 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005025
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005026# ifdef FEAT_MZSCHEME
5027 mzvim_check_threads();
5028 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5029 {
5030 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
5031 mzquantum_used = TRUE;
5032 }
5033# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005034 fds[0].fd = fd;
5035 fds[0].events = POLLIN;
5036 nfd = 1;
5037
5038# ifdef FEAT_SNIFF
5039# define SNIFF_IDX 1
5040 if (want_sniff_request)
5041 {
5042 fds[SNIFF_IDX].fd = fd_from_sniff;
5043 fds[SNIFF_IDX].events = POLLIN;
5044 nfd++;
5045 }
5046# endif
5047# ifdef FEAT_XCLIPBOARD
5048 if (xterm_Shell != (Widget)0)
5049 {
5050 xterm_idx = nfd;
5051 fds[nfd].fd = ConnectionNumber(xterm_dpy);
5052 fds[nfd].events = POLLIN;
5053 nfd++;
5054 }
5055# endif
5056# ifdef FEAT_MOUSE_GPM
5057 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5058 {
5059 gpm_idx = nfd;
5060 fds[nfd].fd = gpm_fd;
5061 fds[nfd].events = POLLIN;
5062 nfd++;
5063 }
5064# endif
5065# ifdef USE_XSMP
5066 if (xsmp_icefd != -1)
5067 {
5068 xsmp_idx = nfd;
5069 fds[nfd].fd = xsmp_icefd;
5070 fds[nfd].events = POLLIN;
5071 nfd++;
5072 }
5073# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005074#ifdef FEAT_NETBEANS_INTG
5075 if (nb_fd != -1)
5076 {
5077 nb_idx = nfd;
5078 fds[nfd].fd = nb_fd;
5079 fds[nfd].events = POLLIN;
5080 nfd++;
5081 }
5082#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005083
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005084 ret = poll(fds, nfd, towait);
5085# ifdef FEAT_MZSCHEME
5086 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005087 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005088 finished = FALSE;
5089# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005090
5091# ifdef FEAT_SNIFF
5092 if (ret < 0)
5093 sniff_disconnect(1);
5094 else if (want_sniff_request)
5095 {
5096 if (fds[SNIFF_IDX].revents & POLLHUP)
5097 sniff_disconnect(1);
5098 if (fds[SNIFF_IDX].revents & POLLIN)
5099 sniff_request_waiting = 1;
5100 }
5101# endif
5102# ifdef FEAT_XCLIPBOARD
5103 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
5104 {
5105 xterm_update(); /* Maybe we should hand out clipboard */
5106 if (--ret == 0 && !input_available())
5107 /* Try again */
5108 finished = FALSE;
5109 }
5110# endif
5111# ifdef FEAT_MOUSE_GPM
5112 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
5113 {
5114 *check_for_gpm = 1;
5115 }
5116# endif
5117# ifdef USE_XSMP
5118 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
5119 {
5120 if (fds[xsmp_idx].revents & POLLIN)
5121 {
5122 busy = TRUE;
5123 xsmp_handle_requests();
5124 busy = FALSE;
5125 }
5126 else if (fds[xsmp_idx].revents & POLLHUP)
5127 {
5128 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005129 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005130 xsmp_close();
5131 }
5132 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005133 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005134 }
5135# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005136#ifdef FEAT_NETBEANS_INTG
5137 if (ret > 0 && nb_idx != -1 && fds[nb_idx].revents & POLLIN)
5138 {
5139 netbeans_read();
5140 --ret;
5141 }
5142#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143
5144
5145#else /* HAVE_SELECT */
5146
5147 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005148 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005149 fd_set rfds, efds;
5150 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005151 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005152
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005153# ifdef FEAT_MZSCHEME
5154 mzvim_check_threads();
5155 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5156 {
5157 towait = p_mzq; /* don't wait longer than 'mzquantum' */
5158 mzquantum_used = TRUE;
5159 }
5160# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005161# ifdef __EMX__
5162 /* don't check for incoming chars if not in raw mode, because select()
5163 * always returns TRUE then (in some version of emx.dll) */
5164 if (curr_tmode != TMODE_RAW)
5165 return 0;
5166# endif
5167
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005168 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005169 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005170 tv.tv_sec = towait / 1000;
5171 tv.tv_usec = (towait % 1000) * (1000000/1000);
5172 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005173 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005174 else
5175 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005176
5177 /*
5178 * Select on ready for reading and exceptional condition (end of file).
5179 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005180select_eintr:
5181 FD_ZERO(&rfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005182 FD_ZERO(&efds);
5183 FD_SET(fd, &rfds);
5184# if !defined(__QNX__) && !defined(__CYGWIN32__)
5185 /* For QNX select() always returns 1 if this is set. Why? */
5186 FD_SET(fd, &efds);
5187# endif
5188 maxfd = fd;
5189
5190# ifdef FEAT_SNIFF
5191 if (want_sniff_request)
5192 {
5193 FD_SET(fd_from_sniff, &rfds);
5194 FD_SET(fd_from_sniff, &efds);
5195 if (maxfd < fd_from_sniff)
5196 maxfd = fd_from_sniff;
5197 }
5198# endif
5199# ifdef FEAT_XCLIPBOARD
5200 if (xterm_Shell != (Widget)0)
5201 {
5202 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
5203 if (maxfd < ConnectionNumber(xterm_dpy))
5204 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02005205
5206 /* An event may have already been read but not handled. In
5207 * particulary, XFlush may cause this. */
5208 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005209 }
5210# endif
5211# ifdef FEAT_MOUSE_GPM
5212 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5213 {
5214 FD_SET(gpm_fd, &rfds);
5215 FD_SET(gpm_fd, &efds);
5216 if (maxfd < gpm_fd)
5217 maxfd = gpm_fd;
5218 }
5219# endif
5220# ifdef USE_XSMP
5221 if (xsmp_icefd != -1)
5222 {
5223 FD_SET(xsmp_icefd, &rfds);
5224 FD_SET(xsmp_icefd, &efds);
5225 if (maxfd < xsmp_icefd)
5226 maxfd = xsmp_icefd;
5227 }
5228# endif
Bram Moolenaardd82d692012-08-15 17:26:57 +02005229# ifdef FEAT_NETBEANS_INTG
Bram Moolenaar67c53842010-05-22 18:28:27 +02005230 if (nb_fd != -1)
5231 {
5232 FD_SET(nb_fd, &rfds);
5233 if (maxfd < nb_fd)
5234 maxfd = nb_fd;
5235 }
Bram Moolenaardd82d692012-08-15 17:26:57 +02005236# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005237
5238# ifdef OLD_VMS
5239 /* Old VMS as v6.2 and older have broken select(). It waits more than
5240 * required. Should not be used */
5241 ret = 0;
5242# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005243 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
5244# endif
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005245# ifdef EINTR
5246 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005247 {
5248 /* Check whether window has been resized, EINTR may be caused by
5249 * SIGWINCH. */
5250 if (do_resize)
5251 handle_resize();
5252
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005253 /* Interrupted by a signal, need to try again. We ignore msec
5254 * here, because we do want to check even after a timeout if
5255 * characters are available. Needed for reading output of an
5256 * external command after the process has finished. */
5257 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005258 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005259# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00005260# ifdef __TANDEM
5261 if (ret == -1 && errno == ENOTSUP)
5262 {
5263 FD_ZERO(&rfds);
5264 FD_ZERO(&efds);
5265 ret = 0;
5266 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005267# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005268# ifdef FEAT_MZSCHEME
5269 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005270 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005271 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005272# endif
5273
5274# ifdef FEAT_SNIFF
5275 if (ret < 0 )
5276 sniff_disconnect(1);
5277 else if (ret > 0 && want_sniff_request)
5278 {
5279 if (FD_ISSET(fd_from_sniff, &efds))
5280 sniff_disconnect(1);
5281 if (FD_ISSET(fd_from_sniff, &rfds))
5282 sniff_request_waiting = 1;
5283 }
5284# endif
5285# ifdef FEAT_XCLIPBOARD
5286 if (ret > 0 && xterm_Shell != (Widget)0
5287 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
5288 {
5289 xterm_update(); /* Maybe we should hand out clipboard */
5290 /* continue looping when we only got the X event and the input
5291 * buffer is empty */
5292 if (--ret == 0 && !input_available())
5293 {
5294 /* Try again */
5295 finished = FALSE;
5296 }
5297 }
5298# endif
5299# ifdef FEAT_MOUSE_GPM
5300 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
5301 {
5302 if (FD_ISSET(gpm_fd, &efds))
5303 gpm_close();
5304 else if (FD_ISSET(gpm_fd, &rfds))
5305 *check_for_gpm = 1;
5306 }
5307# endif
5308# ifdef USE_XSMP
5309 if (ret > 0 && xsmp_icefd != -1)
5310 {
5311 if (FD_ISSET(xsmp_icefd, &efds))
5312 {
5313 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005314 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005315 xsmp_close();
5316 if (--ret == 0)
5317 finished = FALSE; /* keep going if event was only one */
5318 }
5319 else if (FD_ISSET(xsmp_icefd, &rfds))
5320 {
5321 busy = TRUE;
5322 xsmp_handle_requests();
5323 busy = FALSE;
5324 if (--ret == 0)
5325 finished = FALSE; /* keep going if event was only one */
5326 }
5327 }
5328# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005329#ifdef FEAT_NETBEANS_INTG
5330 if (ret > 0 && nb_fd != -1 && FD_ISSET(nb_fd, &rfds))
5331 {
5332 netbeans_read();
5333 --ret;
5334 }
5335#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005336
5337#endif /* HAVE_SELECT */
5338
5339#ifdef MAY_LOOP
5340 if (finished || msec == 0)
5341 break;
5342
5343 /* We're going to loop around again, find out for how long */
5344 if (msec > 0)
5345 {
5346# ifdef USE_START_TV
5347 struct timeval mtv;
5348
5349 /* Compute remaining wait time. */
5350 gettimeofday(&mtv, NULL);
5351 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
5352 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
5353# else
5354 /* Guess we got interrupted halfway. */
5355 msec = msec / 2;
5356# endif
5357 if (msec <= 0)
5358 break; /* waited long enough */
5359 }
5360#endif
5361 }
5362
5363 return (ret > 0);
5364}
5365
5366#ifndef VMS
5367
5368#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00005369/*
Bram Moolenaar02743632005-07-25 20:42:36 +00005370 * Expand a path into all matching files and/or directories. Handles "*",
5371 * "?", "[a-z]", "**", etc.
5372 * "path" has backslashes before chars that are not to be expanded.
5373 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005374 */
5375 int
5376mch_expandpath(gap, path, flags)
5377 garray_T *gap;
5378 char_u *path;
5379 int flags; /* EW_* flags */
5380{
Bram Moolenaar02743632005-07-25 20:42:36 +00005381 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005382}
5383#endif
5384
5385/*
5386 * mch_expand_wildcards() - this code does wild-card pattern matching using
5387 * the shell
5388 *
5389 * return OK for success, FAIL for error (you may lose some memory) and put
5390 * an error message in *file.
5391 *
5392 * num_pat is number of input patterns
5393 * pat is array of pointers to input patterns
5394 * num_file is pointer to number of matched file names
5395 * file is pointer to array of pointers to matched file names
5396 */
5397
5398#ifndef SEEK_SET
5399# define SEEK_SET 0
5400#endif
5401#ifndef SEEK_END
5402# define SEEK_END 2
5403#endif
5404
Bram Moolenaar5555acc2006-04-07 21:33:12 +00005405#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00005406
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407 int
5408mch_expand_wildcards(num_pat, pat, num_file, file, flags)
5409 int num_pat;
5410 char_u **pat;
5411 int *num_file;
5412 char_u ***file;
5413 int flags; /* EW_* flags */
5414{
5415 int i;
5416 size_t len;
5417 char_u *p;
5418 int dir;
5419#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00005420 /*
5421 * This is the OS/2 implementation.
5422 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005423# define EXPL_ALLOC_INC 16
5424 char_u **expl_files;
5425 size_t files_alloced, files_free;
5426 char_u *buf;
5427 int has_wildcard;
5428
5429 *num_file = 0; /* default: no files found */
5430 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
5431 files_free = EXPL_ALLOC_INC; /* how much space is not used */
5432 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
5433 if (*file == NULL)
5434 return FAIL;
5435
5436 for (; num_pat > 0; num_pat--, pat++)
5437 {
5438 expl_files = NULL;
5439 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
5440 /* expand environment var or home dir */
5441 buf = expand_env_save(*pat);
5442 else
5443 buf = vim_strsave(*pat);
5444 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005445 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005446 if (has_wildcard) /* yes, so expand them */
5447 expl_files = (char_u **)_fnexplode(buf);
5448
5449 /*
5450 * return value of buf if no wildcards left,
5451 * OR if no match AND EW_NOTFOUND is set.
5452 */
5453 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
5454 || (expl_files == NULL && (flags & EW_NOTFOUND)))
5455 { /* simply save the current contents of *buf */
5456 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
5457 if (expl_files != NULL)
5458 {
5459 expl_files[0] = vim_strsave(buf);
5460 expl_files[1] = NULL;
5461 }
5462 }
5463 vim_free(buf);
5464
5465 /*
5466 * Count number of names resulting from expansion,
5467 * At the same time add a backslash to the end of names that happen to
5468 * be directories, and replace slashes with backslashes.
5469 */
5470 if (expl_files)
5471 {
5472 for (i = 0; (p = expl_files[i]) != NULL; i++)
5473 {
5474 dir = mch_isdir(p);
5475 /* If we don't want dirs and this is one, skip it */
5476 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5477 continue;
5478
Bram Moolenaara2031822006-03-07 22:29:51 +00005479 /* Skip files that are not executable if we check for that. */
5480 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
5481 continue;
5482
Bram Moolenaar071d4272004-06-13 20:20:40 +00005483 if (--files_free == 0)
5484 {
5485 /* need more room in table of pointers */
5486 files_alloced += EXPL_ALLOC_INC;
5487 *file = (char_u **)vim_realloc(*file,
5488 sizeof(char_u **) * files_alloced);
5489 if (*file == NULL)
5490 {
5491 EMSG(_(e_outofmem));
5492 *num_file = 0;
5493 return FAIL;
5494 }
5495 files_free = EXPL_ALLOC_INC;
5496 }
5497 slash_adjust(p);
5498 if (dir)
5499 {
5500 /* For a directory we add a '/', unless it's already
5501 * there. */
5502 len = STRLEN(p);
5503 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5504 {
5505 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005506 if (!after_pathsep((*file)[*num_file],
5507 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005508 {
5509 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005510 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005511 }
5512 }
5513 }
5514 else
5515 {
5516 (*file)[*num_file] = vim_strsave(p);
5517 }
5518
5519 /*
5520 * Error message already given by either alloc or vim_strsave.
5521 * Should return FAIL, but returning OK works also.
5522 */
5523 if ((*file)[*num_file] == NULL)
5524 break;
5525 (*num_file)++;
5526 }
5527 _fnexplodefree((char **)expl_files);
5528 }
5529 }
5530 return OK;
5531
5532#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005533 /*
5534 * This is the non-OS/2 implementation (really Unix).
5535 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005536 int j;
5537 char_u *tempname;
5538 char_u *command;
5539 FILE *fd;
5540 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005541#define STYLE_ECHO 0 /* use "echo", the default */
5542#define STYLE_GLOB 1 /* use "glob", for csh */
5543#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5544#define STYLE_PRINT 3 /* use "print -N", for zsh */
5545#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5546 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005547 int shell_style = STYLE_ECHO;
5548 int check_spaces;
5549 static int did_find_nul = FALSE;
5550 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005551 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005552 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005553
5554 *num_file = 0; /* default: no files found */
5555 *file = NULL;
5556
5557 /*
5558 * If there are no wildcards, just copy the names to allocated memory.
5559 * Saves a lot of time, because we don't have to start a new shell.
5560 */
5561 if (!have_wildcard(num_pat, pat))
5562 return save_patterns(num_pat, pat, num_file, file);
5563
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005564# ifdef HAVE_SANDBOX
5565 /* Don't allow any shell command in the sandbox. */
5566 if (sandbox != 0 && check_secure())
5567 return FAIL;
5568# endif
5569
Bram Moolenaar071d4272004-06-13 20:20:40 +00005570 /*
5571 * Don't allow the use of backticks in secure and restricted mode.
5572 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005573 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005574 for (i = 0; i < num_pat; ++i)
5575 if (vim_strchr(pat[i], '`') != NULL
5576 && (check_restricted() || check_secure()))
5577 return FAIL;
5578
5579 /*
5580 * get a name for the temp file
5581 */
5582 if ((tempname = vim_tempname('o')) == NULL)
5583 {
5584 EMSG(_(e_notmp));
5585 return FAIL;
5586 }
5587
5588 /*
5589 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005590 * file.
5591 * STYLE_BT: NL separated
5592 * If expanding `cmd` execute it directly.
5593 * STYLE_GLOB: NUL separated
5594 * If we use *csh, "glob" will work better than "echo".
5595 * STYLE_PRINT: NL or NUL separated
5596 * If we use *zsh, "print -N" will work better than "glob".
5597 * STYLE_VIMGLOB: NL separated
5598 * If we use *sh*, we define "vimglob()".
5599 * STYLE_ECHO: space separated.
5600 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005601 */
5602 if (num_pat == 1 && *pat[0] == '`'
5603 && (len = STRLEN(pat[0])) > 2
5604 && *(pat[0] + len - 1) == '`')
5605 shell_style = STYLE_BT;
5606 else if ((len = STRLEN(p_sh)) >= 3)
5607 {
5608 if (STRCMP(p_sh + len - 3, "csh") == 0)
5609 shell_style = STYLE_GLOB;
5610 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5611 shell_style = STYLE_PRINT;
5612 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005613 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5614 "sh") != NULL)
5615 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005616
Bram Moolenaarc7247912008-01-13 12:54:11 +00005617 /* Compute the length of the command. We need 2 extra bytes: for the
5618 * optional '&' and for the NUL.
5619 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005620 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005621 if (shell_style == STYLE_VIMGLOB)
5622 len += STRLEN(sh_vimglob_func);
5623
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005624 for (i = 0; i < num_pat; ++i)
5625 {
5626 /* Count the length of the patterns in the same way as they are put in
5627 * "command" below. */
5628#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005629 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005630#else
5631 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005632 for (j = 0; pat[i][j] != NUL; ++j)
5633 {
5634 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5635 ++len; /* may add a backslash */
5636 ++len;
5637 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005638#endif
5639 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005640 command = alloc(len);
5641 if (command == NULL)
5642 {
5643 /* out of memory */
5644 vim_free(tempname);
5645 return FAIL;
5646 }
5647
5648 /*
5649 * Build the shell command:
5650 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5651 * recognizes this).
5652 * - Add the shell command to print the expanded names.
5653 * - Add the temp file name.
5654 * - Add the file name patterns.
5655 */
5656 if (shell_style == STYLE_BT)
5657 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005658 /* change `command; command& ` to (command; command ) */
5659 STRCPY(command, "(");
5660 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005661 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005662 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005663 while (p > command && vim_iswhite(*p))
5664 --p;
5665 if (*p == '&') /* remove trailing '&' */
5666 {
5667 ampersent = TRUE;
5668 *p = ' ';
5669 }
5670 STRCAT(command, ">");
5671 }
5672 else
5673 {
5674 if (flags & EW_NOTFOUND)
5675 STRCPY(command, "set nonomatch; ");
5676 else
5677 STRCPY(command, "unset nonomatch; ");
5678 if (shell_style == STYLE_GLOB)
5679 STRCAT(command, "glob >");
5680 else if (shell_style == STYLE_PRINT)
5681 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005682 else if (shell_style == STYLE_VIMGLOB)
5683 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005684 else
5685 STRCAT(command, "echo >");
5686 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005687
Bram Moolenaar071d4272004-06-13 20:20:40 +00005688 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005689
Bram Moolenaar071d4272004-06-13 20:20:40 +00005690 if (shell_style != STYLE_BT)
5691 for (i = 0; i < num_pat; ++i)
5692 {
5693 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005694 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005695 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005696#ifdef USE_SYSTEM
5697 STRCAT(command, " \"");
5698 STRCAT(command, pat[i]);
5699 STRCAT(command, "\"");
5700#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005701 int intick = FALSE;
5702
Bram Moolenaar071d4272004-06-13 20:20:40 +00005703 p = command + STRLEN(command);
5704 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005705 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005706 {
5707 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005708 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005709 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5710 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005711 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005712 * backslash inside backticks, before a special character
5713 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005714 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005715 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5716 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005717 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005718 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005719 }
5720 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005721 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005722 /* Put a backslash before a special character, but not
5723 * when inside ``. */
5724 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005725
5726 /* Copy one character. */
5727 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005728 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005729 *p = NUL;
5730#endif
5731 }
5732 if (flags & EW_SILENT)
5733 show_shell_mess = FALSE;
5734 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00005735 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005736
5737 /*
5738 * Using zsh -G: If a pattern has no matches, it is just deleted from
5739 * the argument list, otherwise zsh gives an error message and doesn't
5740 * expand any other pattern.
5741 */
5742 if (shell_style == STYLE_PRINT)
5743 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5744
5745 /*
5746 * If we use -f then shell variables set in .cshrc won't get expanded.
5747 * vi can do it, so we will too, but it is only necessary if there is a "$"
5748 * in one of the patterns, otherwise we can still use the fast option.
5749 */
5750 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5751 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5752
5753 /*
5754 * execute the shell command
5755 */
5756 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5757
5758 /* When running in the background, give it some time to create the temp
5759 * file, but don't wait for it to finish. */
5760 if (ampersent)
5761 mch_delay(10L, TRUE);
5762
5763 extra_shell_arg = NULL; /* cleanup */
5764 show_shell_mess = TRUE;
5765 vim_free(command);
5766
Bram Moolenaarc7247912008-01-13 12:54:11 +00005767 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005768 {
5769 mch_remove(tempname);
5770 vim_free(tempname);
5771 /*
5772 * With interactive completion, the error message is not printed.
5773 * However with USE_SYSTEM, I don't know how to turn off error messages
5774 * from the shell, so screen may still get messed up -- webb.
5775 */
5776#ifndef USE_SYSTEM
5777 if (!(flags & EW_SILENT))
5778#endif
5779 {
5780 redraw_later_clear(); /* probably messed up screen */
5781 msg_putchar('\n'); /* clear bottom line quickly */
5782 cmdline_row = Rows - 1; /* continue on last line */
5783#ifdef USE_SYSTEM
5784 if (!(flags & EW_SILENT))
5785#endif
5786 {
5787 MSG(_(e_wildexpand));
5788 msg_start(); /* don't overwrite this message */
5789 }
5790 }
5791 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5792 * EW_NOTFOUND is given */
5793 if (shell_style == STYLE_BT)
5794 return FAIL;
5795 goto notfound;
5796 }
5797
5798 /*
5799 * read the names from the file into memory
5800 */
5801 fd = fopen((char *)tempname, READBIN);
5802 if (fd == NULL)
5803 {
5804 /* Something went wrong, perhaps a file name with a special char. */
5805 if (!(flags & EW_SILENT))
5806 {
5807 MSG(_(e_wildexpand));
5808 msg_start(); /* don't overwrite this message */
5809 }
5810 vim_free(tempname);
5811 goto notfound;
5812 }
5813 fseek(fd, 0L, SEEK_END);
5814 len = ftell(fd); /* get size of temp file */
5815 fseek(fd, 0L, SEEK_SET);
5816 buffer = alloc(len + 1);
5817 if (buffer == NULL)
5818 {
5819 /* out of memory */
5820 mch_remove(tempname);
5821 vim_free(tempname);
5822 fclose(fd);
5823 return FAIL;
5824 }
5825 i = fread((char *)buffer, 1, len, fd);
5826 fclose(fd);
5827 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00005828 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005829 {
5830 /* unexpected read error */
5831 EMSG2(_(e_notread), tempname);
5832 vim_free(tempname);
5833 vim_free(buffer);
5834 return FAIL;
5835 }
5836 vim_free(tempname);
5837
Bram Moolenaarc7247912008-01-13 12:54:11 +00005838# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5840 p = buffer;
5841 for (i = 0; i < len; ++i)
5842 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5843 *p++ = buffer[i];
5844 len = p - buffer;
5845# endif
5846
5847
5848 /* file names are separated with Space */
5849 if (shell_style == STYLE_ECHO)
5850 {
5851 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5852 p = buffer;
5853 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5854 {
5855 while (*p != ' ' && *p != '\n')
5856 ++p;
5857 p = skipwhite(p); /* skip to next entry */
5858 }
5859 }
5860 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005861 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005862 {
5863 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5864 p = buffer;
5865 for (i = 0; *p != NUL; ++i) /* count number of entries */
5866 {
5867 while (*p != '\n' && *p != NUL)
5868 ++p;
5869 if (*p != NUL)
5870 ++p;
5871 p = skipwhite(p); /* skip leading white space */
5872 }
5873 }
5874 /* file names are separated with NUL */
5875 else
5876 {
5877 /*
5878 * Some versions of zsh use spaces instead of NULs to separate
5879 * results. Only do this when there is no NUL before the end of the
5880 * buffer, otherwise we would never be able to use file names with
5881 * embedded spaces when zsh does use NULs.
5882 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5883 * don't check for spaces again.
5884 */
5885 check_spaces = FALSE;
5886 if (shell_style == STYLE_PRINT && !did_find_nul)
5887 {
5888 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02005889 buffer[len] = NUL;
Bram Moolenaar78a15312009-05-15 19:33:18 +00005890 if (len && (int)STRLEN(buffer) < (int)len - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005891 did_find_nul = TRUE;
5892 else
5893 check_spaces = TRUE;
5894 }
5895
5896 /*
5897 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5898 * already is one, for STYLE_GLOB it needs to be added.
5899 */
5900 if (len && buffer[len - 1] == NUL)
5901 --len;
5902 else
5903 buffer[len] = NUL;
5904 i = 0;
5905 for (p = buffer; p < buffer + len; ++p)
5906 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5907 {
5908 ++i;
5909 *p = NUL;
5910 }
5911 if (len)
5912 ++i; /* count last entry */
5913 }
5914 if (i == 0)
5915 {
5916 /*
5917 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5918 * /bin/sh will happily expand it to nothing rather than returning an
5919 * error; and hey, it's good to check anyway -- webb.
5920 */
5921 vim_free(buffer);
5922 goto notfound;
5923 }
5924 *num_file = i;
5925 *file = (char_u **)alloc(sizeof(char_u *) * i);
5926 if (*file == NULL)
5927 {
5928 /* out of memory */
5929 vim_free(buffer);
5930 return FAIL;
5931 }
5932
5933 /*
5934 * Isolate the individual file names.
5935 */
5936 p = buffer;
5937 for (i = 0; i < *num_file; ++i)
5938 {
5939 (*file)[i] = p;
5940 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005941 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
5942 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005943 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00005944 while (!(shell_style == STYLE_ECHO && *p == ' ')
5945 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005946 ++p;
5947 if (p == buffer + len) /* last entry */
5948 *p = NUL;
5949 else
5950 {
5951 *p++ = NUL;
5952 p = skipwhite(p); /* skip to next entry */
5953 }
5954 }
5955 else /* NUL separates */
5956 {
5957 while (*p && p < buffer + len) /* skip entry */
5958 ++p;
5959 ++p; /* skip NUL */
5960 }
5961 }
5962
5963 /*
5964 * Move the file names to allocated memory.
5965 */
5966 for (j = 0, i = 0; i < *num_file; ++i)
5967 {
5968 /* Require the files to exist. Helps when using /bin/sh */
5969 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5970 continue;
5971
5972 /* check if this entry should be included */
5973 dir = (mch_isdir((*file)[i]));
5974 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5975 continue;
5976
Bram Moolenaara2031822006-03-07 22:29:51 +00005977 /* Skip files that are not executable if we check for that. */
5978 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
5979 continue;
5980
Bram Moolenaar071d4272004-06-13 20:20:40 +00005981 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5982 if (p)
5983 {
5984 STRCPY(p, (*file)[i]);
5985 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00005986 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005987 (*file)[j++] = p;
5988 }
5989 }
5990 vim_free(buffer);
5991 *num_file = j;
5992
5993 if (*num_file == 0) /* rejected all entries */
5994 {
5995 vim_free(*file);
5996 *file = NULL;
5997 goto notfound;
5998 }
5999
6000 return OK;
6001
6002notfound:
6003 if (flags & EW_NOTFOUND)
6004 return save_patterns(num_pat, pat, num_file, file);
6005 return FAIL;
6006
6007#endif /* __EMX__ */
6008}
6009
6010#endif /* VMS */
6011
6012#ifndef __EMX__
6013 static int
6014save_patterns(num_pat, pat, num_file, file)
6015 int num_pat;
6016 char_u **pat;
6017 int *num_file;
6018 char_u ***file;
6019{
6020 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006021 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006022
6023 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
6024 if (*file == NULL)
6025 return FAIL;
6026 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006027 {
6028 s = vim_strsave(pat[i]);
6029 if (s != NULL)
6030 /* Be compatible with expand_filename(): halve the number of
6031 * backslashes. */
6032 backslash_halve(s);
6033 (*file)[i] = s;
6034 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006035 *num_file = num_pat;
6036 return OK;
6037}
6038#endif
6039
6040
6041/*
6042 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
6043 * expand.
6044 */
6045 int
6046mch_has_exp_wildcard(p)
6047 char_u *p;
6048{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006049 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006050 {
6051#ifndef OS2
6052 if (*p == '\\' && p[1] != NUL)
6053 ++p;
6054 else
6055#endif
6056 if (vim_strchr((char_u *)
6057#ifdef VMS
6058 "*?%"
6059#else
6060# ifdef OS2
6061 "*?"
6062# else
6063 "*?[{'"
6064# endif
6065#endif
6066 , *p) != NULL)
6067 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006068 }
6069 return FALSE;
6070}
6071
6072/*
6073 * Return TRUE if the string "p" contains a wildcard.
6074 * Don't recognize '~' at the end as a wildcard.
6075 */
6076 int
6077mch_has_wildcard(p)
6078 char_u *p;
6079{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006080 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006081 {
6082#ifndef OS2
6083 if (*p == '\\' && p[1] != NUL)
6084 ++p;
6085 else
6086#endif
6087 if (vim_strchr((char_u *)
6088#ifdef VMS
6089 "*?%$"
6090#else
6091# ifdef OS2
6092# ifdef VIM_BACKTICK
6093 "*?$`"
6094# else
6095 "*?$"
6096# endif
6097# else
6098 "*?[{`'$"
6099# endif
6100#endif
6101 , *p) != NULL
6102 || (*p == '~' && p[1] != NUL))
6103 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006104 }
6105 return FALSE;
6106}
6107
6108#ifndef __EMX__
6109 static int
6110have_wildcard(num, file)
6111 int num;
6112 char_u **file;
6113{
6114 int i;
6115
6116 for (i = 0; i < num; i++)
6117 if (mch_has_wildcard(file[i]))
6118 return 1;
6119 return 0;
6120}
6121
6122 static int
6123have_dollars(num, file)
6124 int num;
6125 char_u **file;
6126{
6127 int i;
6128
6129 for (i = 0; i < num; i++)
6130 if (vim_strchr(file[i], '$') != NULL)
6131 return TRUE;
6132 return FALSE;
6133}
6134#endif /* ifndef __EMX__ */
6135
6136#ifndef HAVE_RENAME
6137/*
6138 * Scaled-down version of rename(), which is missing in Xenix.
6139 * This version can only move regular files and will fail if the
6140 * destination exists.
6141 */
6142 int
6143mch_rename(src, dest)
6144 const char *src, *dest;
6145{
6146 struct stat st;
6147
6148 if (stat(dest, &st) >= 0) /* fail if destination exists */
6149 return -1;
6150 if (link(src, dest) != 0) /* link file to new name */
6151 return -1;
6152 if (mch_remove(src) == 0) /* delete link to old name */
6153 return 0;
6154 return -1;
6155}
6156#endif /* !HAVE_RENAME */
6157
6158#ifdef FEAT_MOUSE_GPM
6159/*
6160 * Initializes connection with gpm (if it isn't already opened)
6161 * Return 1 if succeeded (or connection already opened), 0 if failed
6162 */
6163 static int
6164gpm_open()
6165{
6166 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
6167
6168 if (!gpm_flag)
6169 {
6170 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
6171 gpm_connect.defaultMask = ~GPM_HARD;
6172 /* Default handling for mouse move*/
6173 gpm_connect.minMod = 0; /* Handle any modifier keys */
6174 gpm_connect.maxMod = 0xffff;
6175 if (Gpm_Open(&gpm_connect, 0) > 0)
6176 {
6177 /* gpm library tries to handling TSTP causes
6178 * problems. Anyways, we close connection to Gpm whenever
6179 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006180 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00006181 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006182# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00006183 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006184# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006185 return 1; /* succeed */
6186 }
6187 if (gpm_fd == -2)
6188 Gpm_Close(); /* We don't want to talk to xterm via gpm */
6189 return 0;
6190 }
6191 return 1; /* already open */
6192}
6193
6194/*
6195 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00006196 */
6197 static void
6198gpm_close()
6199{
6200 if (gpm_flag && gpm_fd >= 0) /* if Open */
6201 Gpm_Close();
6202}
6203
6204/* Reads gpm event and adds special keys to input buf. Returns length of
6205 * generated key sequence.
6206 * This function is made after gui_send_mouse_event
6207 */
6208 static int
6209mch_gpm_process()
6210{
6211 int button;
6212 static Gpm_Event gpm_event;
6213 char_u string[6];
6214 int_u vim_modifiers;
6215 int row,col;
6216 unsigned char buttons_mask;
6217 unsigned char gpm_modifiers;
6218 static unsigned char old_buttons = 0;
6219
6220 Gpm_GetEvent(&gpm_event);
6221
6222#ifdef FEAT_GUI
6223 /* Don't put events in the input queue now. */
6224 if (hold_gui_events)
6225 return 0;
6226#endif
6227
6228 row = gpm_event.y - 1;
6229 col = gpm_event.x - 1;
6230
6231 string[0] = ESC; /* Our termcode */
6232 string[1] = 'M';
6233 string[2] = 'G';
6234 switch (GPM_BARE_EVENTS(gpm_event.type))
6235 {
6236 case GPM_DRAG:
6237 string[3] = MOUSE_DRAG;
6238 break;
6239 case GPM_DOWN:
6240 buttons_mask = gpm_event.buttons & ~old_buttons;
6241 old_buttons = gpm_event.buttons;
6242 switch (buttons_mask)
6243 {
6244 case GPM_B_LEFT:
6245 button = MOUSE_LEFT;
6246 break;
6247 case GPM_B_MIDDLE:
6248 button = MOUSE_MIDDLE;
6249 break;
6250 case GPM_B_RIGHT:
6251 button = MOUSE_RIGHT;
6252 break;
6253 default:
6254 return 0;
6255 /*Don't know what to do. Can more than one button be
6256 * reported in one event? */
6257 }
6258 string[3] = (char_u)(button | 0x20);
6259 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
6260 break;
6261 case GPM_UP:
6262 string[3] = MOUSE_RELEASE;
6263 old_buttons &= ~gpm_event.buttons;
6264 break;
6265 default:
6266 return 0;
6267 }
6268 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
6269 gpm_modifiers = gpm_event.modifiers;
6270 vim_modifiers = 0x0;
6271 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
6272 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
6273 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
6274 */
6275 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
6276 vim_modifiers |= MOUSE_SHIFT;
6277
6278 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
6279 vim_modifiers |= MOUSE_CTRL;
6280 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
6281 vim_modifiers |= MOUSE_ALT;
6282 string[3] |= vim_modifiers;
6283 string[4] = (char_u)(col + ' ' + 1);
6284 string[5] = (char_u)(row + ' ' + 1);
6285 add_to_input_buf(string, 6);
6286 return 6;
6287}
6288#endif /* FEAT_MOUSE_GPM */
6289
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006290#ifdef FEAT_SYSMOUSE
6291/*
6292 * Initialize connection with sysmouse.
6293 * Let virtual console inform us with SIGUSR2 for pending sysmouse
6294 * output, any sysmouse output than will be processed via sig_sysmouse().
6295 * Return OK if succeeded, FAIL if failed.
6296 */
6297 static int
6298sysmouse_open()
6299{
6300 struct mouse_info mouse;
6301
6302 mouse.operation = MOUSE_MODE;
6303 mouse.u.mode.mode = 0;
6304 mouse.u.mode.signal = SIGUSR2;
6305 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
6306 {
6307 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
6308 mouse.operation = MOUSE_SHOW;
6309 ioctl(1, CONS_MOUSECTL, &mouse);
6310 return OK;
6311 }
6312 return FAIL;
6313}
6314
6315/*
6316 * Stop processing SIGUSR2 signals, and also make sure that
6317 * virtual console do not send us any sysmouse related signal.
6318 */
6319 static void
6320sysmouse_close()
6321{
6322 struct mouse_info mouse;
6323
6324 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
6325 mouse.operation = MOUSE_MODE;
6326 mouse.u.mode.mode = 0;
6327 mouse.u.mode.signal = 0;
6328 ioctl(1, CONS_MOUSECTL, &mouse);
6329}
6330
6331/*
6332 * Gets info from sysmouse and adds special keys to input buf.
6333 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006334 static RETSIGTYPE
6335sig_sysmouse SIGDEFARG(sigarg)
6336{
6337 struct mouse_info mouse;
6338 struct video_info video;
6339 char_u string[6];
6340 int row, col;
6341 int button;
6342 int buttons;
6343 static int oldbuttons = 0;
6344
6345#ifdef FEAT_GUI
6346 /* Don't put events in the input queue now. */
6347 if (hold_gui_events)
6348 return;
6349#endif
6350
6351 mouse.operation = MOUSE_GETINFO;
6352 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
6353 && ioctl(1, FBIO_MODEINFO, &video) != -1
6354 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
6355 && video.vi_cheight > 0 && video.vi_cwidth > 0)
6356 {
6357 row = mouse.u.data.y / video.vi_cheight;
6358 col = mouse.u.data.x / video.vi_cwidth;
6359 buttons = mouse.u.data.buttons;
6360 string[0] = ESC; /* Our termcode */
6361 string[1] = 'M';
6362 string[2] = 'S';
6363 if (oldbuttons == buttons && buttons != 0)
6364 {
6365 button = MOUSE_DRAG;
6366 }
6367 else
6368 {
6369 switch (buttons)
6370 {
6371 case 0:
6372 button = MOUSE_RELEASE;
6373 break;
6374 case 1:
6375 button = MOUSE_LEFT;
6376 break;
6377 case 2:
6378 button = MOUSE_MIDDLE;
6379 break;
6380 case 4:
6381 button = MOUSE_RIGHT;
6382 break;
6383 default:
6384 return;
6385 }
6386 oldbuttons = buttons;
6387 }
6388 string[3] = (char_u)(button);
6389 string[4] = (char_u)(col + ' ' + 1);
6390 string[5] = (char_u)(row + ' ' + 1);
6391 add_to_input_buf(string, 6);
6392 }
6393 return;
6394}
6395#endif /* FEAT_SYSMOUSE */
6396
Bram Moolenaar071d4272004-06-13 20:20:40 +00006397#if defined(FEAT_LIBCALL) || defined(PROTO)
6398typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
6399typedef char_u * (*INTPROCSTR)__ARGS((int));
6400typedef int (*STRPROCINT)__ARGS((char_u *));
6401typedef int (*INTPROCINT)__ARGS((int));
6402
6403/*
6404 * Call a DLL routine which takes either a string or int param
6405 * and returns an allocated string.
6406 */
6407 int
6408mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
6409 char_u *libname;
6410 char_u *funcname;
6411 char_u *argstring; /* NULL when using a argint */
6412 int argint;
6413 char_u **string_result;/* NULL when using number_result */
6414 int *number_result;
6415{
6416# if defined(USE_DLOPEN)
6417 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006418 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006419# else
6420 shl_t hinstLib;
6421# endif
6422 STRPROCSTR ProcAdd;
6423 INTPROCSTR ProcAddI;
6424 char_u *retval_str = NULL;
6425 int retval_int = 0;
6426 int success = FALSE;
6427
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006428 /*
6429 * Get a handle to the DLL module.
6430 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006431# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006432 /* First clear any error, it's not cleared by the dlopen() call. */
6433 (void)dlerror();
6434
Bram Moolenaar071d4272004-06-13 20:20:40 +00006435 hinstLib = dlopen((char *)libname, RTLD_LAZY
6436# ifdef RTLD_LOCAL
6437 | RTLD_LOCAL
6438# endif
6439 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006440 if (hinstLib == NULL)
6441 {
6442 /* "dlerr" must be used before dlclose() */
6443 dlerr = (char *)dlerror();
6444 if (dlerr != NULL)
6445 EMSG2(_("dlerror = \"%s\""), dlerr);
6446 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006447# else
6448 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
6449# endif
6450
6451 /* If the handle is valid, try to get the function address. */
6452 if (hinstLib != NULL)
6453 {
6454# ifdef HAVE_SETJMP_H
6455 /*
6456 * Catch a crash when calling the library function. For example when
6457 * using a number where a string pointer is expected.
6458 */
6459 mch_startjmp();
6460 if (SETJMP(lc_jump_env) != 0)
6461 {
6462 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006463# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006464 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006465# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006466 mch_didjmp();
6467 }
6468 else
6469# endif
6470 {
6471 retval_str = NULL;
6472 retval_int = 0;
6473
6474 if (argstring != NULL)
6475 {
6476# if defined(USE_DLOPEN)
6477 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006478 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006479# else
6480 if (shl_findsym(&hinstLib, (const char *)funcname,
6481 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
6482 ProcAdd = NULL;
6483# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006484 if ((success = (ProcAdd != NULL
6485# if defined(USE_DLOPEN)
6486 && dlerr == NULL
6487# endif
6488 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006489 {
6490 if (string_result == NULL)
6491 retval_int = ((STRPROCINT)ProcAdd)(argstring);
6492 else
6493 retval_str = (ProcAdd)(argstring);
6494 }
6495 }
6496 else
6497 {
6498# if defined(USE_DLOPEN)
6499 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006500 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006501# else
6502 if (shl_findsym(&hinstLib, (const char *)funcname,
6503 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
6504 ProcAddI = NULL;
6505# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006506 if ((success = (ProcAddI != NULL
6507# if defined(USE_DLOPEN)
6508 && dlerr == NULL
6509# endif
6510 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006511 {
6512 if (string_result == NULL)
6513 retval_int = ((INTPROCINT)ProcAddI)(argint);
6514 else
6515 retval_str = (ProcAddI)(argint);
6516 }
6517 }
6518
6519 /* Save the string before we free the library. */
6520 /* Assume that a "1" or "-1" result is an illegal pointer. */
6521 if (string_result == NULL)
6522 *number_result = retval_int;
6523 else if (retval_str != NULL
6524 && retval_str != (char_u *)1
6525 && retval_str != (char_u *)-1)
6526 *string_result = vim_strsave(retval_str);
6527 }
6528
6529# ifdef HAVE_SETJMP_H
6530 mch_endjmp();
6531# ifdef SIGHASARG
6532 if (lc_signal != 0)
6533 {
6534 int i;
6535
6536 /* try to find the name of this signal */
6537 for (i = 0; signal_info[i].sig != -1; i++)
6538 if (lc_signal == signal_info[i].sig)
6539 break;
6540 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6541 }
6542# endif
6543# endif
6544
Bram Moolenaar071d4272004-06-13 20:20:40 +00006545# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006546 /* "dlerr" must be used before dlclose() */
6547 if (dlerr != NULL)
6548 EMSG2(_("dlerror = \"%s\""), dlerr);
6549
6550 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006551 (void)dlclose(hinstLib);
6552# else
6553 (void)shl_unload(hinstLib);
6554# endif
6555 }
6556
6557 if (!success)
6558 {
6559 EMSG2(_(e_libcall), funcname);
6560 return FAIL;
6561 }
6562
6563 return OK;
6564}
6565#endif
6566
6567#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6568static int xterm_trace = -1; /* default: disabled */
6569static int xterm_button;
6570
6571/*
6572 * Setup a dummy window for X selections in a terminal.
6573 */
6574 void
6575setup_term_clip()
6576{
6577 int z = 0;
6578 char *strp = "";
6579 Widget AppShell;
6580
6581 if (!x_connect_to_server())
6582 return;
6583
6584 open_app_context();
6585 if (app_context != NULL && xterm_Shell == (Widget)0)
6586 {
6587 int (*oldhandler)();
6588#if defined(HAVE_SETJMP_H)
6589 int (*oldIOhandler)();
6590#endif
6591# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6592 struct timeval start_tv;
6593
6594 if (p_verbose > 0)
6595 gettimeofday(&start_tv, NULL);
6596# endif
6597
6598 /* Ignore X errors while opening the display */
6599 oldhandler = XSetErrorHandler(x_error_check);
6600
6601#if defined(HAVE_SETJMP_H)
6602 /* Ignore X IO errors while opening the display */
6603 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6604 mch_startjmp();
6605 if (SETJMP(lc_jump_env) != 0)
6606 {
6607 mch_didjmp();
6608 xterm_dpy = NULL;
6609 }
6610 else
6611#endif
6612 {
6613 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6614 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6615#if defined(HAVE_SETJMP_H)
6616 mch_endjmp();
6617#endif
6618 }
6619
6620#if defined(HAVE_SETJMP_H)
6621 /* Now handle X IO errors normally. */
6622 (void)XSetIOErrorHandler(oldIOhandler);
6623#endif
6624 /* Now handle X errors normally. */
6625 (void)XSetErrorHandler(oldhandler);
6626
6627 if (xterm_dpy == NULL)
6628 {
6629 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006630 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006631 return;
6632 }
6633
6634 /* Catch terminating error of the X server connection. */
6635 (void)XSetIOErrorHandler(x_IOerror_handler);
6636
6637# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6638 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006639 {
6640 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006641 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006642 verbose_leave();
6643 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006644# endif
6645
6646 /* Create a Shell to make converters work. */
6647 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6648 applicationShellWidgetClass, xterm_dpy,
6649 NULL);
6650 if (AppShell == (Widget)0)
6651 return;
6652 xterm_Shell = XtVaCreatePopupShell("VIM",
6653 topLevelShellWidgetClass, AppShell,
6654 XtNmappedWhenManaged, 0,
6655 XtNwidth, 1,
6656 XtNheight, 1,
6657 NULL);
6658 if (xterm_Shell == (Widget)0)
6659 return;
6660
6661 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02006662 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006663 if (x11_display == NULL)
6664 x11_display = xterm_dpy;
6665
6666 XtRealizeWidget(xterm_Shell);
6667 XSync(xterm_dpy, False);
6668 xterm_update();
6669 }
6670 if (xterm_Shell != (Widget)0)
6671 {
6672 clip_init(TRUE);
6673 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6674 x11_window = (Window)atol(strp);
6675 /* Check if $WINDOWID is valid. */
6676 if (test_x11_window(xterm_dpy) == FAIL)
6677 x11_window = 0;
6678 if (x11_window != 0)
6679 xterm_trace = 0;
6680 }
6681}
6682
6683 void
6684start_xterm_trace(button)
6685 int button;
6686{
6687 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6688 return;
6689 xterm_trace = 1;
6690 xterm_button = button;
6691 do_xterm_trace();
6692}
6693
6694
6695 void
6696stop_xterm_trace()
6697{
6698 if (xterm_trace < 0)
6699 return;
6700 xterm_trace = 0;
6701}
6702
6703/*
6704 * Query the xterm pointer and generate mouse termcodes if necessary
6705 * return TRUE if dragging is active, else FALSE
6706 */
6707 static int
6708do_xterm_trace()
6709{
6710 Window root, child;
6711 int root_x, root_y;
6712 int win_x, win_y;
6713 int row, col;
6714 int_u mask_return;
6715 char_u buf[50];
6716 char_u *strp;
6717 long got_hints;
6718 static char_u *mouse_code;
6719 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6720 static int prev_row = 0, prev_col = 0;
6721 static XSizeHints xterm_hints;
6722
6723 if (xterm_trace <= 0)
6724 return FALSE;
6725
6726 if (xterm_trace == 1)
6727 {
6728 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006729 * have changed recently. */
6730 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6731 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006732 || xterm_hints.width_inc <= 1
6733 || xterm_hints.height_inc <= 1)
6734 {
6735 xterm_trace = -1; /* Not enough data -- disable tracing */
6736 return FALSE;
6737 }
6738
6739 /* Rely on the same mouse code for the duration of this */
6740 mouse_code = find_termcode(mouse_name);
6741 prev_row = mouse_row;
6742 prev_row = mouse_col;
6743 xterm_trace = 2;
6744
6745 /* Find the offset of the chars, there might be a scrollbar on the
6746 * left of the window and/or a menu on the top (eterm etc.) */
6747 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6748 &win_x, &win_y, &mask_return);
6749 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6750 - (xterm_hints.height_inc / 2);
6751 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6752 xterm_hints.y = 2;
6753 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6754 - (xterm_hints.width_inc / 2);
6755 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6756 xterm_hints.x = 2;
6757 return TRUE;
6758 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006759 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006760 {
6761 xterm_trace = 0;
6762 return FALSE;
6763 }
6764
6765 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6766 &win_x, &win_y, &mask_return);
6767
6768 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6769 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6770 if (row == prev_row && col == prev_col)
6771 return TRUE;
6772
6773 STRCPY(buf, mouse_code);
6774 strp = buf + STRLEN(buf);
6775 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6776 *strp++ = (char_u)(col + ' ' + 1);
6777 *strp++ = (char_u)(row + ' ' + 1);
6778 *strp = 0;
6779 add_to_input_buf(buf, STRLEN(buf));
6780
6781 prev_row = row;
6782 prev_col = col;
6783 return TRUE;
6784}
6785
6786# if defined(FEAT_GUI) || defined(PROTO)
6787/*
6788 * Destroy the display, window and app_context. Required for GTK.
6789 */
6790 void
6791clear_xterm_clip()
6792{
6793 if (xterm_Shell != (Widget)0)
6794 {
6795 XtDestroyWidget(xterm_Shell);
6796 xterm_Shell = (Widget)0;
6797 }
6798 if (xterm_dpy != NULL)
6799 {
Bram Moolenaare8208012008-06-20 09:59:25 +00006800# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006801 /* Lesstif and Solaris crash here, lose some memory */
6802 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00006803# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006804 if (x11_display == xterm_dpy)
6805 x11_display = NULL;
6806 xterm_dpy = NULL;
6807 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006808# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006809 if (app_context != (XtAppContext)NULL)
6810 {
6811 /* Lesstif and Solaris crash here, lose some memory */
6812 XtDestroyApplicationContext(app_context);
6813 app_context = (XtAppContext)NULL;
6814 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006815# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006816}
6817# endif
6818
6819/*
6820 * Catch up with any queued X events. This may put keyboard input into the
6821 * input buffer, call resize call-backs, trigger timers etc. If there is
6822 * nothing in the X event queue (& no timers pending), then we return
6823 * immediately.
6824 */
6825 static void
6826xterm_update()
6827{
6828 XEvent event;
6829
6830 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6831 {
6832 XtAppNextEvent(app_context, &event);
6833#ifdef FEAT_CLIENTSERVER
6834 {
6835 XPropertyEvent *e = (XPropertyEvent *)&event;
6836
6837 if (e->type == PropertyNotify && e->window == commWindow
6838 && e->atom == commProperty && e->state == PropertyNewValue)
6839 serverEventProc(xterm_dpy, &event);
6840 }
6841#endif
6842 XtDispatchEvent(&event);
6843 }
6844}
6845
6846 int
6847clip_xterm_own_selection(cbd)
6848 VimClipboard *cbd;
6849{
6850 if (xterm_Shell != (Widget)0)
6851 return clip_x11_own_selection(xterm_Shell, cbd);
6852 return FAIL;
6853}
6854
6855 void
6856clip_xterm_lose_selection(cbd)
6857 VimClipboard *cbd;
6858{
6859 if (xterm_Shell != (Widget)0)
6860 clip_x11_lose_selection(xterm_Shell, cbd);
6861}
6862
6863 void
6864clip_xterm_request_selection(cbd)
6865 VimClipboard *cbd;
6866{
6867 if (xterm_Shell != (Widget)0)
6868 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6869}
6870
6871 void
6872clip_xterm_set_selection(cbd)
6873 VimClipboard *cbd;
6874{
6875 clip_x11_set_selection(cbd);
6876}
6877#endif
6878
6879
6880#if defined(USE_XSMP) || defined(PROTO)
6881/*
6882 * Code for X Session Management Protocol.
6883 */
6884static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6885static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6886static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6887static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6888static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6889
6890
6891# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6892static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6893
6894/*
6895 * This is our chance to ask the user if they want to save,
6896 * or abort the logout
6897 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006898 static void
6899xsmp_handle_interaction(smc_conn, client_data)
6900 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006901 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006902{
6903 cmdmod_T save_cmdmod;
6904 int cancel_shutdown = False;
6905
6906 save_cmdmod = cmdmod;
6907 cmdmod.confirm = TRUE;
6908 if (check_changed_any(FALSE))
6909 /* Mustn't logout */
6910 cancel_shutdown = True;
6911 cmdmod = save_cmdmod;
6912 setcursor(); /* position cursor */
6913 out_flush();
6914
6915 /* Done interaction */
6916 SmcInteractDone(smc_conn, cancel_shutdown);
6917
6918 /* Finish off
6919 * Only end save-yourself here if we're not cancelling shutdown;
6920 * we'll get a cancelled callback later in which we'll end it.
6921 * Hopefully get around glitchy SMs (like GNOME-1)
6922 */
6923 if (!cancel_shutdown)
6924 {
6925 xsmp.save_yourself = False;
6926 SmcSaveYourselfDone(smc_conn, True);
6927 }
6928}
6929# endif
6930
6931/*
6932 * Callback that starts save-yourself.
6933 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006934 static void
6935xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6936 shutdown, interact_style, fast)
6937 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006938 SmPointer client_data UNUSED;
6939 int save_type UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006940 Bool shutdown;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006941 int interact_style UNUSED;
6942 Bool fast UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006943{
6944 /* Handle already being in saveyourself */
6945 if (xsmp.save_yourself)
6946 SmcSaveYourselfDone(smc_conn, True);
6947 xsmp.save_yourself = True;
6948 xsmp.shutdown = shutdown;
6949
6950 /* First up, preserve all files */
6951 out_flush();
6952 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6953
6954 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006955 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006956
6957# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6958 /* Now see if we can ask about unsaved files */
6959 if (shutdown && !fast && gui.in_use)
6960 /* Need to interact with user, but need SM's permission */
6961 SmcInteractRequest(smc_conn, SmDialogError,
6962 xsmp_handle_interaction, client_data);
6963 else
6964# endif
6965 {
6966 /* Can stop the cycle here */
6967 SmcSaveYourselfDone(smc_conn, True);
6968 xsmp.save_yourself = False;
6969 }
6970}
6971
6972
6973/*
6974 * Callback to warn us of imminent death.
6975 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006976 static void
6977xsmp_die(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006978 SmcConn smc_conn UNUSED;
6979 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006980{
6981 xsmp_close();
6982
6983 /* quit quickly leaving swapfiles for modified buffers behind */
6984 getout_preserve_modified(0);
6985}
6986
6987
6988/*
6989 * Callback to tell us that save-yourself has completed.
6990 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006991 static void
6992xsmp_save_complete(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006993 SmcConn smc_conn UNUSED;
6994 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006995{
6996 xsmp.save_yourself = False;
6997}
6998
6999
7000/*
7001 * Callback to tell us that an instigated shutdown was cancelled
7002 * (maybe even by us)
7003 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007004 static void
7005xsmp_shutdown_cancelled(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 if (xsmp.save_yourself)
7010 SmcSaveYourselfDone(smc_conn, True);
7011 xsmp.save_yourself = False;
7012 xsmp.shutdown = False;
7013}
7014
7015
7016/*
7017 * Callback to tell us that a new ICE connection has been established.
7018 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007019 static void
7020xsmp_ice_connection(iceConn, clientData, opening, watchData)
7021 IceConn iceConn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007022 IcePointer clientData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007023 Bool opening;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007024 IcePointer *watchData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007025{
7026 /* Intercept creation of ICE connection fd */
7027 if (opening)
7028 {
7029 xsmp_icefd = IceConnectionNumber(iceConn);
7030 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7031 }
7032}
7033
7034
7035/* Handle any ICE processing that's required; return FAIL if SM lost */
7036 int
7037xsmp_handle_requests()
7038{
7039 Bool rep;
7040
7041 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7042 == IceProcessMessagesIOError)
7043 {
7044 /* Lost ICE */
7045 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007046 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007047 xsmp_close();
7048 return FAIL;
7049 }
7050 else
7051 return OK;
7052}
7053
7054static int dummy;
7055
7056/* Set up X Session Management Protocol */
7057 void
7058xsmp_init(void)
7059{
7060 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007061 SmcCallbacks smcallbacks;
7062#if 0
7063 SmPropValue smname;
7064 SmProp smnameprop;
7065 SmProp *smprops[1];
7066#endif
7067
7068 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007069 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007070
7071 xsmp.save_yourself = xsmp.shutdown = False;
7072
7073 /* Set up SM callbacks - must have all, even if they're not used */
7074 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
7075 smcallbacks.save_yourself.client_data = NULL;
7076 smcallbacks.die.callback = xsmp_die;
7077 smcallbacks.die.client_data = NULL;
7078 smcallbacks.save_complete.callback = xsmp_save_complete;
7079 smcallbacks.save_complete.client_data = NULL;
7080 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
7081 smcallbacks.shutdown_cancelled.client_data = NULL;
7082
7083 /* Set up a watch on ICE connection creations. The "dummy" argument is
7084 * apparently required for FreeBSD (we get a BUS error when using NULL). */
7085 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
7086 {
7087 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007088 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007089 return;
7090 }
7091
7092 /* Create an SM connection */
7093 xsmp.smcconn = SmcOpenConnection(
7094 NULL,
7095 NULL,
7096 SmProtoMajor,
7097 SmProtoMinor,
7098 SmcSaveYourselfProcMask | SmcDieProcMask
7099 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
7100 &smcallbacks,
7101 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00007102 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007103 sizeof(errorstring),
7104 errorstring);
7105 if (xsmp.smcconn == NULL)
7106 {
7107 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00007108
Bram Moolenaar071d4272004-06-13 20:20:40 +00007109 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007110 {
7111 vim_snprintf(errorreport, sizeof(errorreport),
7112 _("XSMP SmcOpenConnection failed: %s"), errorstring);
7113 verb_msg((char_u *)errorreport);
7114 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007115 return;
7116 }
7117 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
7118
7119#if 0
7120 /* ID ourselves */
7121 smname.value = "vim";
7122 smname.length = 3;
7123 smnameprop.name = "SmProgram";
7124 smnameprop.type = "SmARRAY8";
7125 smnameprop.num_vals = 1;
7126 smnameprop.vals = &smname;
7127
7128 smprops[0] = &smnameprop;
7129 SmcSetProperties(xsmp.smcconn, 1, smprops);
7130#endif
7131}
7132
7133
7134/* Shut down XSMP comms. */
7135 void
7136xsmp_close()
7137{
7138 if (xsmp_icefd != -1)
7139 {
7140 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00007141 if (xsmp.clientid != NULL)
7142 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00007143 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007144 xsmp_icefd = -1;
7145 }
7146}
7147#endif /* USE_XSMP */
7148
7149
7150#ifdef EBCDIC
7151/* Translate character to its CTRL- value */
7152char CtrlTable[] =
7153{
7154/* 00 - 5E */
7155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7157 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7158 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7159 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7161/* ^ */ 0x1E,
7162/* - */ 0x1F,
7163/* 61 - 6C */
7164 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7165/* _ */ 0x1F,
7166/* 6E - 80 */
7167 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7168/* a */ 0x01,
7169/* b */ 0x02,
7170/* c */ 0x03,
7171/* d */ 0x37,
7172/* e */ 0x2D,
7173/* f */ 0x2E,
7174/* g */ 0x2F,
7175/* h */ 0x16,
7176/* i */ 0x05,
7177/* 8A - 90 */
7178 0, 0, 0, 0, 0, 0, 0,
7179/* j */ 0x15,
7180/* k */ 0x0B,
7181/* l */ 0x0C,
7182/* m */ 0x0D,
7183/* n */ 0x0E,
7184/* o */ 0x0F,
7185/* p */ 0x10,
7186/* q */ 0x11,
7187/* r */ 0x12,
7188/* 9A - A1 */
7189 0, 0, 0, 0, 0, 0, 0, 0,
7190/* s */ 0x13,
7191/* t */ 0x3C,
7192/* u */ 0x3D,
7193/* v */ 0x32,
7194/* w */ 0x26,
7195/* x */ 0x18,
7196/* y */ 0x19,
7197/* z */ 0x3F,
7198/* AA - AC */
7199 0, 0, 0,
7200/* [ */ 0x27,
7201/* AE - BC */
7202 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7203/* ] */ 0x1D,
7204/* BE - C0 */ 0, 0, 0,
7205/* A */ 0x01,
7206/* B */ 0x02,
7207/* C */ 0x03,
7208/* D */ 0x37,
7209/* E */ 0x2D,
7210/* F */ 0x2E,
7211/* G */ 0x2F,
7212/* H */ 0x16,
7213/* I */ 0x05,
7214/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
7215/* J */ 0x15,
7216/* K */ 0x0B,
7217/* L */ 0x0C,
7218/* M */ 0x0D,
7219/* N */ 0x0E,
7220/* O */ 0x0F,
7221/* P */ 0x10,
7222/* Q */ 0x11,
7223/* R */ 0x12,
7224/* DA - DF */ 0, 0, 0, 0, 0, 0,
7225/* \ */ 0x1C,
7226/* E1 */ 0,
7227/* S */ 0x13,
7228/* T */ 0x3C,
7229/* U */ 0x3D,
7230/* V */ 0x32,
7231/* W */ 0x26,
7232/* X */ 0x18,
7233/* Y */ 0x19,
7234/* Z */ 0x3F,
7235/* EA - FF*/ 0, 0, 0, 0, 0, 0,
7236 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7237};
7238
7239char MetaCharTable[]=
7240{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7241 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
7242 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
7243 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
7244 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
7245};
7246
7247
7248/* TODO: Use characters NOT numbers!!! */
7249char CtrlCharTable[]=
7250{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7251 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
7252 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
7253 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
7254 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
7255};
7256
7257
7258#endif