blob: 9d9483261909294eb6bf2108dc4c230599dca438 [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));
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001141static void save_clipboard __ARGS((void));
1142static void restore_clipboard __ARGS((void));
1143
1144static void *clip_star_save = NULL;
1145static void *clip_plus_save = NULL;
Bram Moolenaar62b42182010-09-21 22:09:37 +02001146
1147/*
1148 * Called when Vim is going to sleep or execute a shell command.
1149 * We can't respond to requests for the X selections. Lose them, otherwise
1150 * other applications will hang. But first copy the text to cut buffer 0.
1151 */
1152 static void
1153loose_clipboard()
1154{
1155 if (clip_star.owned || clip_plus.owned)
1156 {
1157 x11_export_final_selection();
1158 if (clip_star.owned)
1159 clip_lose_selection(&clip_star);
1160 if (clip_plus.owned)
1161 clip_lose_selection(&clip_plus);
1162 if (x11_display != NULL)
1163 XFlush(x11_display);
1164 }
1165}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001166
1167/*
1168 * Save clipboard text to restore later.
1169 */
1170 static void
1171save_clipboard()
1172{
1173 if (clip_star.owned)
1174 clip_star_save = get_register('*', TRUE);
1175 if (clip_plus.owned)
1176 clip_plus_save = get_register('+', TRUE);
1177}
1178
1179/*
1180 * Restore clipboard text if no one own the X selection.
1181 */
1182 static void
1183restore_clipboard()
1184{
1185 if (clip_star_save != NULL)
1186 {
1187 if (!clip_gen_owner_exists(&clip_star))
1188 put_register('*', clip_star_save);
1189 else
1190 free_register(clip_star_save);
1191 clip_star_save = NULL;
1192 }
1193 if (clip_plus_save != NULL)
1194 {
1195 if (!clip_gen_owner_exists(&clip_plus))
1196 put_register('+', clip_plus_save);
1197 else
1198 free_register(clip_plus_save);
1199 clip_plus_save = NULL;
1200 }
1201}
Bram Moolenaar62b42182010-09-21 22:09:37 +02001202#endif
1203
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204/*
1205 * If the machine has job control, use it to suspend the program,
1206 * otherwise fake it by starting a new shell.
1207 */
1208 void
1209mch_suspend()
1210{
1211 /* BeOS does have SIGTSTP, but it doesn't work. */
1212#if defined(SIGTSTP) && !defined(__BEOS__)
1213 out_flush(); /* needed to make cursor visible on some systems */
1214 settmode(TMODE_COOK);
1215 out_flush(); /* needed to disable mouse on some systems */
1216
1217# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001218 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001219# endif
1220
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001221# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001222 sigcont_received = FALSE;
1223# endif
1224 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001225# if defined(_REENTRANT) && defined(SIGCONT)
1226 /*
1227 * Wait for the SIGCONT signal to be handled. It generally happens
1228 * immediately, but somehow not all the time. Do not call pause()
1229 * because there would be race condition which would hang Vim if
1230 * signal happened in between the test of sigcont_received and the
1231 * call to pause(). If signal is not yet received, call sleep(0)
1232 * to just yield CPU. Signal should then be received. If somehow
1233 * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
1234 * further if signal is not received after 1+2+3+4 ms (not expected
1235 * to happen).
1236 */
1237 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001238 long wait_time;
1239 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001240 /* Loop is not entered most of the time */
Bram Moolenaar262735e2009-07-14 10:20:22 +00001241 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001242 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243# endif
1244
1245# ifdef FEAT_TITLE
1246 /*
1247 * Set oldtitle to NULL, so the current title is obtained again.
1248 */
1249 vim_free(oldtitle);
1250 oldtitle = NULL;
1251# endif
1252 settmode(TMODE_RAW);
1253 need_check_timestamps = TRUE;
1254 did_check_timestamps = FALSE;
1255#else
1256 suspend_shell();
1257#endif
1258}
1259
1260 void
1261mch_init()
1262{
1263 Columns = 80;
1264 Rows = 24;
1265
1266 out_flush();
1267 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001268
Bram Moolenaar56718732006-03-15 22:53:57 +00001269#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001270 mac_conv_init();
1271#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001272#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1273 win_clip_init();
1274#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001275}
1276
1277 static void
1278set_signals()
1279{
1280#if defined(SIGWINCH)
1281 /*
1282 * WINDOW CHANGE signal is handled with sig_winch().
1283 */
1284 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1285#endif
1286
1287 /*
1288 * We want the STOP signal to work, to make mch_suspend() work.
1289 * For "rvim" the STOP signal is ignored.
1290 */
1291#ifdef SIGTSTP
1292 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1293#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001294#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001295 signal(SIGCONT, sigcont_handler);
1296#endif
1297
1298 /*
1299 * We want to ignore breaking of PIPEs.
1300 */
1301#ifdef SIGPIPE
1302 signal(SIGPIPE, SIG_IGN);
1303#endif
1304
Bram Moolenaar071d4272004-06-13 20:20:40 +00001305#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001306 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001307#endif
1308
1309 /*
1310 * Ignore alarm signals (Perl's alarm() generates it).
1311 */
1312#ifdef SIGALRM
1313 signal(SIGALRM, SIG_IGN);
1314#endif
1315
1316 /*
1317 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1318 * work will be lost.
1319 */
1320#ifdef SIGPWR
1321 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1322#endif
1323
1324 /*
1325 * Arrange for other signals to gracefully shutdown Vim.
1326 */
1327 catch_signals(deathtrap, SIG_ERR);
1328
1329#if defined(FEAT_GUI) && defined(SIGHUP)
1330 /*
1331 * When the GUI is running, ignore the hangup signal.
1332 */
1333 if (gui.in_use)
1334 signal(SIGHUP, SIG_IGN);
1335#endif
1336}
1337
Bram Moolenaardf177f62005-02-22 08:39:57 +00001338#if defined(SIGINT) || defined(PROTO)
1339/*
1340 * Catch CTRL-C (only works while in Cooked mode).
1341 */
1342 static void
1343catch_int_signal()
1344{
1345 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1346}
1347#endif
1348
Bram Moolenaar071d4272004-06-13 20:20:40 +00001349 void
1350reset_signals()
1351{
1352 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001353#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001354 /* SIGCONT isn't in the list, because its default action is ignore */
1355 signal(SIGCONT, SIG_DFL);
1356#endif
1357}
1358
1359 static void
1360catch_signals(func_deadly, func_other)
1361 RETSIGTYPE (*func_deadly)();
1362 RETSIGTYPE (*func_other)();
1363{
1364 int i;
1365
1366 for (i = 0; signal_info[i].sig != -1; i++)
1367 if (signal_info[i].deadly)
1368 {
1369#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1370 struct sigaction sa;
1371
1372 /* Setup to use the alternate stack for the signal function. */
1373 sa.sa_handler = func_deadly;
1374 sigemptyset(&sa.sa_mask);
1375# if defined(__linux__) && defined(_REENTRANT)
1376 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1377 * thread handling in combination with using the alternate stack:
1378 * pthread library functions try to use the stack pointer to
1379 * identify the current thread, causing a SEGV signal, which
1380 * recursively calls deathtrap() and hangs. */
1381 sa.sa_flags = 0;
1382# else
1383 sa.sa_flags = SA_ONSTACK;
1384# endif
1385 sigaction(signal_info[i].sig, &sa, NULL);
1386#else
1387# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1388 struct sigvec sv;
1389
1390 /* Setup to use the alternate stack for the signal function. */
1391 sv.sv_handler = func_deadly;
1392 sv.sv_mask = 0;
1393 sv.sv_flags = SV_ONSTACK;
1394 sigvec(signal_info[i].sig, &sv, NULL);
1395# else
1396 signal(signal_info[i].sig, func_deadly);
1397# endif
1398#endif
1399 }
1400 else if (func_other != SIG_ERR)
1401 signal(signal_info[i].sig, func_other);
1402}
1403
1404/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001405 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001406 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1407 * return TRUE
1408 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1409 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001410 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001411 * Returns TRUE when Vim should exit.
1412 */
1413 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001414vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001415 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001416{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001417 static int got_signal = 0;
1418 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001419
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001420 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001421 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001422 case SIGNAL_BLOCK: blocked = TRUE;
1423 break;
1424
1425 case SIGNAL_UNBLOCK: blocked = FALSE;
1426 if (got_signal != 0)
1427 {
1428 kill(getpid(), got_signal);
1429 got_signal = 0;
1430 }
1431 break;
1432
1433 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001434 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001435 got_signal = sig;
1436#ifdef SIGPWR
1437 if (sig != SIGPWR)
1438#endif
1439 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001440 break;
1441 }
1442 return FALSE;
1443}
1444
1445/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001446 * Check_win checks whether we have an interactive stdout.
1447 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001448 int
1449mch_check_win(argc, argv)
Bram Moolenaar78a15312009-05-15 19:33:18 +00001450 int argc UNUSED;
1451 char **argv UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001452{
1453#ifdef OS2
1454 /*
1455 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1456 * name, mostly it's just "vim" and found in the path, which is unusable.
1457 */
1458 if (mch_isFullName(argv[0]))
1459 exe_name = vim_strsave((char_u *)argv[0]);
1460#endif
1461 if (isatty(1))
1462 return OK;
1463 return FAIL;
1464}
1465
1466/*
1467 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1468 */
1469 int
1470mch_input_isatty()
1471{
1472 if (isatty(read_cmd_fd))
1473 return TRUE;
1474 return FALSE;
1475}
1476
1477#ifdef FEAT_X11
1478
1479# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1480 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1481
1482static void xopen_message __ARGS((struct timeval *tvp));
1483
1484/*
1485 * Give a message about the elapsed time for opening the X window.
1486 */
1487 static void
1488xopen_message(tvp)
1489 struct timeval *tvp; /* must contain start time */
1490{
1491 struct timeval end_tv;
1492
1493 /* Compute elapsed time. */
1494 gettimeofday(&end_tv, NULL);
1495 smsg((char_u *)_("Opening the X display took %ld msec"),
1496 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001497 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498}
1499# endif
1500#endif
1501
1502#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1503/*
1504 * A few functions shared by X11 title and clipboard code.
1505 */
1506static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1507static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1508static int x_connect_to_server __ARGS((void));
1509static int test_x11_window __ARGS((Display *dpy));
1510
1511static int got_x_error = FALSE;
1512
1513/*
1514 * X Error handler, otherwise X just exits! (very rude) -- webb
1515 */
1516 static int
1517x_error_handler(dpy, error_event)
1518 Display *dpy;
1519 XErrorEvent *error_event;
1520{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001521 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001522 STRCAT(IObuff, _("\nVim: Got X error\n"));
1523
1524 /* We cannot print a message and continue, because no X calls are allowed
1525 * here (causes my system to hang). Silently continuing might be an
1526 * alternative... */
1527 preserve_exit(); /* preserve files and exit */
1528
1529 return 0; /* NOTREACHED */
1530}
1531
1532/*
1533 * Another X Error handler, just used to check for errors.
1534 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001535 static int
1536x_error_check(dpy, error_event)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001537 Display *dpy UNUSED;
1538 XErrorEvent *error_event UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001539{
1540 got_x_error = TRUE;
1541 return 0;
1542}
1543
1544#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1545# if defined(HAVE_SETJMP_H)
1546/*
1547 * An X IO Error handler, used to catch error while opening the display.
1548 */
1549static int x_IOerror_check __ARGS((Display *dpy));
1550
Bram Moolenaar071d4272004-06-13 20:20:40 +00001551 static int
1552x_IOerror_check(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001553 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001554{
1555 /* This function should not return, it causes exit(). Longjump instead. */
1556 LONGJMP(lc_jump_env, 1);
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001557# ifdef VMS
1558 return 0; /* avoid the compiler complains about missing return value */
1559# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001560}
1561# endif
1562
1563/*
1564 * An X IO Error handler, used to catch terminal errors.
1565 */
1566static int x_IOerror_handler __ARGS((Display *dpy));
1567
Bram Moolenaar071d4272004-06-13 20:20:40 +00001568 static int
1569x_IOerror_handler(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001570 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001571{
1572 xterm_dpy = NULL;
1573 x11_window = 0;
1574 x11_display = NULL;
1575 xterm_Shell = (Widget)0;
1576
1577 /* This function should not return, it causes exit(). Longjump instead. */
1578 LONGJMP(x_jump_env, 1);
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001579# ifdef VMS
1580 return 0; /* avoid the compiler complains about missing return value */
1581# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001582}
1583#endif
1584
1585/*
1586 * Return TRUE when connection to the X server is desired.
1587 */
1588 static int
1589x_connect_to_server()
1590{
1591 regmatch_T regmatch;
1592
1593#if defined(FEAT_CLIENTSERVER)
1594 if (x_force_connect)
1595 return TRUE;
1596#endif
1597 if (x_no_connect)
1598 return FALSE;
1599
1600 /* Check for a match with "exclude:" from 'clipboard'. */
1601 if (clip_exclude_prog != NULL)
1602 {
1603 regmatch.rm_ic = FALSE; /* Don't ignore case */
1604 regmatch.regprog = clip_exclude_prog;
1605 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1606 return FALSE;
1607 }
1608 return TRUE;
1609}
1610
1611/*
1612 * Test if "dpy" and x11_window are valid by getting the window title.
1613 * I don't actually want it yet, so there may be a simpler call to use, but
1614 * this will cause the error handler x_error_check() to be called if anything
1615 * is wrong, such as the window pointer being invalid (as can happen when the
1616 * user changes his DISPLAY, but not his WINDOWID) -- webb
1617 */
1618 static int
1619test_x11_window(dpy)
1620 Display *dpy;
1621{
1622 int (*old_handler)();
1623 XTextProperty text_prop;
1624
1625 old_handler = XSetErrorHandler(x_error_check);
1626 got_x_error = FALSE;
1627 if (XGetWMName(dpy, x11_window, &text_prop))
1628 XFree((void *)text_prop.value);
1629 XSync(dpy, False);
1630 (void)XSetErrorHandler(old_handler);
1631
1632 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001633 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001634
1635 return (got_x_error ? FAIL : OK);
1636}
1637#endif
1638
1639#ifdef FEAT_TITLE
1640
1641#ifdef FEAT_X11
1642
1643static int get_x11_thing __ARGS((int get_title, int test_only));
1644
1645/*
1646 * try to get x11 window and display
1647 *
1648 * return FAIL for failure, OK otherwise
1649 */
1650 static int
1651get_x11_windis()
1652{
1653 char *winid;
1654 static int result = -1;
1655#define XD_NONE 0 /* x11_display not set here */
1656#define XD_HERE 1 /* x11_display opened here */
1657#define XD_GUI 2 /* x11_display used from gui.dpy */
1658#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1659 static int x11_display_from = XD_NONE;
1660 static int did_set_error_handler = FALSE;
1661
1662 if (!did_set_error_handler)
1663 {
1664 /* X just exits if it finds an error otherwise! */
1665 (void)XSetErrorHandler(x_error_handler);
1666 did_set_error_handler = TRUE;
1667 }
1668
Bram Moolenaar9372a112005-12-06 19:59:18 +00001669#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001670 if (gui.in_use)
1671 {
1672 /*
1673 * If the X11 display was opened here before, for the window where Vim
1674 * was started, close that one now to avoid a memory leak.
1675 */
1676 if (x11_display_from == XD_HERE && x11_display != NULL)
1677 {
1678 XCloseDisplay(x11_display);
1679 x11_display_from = XD_NONE;
1680 }
1681 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1682 {
1683 x11_display_from = XD_GUI;
1684 return OK;
1685 }
1686 x11_display = NULL;
1687 return FAIL;
1688 }
1689 else if (x11_display_from == XD_GUI)
1690 {
1691 /* GUI must have stopped somehow, clear x11_display */
1692 x11_window = 0;
1693 x11_display = NULL;
1694 x11_display_from = XD_NONE;
1695 }
1696#endif
1697
1698 /* When started with the "-X" argument, don't try connecting. */
1699 if (!x_connect_to_server())
1700 return FAIL;
1701
1702 /*
1703 * If WINDOWID not set, should try another method to find out
1704 * what the current window number is. The only code I know for
1705 * this is very complicated.
1706 * We assume that zero is invalid for WINDOWID.
1707 */
1708 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1709 x11_window = (Window)atol(winid);
1710
1711#ifdef FEAT_XCLIPBOARD
1712 if (xterm_dpy != NULL && x11_window != 0)
1713 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001714 /* We may have checked it already, but Gnome terminal can move us to
1715 * another window, so we need to check every time. */
1716 if (x11_display_from != XD_XTERM)
1717 {
1718 /*
1719 * If the X11 display was opened here before, for the window where
1720 * Vim was started, close that one now to avoid a memory leak.
1721 */
1722 if (x11_display_from == XD_HERE && x11_display != NULL)
1723 XCloseDisplay(x11_display);
1724 x11_display = xterm_dpy;
1725 x11_display_from = XD_XTERM;
1726 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001727 if (test_x11_window(x11_display) == FAIL)
1728 {
1729 /* probably bad $WINDOWID */
1730 x11_window = 0;
1731 x11_display = NULL;
1732 x11_display_from = XD_NONE;
1733 return FAIL;
1734 }
1735 return OK;
1736 }
1737#endif
1738
1739 if (x11_window == 0 || x11_display == NULL)
1740 result = -1;
1741
1742 if (result != -1) /* Have already been here and set this */
1743 return result; /* Don't do all these X calls again */
1744
1745 if (x11_window != 0 && x11_display == NULL)
1746 {
1747#ifdef SET_SIG_ALARM
1748 RETSIGTYPE (*sig_save)();
1749#endif
1750#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1751 struct timeval start_tv;
1752
1753 if (p_verbose > 0)
1754 gettimeofday(&start_tv, NULL);
1755#endif
1756
1757#ifdef SET_SIG_ALARM
1758 /*
1759 * Opening the Display may hang if the DISPLAY setting is wrong, or
1760 * the network connection is bad. Set an alarm timer to get out.
1761 */
1762 sig_alarm_called = FALSE;
1763 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1764 (RETSIGTYPE (*)())sig_alarm);
1765 alarm(2);
1766#endif
1767 x11_display = XOpenDisplay(NULL);
1768
1769#ifdef SET_SIG_ALARM
1770 alarm(0);
1771 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1772 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001773 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001774#endif
1775 if (x11_display != NULL)
1776 {
1777# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1778 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001779 {
1780 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001781 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001782 verbose_leave();
1783 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001784# endif
1785 if (test_x11_window(x11_display) == FAIL)
1786 {
1787 /* Maybe window id is bad */
1788 x11_window = 0;
1789 XCloseDisplay(x11_display);
1790 x11_display = NULL;
1791 }
1792 else
1793 x11_display_from = XD_HERE;
1794 }
1795 }
1796 if (x11_window == 0 || x11_display == NULL)
1797 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001798
1799# ifdef FEAT_EVAL
1800 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1801# endif
1802
Bram Moolenaar071d4272004-06-13 20:20:40 +00001803 return (result = OK);
1804}
1805
1806/*
1807 * Determine original x11 Window Title
1808 */
1809 static int
1810get_x11_title(test_only)
1811 int test_only;
1812{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001813 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001814}
1815
1816/*
1817 * Determine original x11 Window icon
1818 */
1819 static int
1820get_x11_icon(test_only)
1821 int test_only;
1822{
1823 int retval = FALSE;
1824
1825 retval = get_x11_thing(FALSE, test_only);
1826
1827 /* could not get old icon, use terminal name */
1828 if (oldicon == NULL && !test_only)
1829 {
1830 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001831 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001832 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001833 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001834 }
1835
1836 return retval;
1837}
1838
1839 static int
1840get_x11_thing(get_title, test_only)
1841 int get_title; /* get title string */
1842 int test_only;
1843{
1844 XTextProperty text_prop;
1845 int retval = FALSE;
1846 Status status;
1847
1848 if (get_x11_windis() == OK)
1849 {
1850 /* Get window/icon name if any */
1851 if (get_title)
1852 status = XGetWMName(x11_display, x11_window, &text_prop);
1853 else
1854 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1855
1856 /*
1857 * If terminal is xterm, then x11_window may be a child window of the
1858 * outer xterm window that actually contains the window/icon name, so
1859 * keep traversing up the tree until a window with a title/icon is
1860 * found.
1861 */
1862 /* Previously this was only done for xterm and alikes. I don't see a
1863 * reason why it would fail for other terminal emulators.
1864 * if (term_is_xterm) */
1865 {
1866 Window root;
1867 Window parent;
1868 Window win = x11_window;
1869 Window *children;
1870 unsigned int num_children;
1871
1872 while (!status || text_prop.value == NULL)
1873 {
1874 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1875 &num_children))
1876 break;
1877 if (children)
1878 XFree((void *)children);
1879 if (parent == root || parent == 0)
1880 break;
1881
1882 win = parent;
1883 if (get_title)
1884 status = XGetWMName(x11_display, win, &text_prop);
1885 else
1886 status = XGetWMIconName(x11_display, win, &text_prop);
1887 }
1888 }
1889 if (status && text_prop.value != NULL)
1890 {
1891 retval = TRUE;
1892 if (!test_only)
1893 {
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001894#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
1895 if (text_prop.encoding == XA_STRING
1896# ifdef FEAT_MBYTE
1897 && !has_mbyte
1898# endif
1899 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001900 {
1901#endif
1902 if (get_title)
1903 oldtitle = vim_strsave((char_u *)text_prop.value);
1904 else
1905 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001906#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907 }
1908 else
1909 {
1910 char **cl;
1911 Status transform_status;
1912 int n = 0;
1913
1914 transform_status = XmbTextPropertyToTextList(x11_display,
1915 &text_prop,
1916 &cl, &n);
1917 if (transform_status >= Success && n > 0 && cl[0])
1918 {
1919 if (get_title)
1920 oldtitle = vim_strsave((char_u *) cl[0]);
1921 else
1922 oldicon = vim_strsave((char_u *) cl[0]);
1923 XFreeStringList(cl);
1924 }
1925 else
1926 {
1927 if (get_title)
1928 oldtitle = vim_strsave((char_u *)text_prop.value);
1929 else
1930 oldicon = vim_strsave((char_u *)text_prop.value);
1931 }
1932 }
1933#endif
1934 }
1935 XFree((void *)text_prop.value);
1936 }
1937 }
1938 return retval;
1939}
1940
1941/* Are Xutf8 functions available? Avoid error from old compilers. */
1942#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1943# if X_HAVE_UTF8_STRING
1944# define USE_UTF8_STRING
1945# endif
1946#endif
1947
1948/*
1949 * Set x11 Window Title
1950 *
1951 * get_x11_windis() must be called before this and have returned OK
1952 */
1953 static void
1954set_x11_title(title)
1955 char_u *title;
1956{
1957 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1958 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1959 * supported everywhere and STRING doesn't work for multi-byte titles.
1960 */
1961#ifdef USE_UTF8_STRING
1962 if (enc_utf8)
1963 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1964 NULL, NULL, 0, NULL, NULL, NULL);
1965 else
1966#endif
1967 {
1968#if XtSpecificationRelease >= 4
1969# ifdef FEAT_XFONTSET
1970 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1971 NULL, NULL, 0, NULL, NULL, NULL);
1972# else
1973 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001974 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001975
1976 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001977 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001978 XSetWMProperties(x11_display, x11_window, &text_prop,
1979 NULL, NULL, 0, NULL, NULL, NULL);
1980# endif
1981#else
1982 XStoreName(x11_display, x11_window, (char *)title);
1983#endif
1984 }
1985 XFlush(x11_display);
1986}
1987
1988/*
1989 * Set x11 Window icon
1990 *
1991 * get_x11_windis() must be called before this and have returned OK
1992 */
1993 static void
1994set_x11_icon(icon)
1995 char_u *icon;
1996{
1997 /* See above for comments about using X*SetWMProperties(). */
1998#ifdef USE_UTF8_STRING
1999 if (enc_utf8)
2000 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2001 NULL, 0, NULL, NULL, NULL);
2002 else
2003#endif
2004 {
2005#if XtSpecificationRelease >= 4
2006# ifdef FEAT_XFONTSET
2007 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2008 NULL, 0, NULL, NULL, NULL);
2009# else
2010 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002011 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002012
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002013 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002014 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2015 NULL, 0, NULL, NULL, NULL);
2016# endif
2017#else
2018 XSetIconName(x11_display, x11_window, (char *)icon);
2019#endif
2020 }
2021 XFlush(x11_display);
2022}
2023
2024#else /* FEAT_X11 */
2025
Bram Moolenaar071d4272004-06-13 20:20:40 +00002026 static int
2027get_x11_title(test_only)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002028 int test_only UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002029{
2030 return FALSE;
2031}
2032
2033 static int
2034get_x11_icon(test_only)
2035 int test_only;
2036{
2037 if (!test_only)
2038 {
2039 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002040 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002041 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002042 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002043 }
2044 return FALSE;
2045}
2046
2047#endif /* FEAT_X11 */
2048
2049 int
2050mch_can_restore_title()
2051{
2052 return get_x11_title(TRUE);
2053}
2054
2055 int
2056mch_can_restore_icon()
2057{
2058 return get_x11_icon(TRUE);
2059}
2060
2061/*
2062 * Set the window title and icon.
2063 */
2064 void
2065mch_settitle(title, icon)
2066 char_u *title;
2067 char_u *icon;
2068{
2069 int type = 0;
2070 static int recursive = 0;
2071
2072 if (T_NAME == NULL) /* no terminal name (yet) */
2073 return;
2074 if (title == NULL && icon == NULL) /* nothing to do */
2075 return;
2076
2077 /* When one of the X11 functions causes a deadly signal, we get here again
2078 * recursively. Avoid hanging then (something is probably locked). */
2079 if (recursive)
2080 return;
2081 ++recursive;
2082
2083 /*
2084 * if the window ID and the display is known, we may use X11 calls
2085 */
2086#ifdef FEAT_X11
2087 if (get_x11_windis() == OK)
2088 type = 1;
2089#else
2090# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2091 if (gui.in_use)
2092 type = 1;
2093# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002094#endif
2095
2096 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002097 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002098 * than x11 calls, because the x11 calls don't always work
2099 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002100 if ((type || *T_TS != NUL) && title != NULL)
2101 {
2102 if (oldtitle == NULL
2103#ifdef FEAT_GUI
2104 && !gui.in_use
2105#endif
2106 ) /* first call but not in GUI, save title */
2107 (void)get_x11_title(FALSE);
2108
2109 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2110 term_settitle(title);
2111#ifdef FEAT_X11
2112 else
2113# ifdef FEAT_GUI_GTK
2114 if (!gui.in_use) /* don't do this if GTK+ is running */
2115# endif
2116 set_x11_title(title); /* x11 */
2117#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002118#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002119 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2120 else
2121 gui_mch_settitle(title, icon);
2122#endif
2123 did_set_title = TRUE;
2124 }
2125
2126 if ((type || *T_CIS != NUL) && icon != NULL)
2127 {
2128 if (oldicon == NULL
2129#ifdef FEAT_GUI
2130 && !gui.in_use
2131#endif
2132 ) /* first call, save icon */
2133 get_x11_icon(FALSE);
2134
2135 if (*T_CIS != NUL)
2136 {
2137 out_str(T_CIS); /* set icon start */
2138 out_str_nf(icon);
2139 out_str(T_CIE); /* set icon end */
2140 out_flush();
2141 }
2142#ifdef FEAT_X11
2143 else
2144# ifdef FEAT_GUI_GTK
2145 if (!gui.in_use) /* don't do this if GTK+ is running */
2146# endif
2147 set_x11_icon(icon); /* x11 */
2148#endif
2149 did_set_icon = TRUE;
2150 }
2151 --recursive;
2152}
2153
2154/*
2155 * Restore the window/icon title.
2156 * "which" is one of:
2157 * 1 only restore title
2158 * 2 only restore icon
2159 * 3 restore title and icon
2160 */
2161 void
2162mch_restore_title(which)
2163 int which;
2164{
2165 /* only restore the title or icon when it has been set */
2166 mch_settitle(((which & 1) && did_set_title) ?
2167 (oldtitle ? oldtitle : p_titleold) : NULL,
2168 ((which & 2) && did_set_icon) ? oldicon : NULL);
2169}
2170
2171#endif /* FEAT_TITLE */
2172
2173/*
2174 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002175 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002176 */
2177 int
2178vim_is_xterm(name)
2179 char_u *name;
2180{
2181 if (name == NULL)
2182 return FALSE;
2183 return (STRNICMP(name, "xterm", 5) == 0
2184 || STRNICMP(name, "nxterm", 6) == 0
2185 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002186 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002187 || STRNICMP(name, "rxvt", 4) == 0
2188 || STRCMP(name, "builtin_xterm") == 0);
2189}
2190
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002191#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2192/*
2193 * Return TRUE if "name" appears to be that of a terminal
2194 * known to support the xterm-style mouse protocol.
2195 * Relies on term_is_xterm having been set to its correct value.
2196 */
2197 int
2198use_xterm_like_mouse(name)
2199 char_u *name;
2200{
2201 return (name != NULL
2202 && (term_is_xterm || STRNICMP(name, "screen", 6) == 0));
2203}
2204#endif
2205
Bram Moolenaar071d4272004-06-13 20:20:40 +00002206#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2207/*
2208 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2209 * Return 1 for "xterm".
2210 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002211 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002212 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002213 */
2214 int
2215use_xterm_mouse()
2216{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002217 if (ttym_flags == TTYM_SGR)
2218 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002219 if (ttym_flags == TTYM_URXVT)
2220 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002221 if (ttym_flags == TTYM_XTERM2)
2222 return 2;
2223 if (ttym_flags == TTYM_XTERM)
2224 return 1;
2225 return 0;
2226}
2227#endif
2228
2229 int
2230vim_is_iris(name)
2231 char_u *name;
2232{
2233 if (name == NULL)
2234 return FALSE;
2235 return (STRNICMP(name, "iris-ansi", 9) == 0
2236 || STRCMP(name, "builtin_iris-ansi") == 0);
2237}
2238
2239 int
2240vim_is_vt300(name)
2241 char_u *name;
2242{
2243 if (name == NULL)
2244 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002245 /* catch VT100 - VT5xx */
2246 return ((STRNICMP(name, "vt", 2) == 0
2247 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248 || STRCMP(name, "builtin_vt320") == 0);
2249}
2250
2251/*
2252 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2253 * This should include all windowed terminal emulators.
2254 */
2255 int
2256vim_is_fastterm(name)
2257 char_u *name;
2258{
2259 if (name == NULL)
2260 return FALSE;
2261 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2262 return TRUE;
2263 return ( STRNICMP(name, "hpterm", 6) == 0
2264 || STRNICMP(name, "sun-cmd", 7) == 0
2265 || STRNICMP(name, "screen", 6) == 0
2266 || STRNICMP(name, "dtterm", 6) == 0);
2267}
2268
2269/*
2270 * Insert user name in s[len].
2271 * Return OK if a name found.
2272 */
2273 int
2274mch_get_user_name(s, len)
2275 char_u *s;
2276 int len;
2277{
2278#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002279 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002280 return OK;
2281#else
2282 return mch_get_uname(getuid(), s, len);
2283#endif
2284}
2285
2286/*
2287 * Insert user name for "uid" in s[len].
2288 * Return OK if a name found.
2289 */
2290 int
2291mch_get_uname(uid, s, len)
2292 uid_t uid;
2293 char_u *s;
2294 int len;
2295{
2296#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2297 struct passwd *pw;
2298
2299 if ((pw = getpwuid(uid)) != NULL
2300 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2301 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002302 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303 return OK;
2304 }
2305#endif
2306 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2307 return FAIL; /* a number is not a name */
2308}
2309
2310/*
2311 * Insert host name is s[len].
2312 */
2313
2314#ifdef HAVE_SYS_UTSNAME_H
2315 void
2316mch_get_host_name(s, len)
2317 char_u *s;
2318 int len;
2319{
2320 struct utsname vutsname;
2321
2322 if (uname(&vutsname) < 0)
2323 *s = NUL;
2324 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002325 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002326}
2327#else /* HAVE_SYS_UTSNAME_H */
2328
2329# ifdef HAVE_SYS_SYSTEMINFO_H
2330# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2331# endif
2332
2333 void
2334mch_get_host_name(s, len)
2335 char_u *s;
2336 int len;
2337{
2338# ifdef VAXC
2339 vaxc$gethostname((char *)s, len);
2340# else
2341 gethostname((char *)s, len);
2342# endif
2343 s[len - 1] = NUL; /* make sure it's terminated */
2344}
2345#endif /* HAVE_SYS_UTSNAME_H */
2346
2347/*
2348 * return process ID
2349 */
2350 long
2351mch_get_pid()
2352{
2353 return (long)getpid();
2354}
2355
2356#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2357static char *strerror __ARGS((int));
2358
2359 static char *
2360strerror(err)
2361 int err;
2362{
2363 extern int sys_nerr;
2364 extern char *sys_errlist[];
2365 static char er[20];
2366
2367 if (err > 0 && err < sys_nerr)
2368 return (sys_errlist[err]);
2369 sprintf(er, "Error %d", err);
2370 return er;
2371}
2372#endif
2373
2374/*
2375 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2376 * Return OK for success, FAIL for failure.
2377 */
2378 int
2379mch_dirname(buf, len)
2380 char_u *buf;
2381 int len;
2382{
2383#if defined(USE_GETCWD)
2384 if (getcwd((char *)buf, len) == NULL)
2385 {
2386 STRCPY(buf, strerror(errno));
2387 return FAIL;
2388 }
2389 return OK;
2390#else
2391 return (getwd((char *)buf) != NULL ? OK : FAIL);
2392#endif
2393}
2394
2395#if defined(OS2) || defined(PROTO)
2396/*
2397 * Replace all slashes by backslashes.
2398 * When 'shellslash' set do it the other way around.
2399 */
2400 void
2401slash_adjust(p)
2402 char_u *p;
2403{
2404 while (*p)
2405 {
2406 if (*p == psepcN)
2407 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002408 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409 }
2410}
2411#endif
2412
2413/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002414 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002415 *
2416 * return FAIL for failure, OK for success
2417 */
2418 int
2419mch_FullName(fname, buf, len, force)
2420 char_u *fname, *buf;
2421 int len;
2422 int force; /* also expand when already absolute path */
2423{
2424 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002425#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002427#endif
2428#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429 int fd = -1;
2430 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002431#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432 char_u olddir[MAXPATHL];
2433 char_u *p;
2434 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002435#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002436 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2437 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002438#endif
2439
Bram Moolenaar38323e42007-03-06 19:22:53 +00002440#ifdef VMS
2441 fname = vms_fixfilename(fname);
2442#endif
2443
Bram Moolenaara2442432007-04-26 14:26:37 +00002444#ifdef __CYGWIN__
2445 /*
2446 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2447 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002448# if CYGWIN_VERSION_DLL_MAJOR >= 1007
2449 cygwin_conv_path(CCP_WIN_A_TO_POSIX, fname, posix_fname, MAXPATHL);
2450# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002451 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002452# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002453 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002454#endif
2455
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 /* expand it if forced or not an absolute path */
2457 if (force || !mch_isFullName(fname))
2458 {
2459 /*
2460 * If the file name has a path, change to that directory for a moment,
2461 * and then do the getwd() (and get back to where we were).
2462 * This will get the correct path name with "../" things.
2463 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002464#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002465 only_drive = 0;
2466 if (((p = vim_strrchr(fname, '/')) != NULL)
2467 || ((p = vim_strrchr(fname, '\\')) != NULL)
2468 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002469#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002470 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002471#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002472 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002473#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 /*
2475 * Use fchdir() if possible, it's said to be faster and more
2476 * reliable. But on SunOS 4 it might not work. Check this by
2477 * doing a fchdir() right now.
2478 */
2479 if (!dont_fchdir)
2480 {
2481 fd = open(".", O_RDONLY | O_EXTRA, 0);
2482 if (fd >= 0 && fchdir(fd) < 0)
2483 {
2484 close(fd);
2485 fd = -1;
2486 dont_fchdir = TRUE; /* don't try again */
2487 }
2488 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002489#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002490
2491 /* Only change directory when we are sure we can return to where
2492 * we are now. After doing "su" chdir(".") might not work. */
2493 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002494#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002495 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002496#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002497 (mch_dirname(olddir, MAXPATHL) == FAIL
2498 || mch_chdir((char *)olddir) != 0))
2499 {
2500 p = NULL; /* can't get current dir: don't chdir */
2501 retval = FAIL;
2502 }
2503 else
2504 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002505#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002506 /*
2507 * compensate for case where ':' from "D:" was the only
2508 * path separator detected in the file name; the _next_
2509 * character has to be removed, and then restored later.
2510 */
2511 if (only_drive)
2512 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002513#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002514 /* The directory is copied into buf[], to be able to remove
2515 * the file name without changing it (could be a string in
2516 * read-only memory) */
2517 if (p - fname >= len)
2518 retval = FAIL;
2519 else
2520 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002521 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002522 if (mch_chdir((char *)buf))
2523 retval = FAIL;
2524 else
2525 fname = p + 1;
2526 *buf = NUL;
2527 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002528#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002529 if (only_drive)
2530 {
2531 p--;
2532 if (retval != FAIL)
2533 fname--;
2534 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002535#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002536 }
2537 }
2538 if (mch_dirname(buf, len) == FAIL)
2539 {
2540 retval = FAIL;
2541 *buf = NUL;
2542 }
2543 if (p != NULL)
2544 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002545#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002546 if (fd >= 0)
2547 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002548 if (p_verbose >= 5)
2549 {
2550 verbose_enter();
2551 MSG("fchdir() to previous dir");
2552 verbose_leave();
2553 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002554 l = fchdir(fd);
2555 close(fd);
2556 }
2557 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002558#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002559 l = mch_chdir((char *)olddir);
2560 if (l != 0)
2561 EMSG(_(e_prev_dir));
2562 }
2563
2564 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002565 if (l >= len - 1)
2566 retval = FAIL; /* no space for trailing "/" */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002567#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002568 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002569 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002570 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002571#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002572 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002573
Bram Moolenaar071d4272004-06-13 20:20:40 +00002574 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002575 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002576 return FAIL;
2577
2578 /* Do not append ".", "/dir/." is equal to "/dir". */
2579 if (STRCMP(fname, ".") != 0)
2580 STRCAT(buf, fname);
2581
2582 return OK;
2583}
2584
2585/*
2586 * Return TRUE if "fname" does not depend on the current directory.
2587 */
2588 int
2589mch_isFullName(fname)
2590 char_u *fname;
2591{
2592#ifdef __EMX__
2593 return _fnisabs(fname);
2594#else
2595# ifdef VMS
2596 return ( fname[0] == '/' || fname[0] == '.' ||
2597 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2598 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2599 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2600# else
2601 return (*fname == '/' || *fname == '~');
2602# endif
2603#endif
2604}
2605
Bram Moolenaar24552be2005-12-10 20:17:30 +00002606#if defined(USE_FNAME_CASE) || defined(PROTO)
2607/*
2608 * Set the case of the file name, if it already exists. This will cause the
2609 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002610 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002611 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002612 void
2613fname_case(name, len)
2614 char_u *name;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002615 int len UNUSED; /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002616{
2617 struct stat st;
2618 char_u *slash, *tail;
2619 DIR *dirp;
2620 struct dirent *dp;
2621
2622 if (lstat((char *)name, &st) >= 0)
2623 {
2624 /* Open the directory where the file is located. */
2625 slash = vim_strrchr(name, '/');
2626 if (slash == NULL)
2627 {
2628 dirp = opendir(".");
2629 tail = name;
2630 }
2631 else
2632 {
2633 *slash = NUL;
2634 dirp = opendir((char *)name);
2635 *slash = '/';
2636 tail = slash + 1;
2637 }
2638
2639 if (dirp != NULL)
2640 {
2641 while ((dp = readdir(dirp)) != NULL)
2642 {
2643 /* Only accept names that differ in case and are the same byte
2644 * length. TODO: accept different length name. */
2645 if (STRICMP(tail, dp->d_name) == 0
2646 && STRLEN(tail) == STRLEN(dp->d_name))
2647 {
2648 char_u newname[MAXPATHL + 1];
2649 struct stat st2;
2650
2651 /* Verify the inode is equal. */
2652 vim_strncpy(newname, name, MAXPATHL);
2653 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2654 MAXPATHL - (tail - name));
2655 if (lstat((char *)newname, &st2) >= 0
2656 && st.st_ino == st2.st_ino
2657 && st.st_dev == st2.st_dev)
2658 {
2659 STRCPY(tail, dp->d_name);
2660 break;
2661 }
2662 }
2663 }
2664
2665 closedir(dirp);
2666 }
2667 }
2668}
2669#endif
2670
Bram Moolenaar071d4272004-06-13 20:20:40 +00002671/*
2672 * Get file permissions for 'name'.
2673 * Returns -1 when it doesn't exist.
2674 */
2675 long
2676mch_getperm(name)
2677 char_u *name;
2678{
2679 struct stat statb;
2680
2681 /* Keep the #ifdef outside of stat(), it may be a macro. */
2682#ifdef VMS
2683 if (stat((char *)vms_fixfilename(name), &statb))
2684#else
2685 if (stat((char *)name, &statb))
2686#endif
2687 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002688#ifdef __INTERIX
2689 /* The top bit makes the value negative, which means the file doesn't
2690 * exist. Remove the bit, we don't use it. */
2691 return statb.st_mode & ~S_ADDACE;
2692#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002694#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002695}
2696
2697/*
2698 * set file permission for 'name' to 'perm'
2699 *
2700 * return FAIL for failure, OK otherwise
2701 */
2702 int
2703mch_setperm(name, perm)
2704 char_u *name;
2705 long perm;
2706{
2707 return (chmod((char *)
2708#ifdef VMS
2709 vms_fixfilename(name),
2710#else
2711 name,
2712#endif
2713 (mode_t)perm) == 0 ? OK : FAIL);
2714}
2715
2716#if defined(HAVE_ACL) || defined(PROTO)
2717# ifdef HAVE_SYS_ACL_H
2718# include <sys/acl.h>
2719# endif
2720# ifdef HAVE_SYS_ACCESS_H
2721# include <sys/access.h>
2722# endif
2723
2724# ifdef HAVE_SOLARIS_ACL
2725typedef struct vim_acl_solaris_T {
2726 int acl_cnt;
2727 aclent_t *acl_entry;
2728} vim_acl_solaris_T;
2729# endif
2730
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002731#if defined(HAVE_SELINUX) || defined(PROTO)
2732/*
2733 * Copy security info from "from_file" to "to_file".
2734 */
2735 void
2736mch_copy_sec(from_file, to_file)
2737 char_u *from_file;
2738 char_u *to_file;
2739{
2740 if (from_file == NULL)
2741 return;
2742
2743 if (selinux_enabled == -1)
2744 selinux_enabled = is_selinux_enabled();
2745
2746 if (selinux_enabled > 0)
2747 {
2748 security_context_t from_context = NULL;
2749 security_context_t to_context = NULL;
2750
2751 if (getfilecon((char *)from_file, &from_context) < 0)
2752 {
2753 /* If the filesystem doesn't support extended attributes,
2754 the original had no special security context and the
2755 target cannot have one either. */
2756 if (errno == EOPNOTSUPP)
2757 return;
2758
2759 MSG_PUTS(_("\nCould not get security context for "));
2760 msg_outtrans(from_file);
2761 msg_putchar('\n');
2762 return;
2763 }
2764 if (getfilecon((char *)to_file, &to_context) < 0)
2765 {
2766 MSG_PUTS(_("\nCould not get security context for "));
2767 msg_outtrans(to_file);
2768 msg_putchar('\n');
2769 freecon (from_context);
2770 return ;
2771 }
2772 if (strcmp(from_context, to_context) != 0)
2773 {
2774 if (setfilecon((char *)to_file, from_context) < 0)
2775 {
2776 MSG_PUTS(_("\nCould not set security context for "));
2777 msg_outtrans(to_file);
2778 msg_putchar('\n');
2779 }
2780 }
2781 freecon(to_context);
2782 freecon(from_context);
2783 }
2784}
2785#endif /* HAVE_SELINUX */
2786
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787/*
2788 * Return a pointer to the ACL of file "fname" in allocated memory.
2789 * Return NULL if the ACL is not available for whatever reason.
2790 */
2791 vim_acl_T
2792mch_get_acl(fname)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002793 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794{
2795 vim_acl_T ret = NULL;
2796#ifdef HAVE_POSIX_ACL
2797 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2798#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002799#ifdef HAVE_SOLARIS_ZFS_ACL
2800 acl_t *aclent;
2801
2802 if (acl_get((char *)fname, 0, &aclent) < 0)
2803 return NULL;
2804 ret = (vim_acl_T)aclent;
2805#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002806#ifdef HAVE_SOLARIS_ACL
2807 vim_acl_solaris_T *aclent;
2808
2809 aclent = malloc(sizeof(vim_acl_solaris_T));
2810 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2811 {
2812 free(aclent);
2813 return NULL;
2814 }
2815 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2816 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2817 {
2818 free(aclent->acl_entry);
2819 free(aclent);
2820 return NULL;
2821 }
2822 ret = (vim_acl_T)aclent;
2823#else
2824#if defined(HAVE_AIX_ACL)
2825 int aclsize;
2826 struct acl *aclent;
2827
2828 aclsize = sizeof(struct acl);
2829 aclent = malloc(aclsize);
2830 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2831 {
2832 if (errno == ENOSPC)
2833 {
2834 aclsize = aclent->acl_len;
2835 aclent = realloc(aclent, aclsize);
2836 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2837 {
2838 free(aclent);
2839 return NULL;
2840 }
2841 }
2842 else
2843 {
2844 free(aclent);
2845 return NULL;
2846 }
2847 }
2848 ret = (vim_acl_T)aclent;
2849#endif /* HAVE_AIX_ACL */
2850#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002851#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002852#endif /* HAVE_POSIX_ACL */
2853 return ret;
2854}
2855
2856/*
2857 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2858 */
2859 void
2860mch_set_acl(fname, aclent)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002861 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002862 vim_acl_T aclent;
2863{
2864 if (aclent == NULL)
2865 return;
2866#ifdef HAVE_POSIX_ACL
2867 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2868#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002869#ifdef HAVE_SOLARIS_ZFS_ACL
2870 acl_set((char *)fname, (acl_t *)aclent);
2871#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002872#ifdef HAVE_SOLARIS_ACL
2873 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2874 ((vim_acl_solaris_T *)aclent)->acl_entry);
2875#else
2876#ifdef HAVE_AIX_ACL
2877 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2878#endif /* HAVE_AIX_ACL */
2879#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002880#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002881#endif /* HAVE_POSIX_ACL */
2882}
2883
2884 void
2885mch_free_acl(aclent)
2886 vim_acl_T aclent;
2887{
2888 if (aclent == NULL)
2889 return;
2890#ifdef HAVE_POSIX_ACL
2891 acl_free((acl_t)aclent);
2892#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002893#ifdef HAVE_SOLARIS_ZFS_ACL
2894 acl_free((acl_t *)aclent);
2895#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896#ifdef HAVE_SOLARIS_ACL
2897 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2898 free(aclent);
2899#else
2900#ifdef HAVE_AIX_ACL
2901 free(aclent);
2902#endif /* HAVE_AIX_ACL */
2903#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002904#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905#endif /* HAVE_POSIX_ACL */
2906}
2907#endif
2908
2909/*
2910 * Set hidden flag for "name".
2911 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002912 void
2913mch_hide(name)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002914 char_u *name UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002915{
2916 /* can't hide a file */
2917}
2918
2919/*
2920 * return TRUE if "name" is a directory
2921 * return FALSE if "name" is not a directory
2922 * return FALSE for error
2923 */
2924 int
2925mch_isdir(name)
2926 char_u *name;
2927{
2928 struct stat statb;
2929
2930 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2931 return FALSE;
2932 if (stat((char *)name, &statb))
2933 return FALSE;
2934#ifdef _POSIX_SOURCE
2935 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2936#else
2937 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2938#endif
2939}
2940
Bram Moolenaar071d4272004-06-13 20:20:40 +00002941static int executable_file __ARGS((char_u *name));
2942
2943/*
2944 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2945 */
2946 static int
2947executable_file(name)
2948 char_u *name;
2949{
2950 struct stat st;
2951
2952 if (stat((char *)name, &st))
2953 return 0;
2954 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2955}
2956
2957/*
2958 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2959 * Return -1 if unknown.
2960 */
2961 int
2962mch_can_exe(name)
2963 char_u *name;
2964{
2965 char_u *buf;
2966 char_u *p, *e;
2967 int retval;
2968
2969 /* If it's an absolute or relative path don't need to use $PATH. */
2970 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2971 || (name[1] == '.' && name[2] == '/'))))
2972 return executable_file(name);
2973
2974 p = (char_u *)getenv("PATH");
2975 if (p == NULL || *p == NUL)
2976 return -1;
2977 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2978 if (buf == NULL)
2979 return -1;
2980
2981 /*
2982 * Walk through all entries in $PATH to check if "name" exists there and
2983 * is an executable file.
2984 */
2985 for (;;)
2986 {
2987 e = (char_u *)strchr((char *)p, ':');
2988 if (e == NULL)
2989 e = p + STRLEN(p);
2990 if (e - p <= 1) /* empty entry means current dir */
2991 STRCPY(buf, "./");
2992 else
2993 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002994 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002995 add_pathsep(buf);
2996 }
2997 STRCAT(buf, name);
2998 retval = executable_file(buf);
2999 if (retval == 1)
3000 break;
3001
3002 if (*e != ':')
3003 break;
3004 p = e + 1;
3005 }
3006
3007 vim_free(buf);
3008 return retval;
3009}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003010
3011/*
3012 * Check what "name" is:
3013 * NODE_NORMAL: file or directory (or doesn't exist)
3014 * NODE_WRITABLE: writable device, socket, fifo, etc.
3015 * NODE_OTHER: non-writable things
3016 */
3017 int
3018mch_nodetype(name)
3019 char_u *name;
3020{
3021 struct stat st;
3022
3023 if (stat((char *)name, &st))
3024 return NODE_NORMAL;
3025 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3026 return NODE_NORMAL;
3027#ifndef OS2
3028 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
3029 return NODE_OTHER;
3030#endif
3031 /* Everything else is writable? */
3032 return NODE_WRITABLE;
3033}
3034
3035 void
3036mch_early_init()
3037{
3038#ifdef HAVE_CHECK_STACK_GROWTH
3039 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003040
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041 check_stack_growth((char *)&i);
3042
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003043# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003044 get_stack_limit();
3045# endif
3046
3047#endif
3048
3049 /*
3050 * Setup an alternative stack for signals. Helps to catch signals when
3051 * running out of stack space.
3052 * Use of sigaltstack() is preferred, it's more portable.
3053 * Ignore any errors.
3054 */
3055#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00003056 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003057 init_signal_stack();
3058#endif
3059}
3060
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003061#if defined(EXITFREE) || defined(PROTO)
3062 void
3063mch_free_mem()
3064{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003065# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3066 if (clip_star.owned)
3067 clip_lose_selection(&clip_star);
3068 if (clip_plus.owned)
3069 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003070# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003071# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003072 if (xterm_Shell != (Widget)0)
3073 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003074# ifndef LESSTIF_VERSION
3075 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003076 if (xterm_dpy != NULL)
3077 XtCloseDisplay(xterm_dpy);
3078 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003079 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003080 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003081# ifdef FEAT_X11
3082 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
3083# endif
3084 }
3085# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003086# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003087# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003088 if (x11_display != NULL
3089# ifdef FEAT_XCLIPBOARD
3090 && x11_display != xterm_dpy
3091# endif
3092 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003093 XCloseDisplay(x11_display);
3094# endif
3095# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
3096 vim_free(signal_stack);
3097 signal_stack = NULL;
3098# endif
3099# ifdef FEAT_TITLE
3100 vim_free(oldtitle);
3101 vim_free(oldicon);
3102# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003103}
3104#endif
3105
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106static void exit_scroll __ARGS((void));
3107
3108/*
3109 * Output a newline when exiting.
3110 * Make sure the newline goes to the same stream as the text.
3111 */
3112 static void
3113exit_scroll()
3114{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003115 if (silent_mode)
3116 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003117 if (newline_on_exit || msg_didout)
3118 {
3119 if (msg_use_printf())
3120 {
3121 if (info_message)
3122 mch_msg("\n");
3123 else
3124 mch_errmsg("\r\n");
3125 }
3126 else
3127 out_char('\n');
3128 }
3129 else
3130 {
3131 restore_cterm_colors(); /* get original colors back */
3132 msg_clr_eos_force(); /* clear the rest of the display */
3133 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3134 }
3135}
3136
3137 void
3138mch_exit(r)
3139 int r;
3140{
3141 exiting = TRUE;
3142
3143#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3144 x11_export_final_selection();
3145#endif
3146
3147#ifdef FEAT_GUI
3148 if (!gui.in_use)
3149#endif
3150 {
3151 settmode(TMODE_COOK);
3152#ifdef FEAT_TITLE
3153 mch_restore_title(3); /* restore xterm title and icon name */
3154#endif
3155 /*
3156 * When t_ti is not empty but it doesn't cause swapping terminal
3157 * pages, need to output a newline when msg_didout is set. But when
3158 * t_ti does swap pages it should not go to the shell page. Do this
3159 * before stoptermcap().
3160 */
3161 if (swapping_screen() && !newline_on_exit)
3162 exit_scroll();
3163
3164 /* Stop termcap: May need to check for T_CRV response, which
3165 * requires RAW mode. */
3166 stoptermcap();
3167
3168 /*
3169 * A newline is only required after a message in the alternate screen.
3170 * This is set to TRUE by wait_return().
3171 */
3172 if (!swapping_screen() || newline_on_exit)
3173 exit_scroll();
3174
3175 /* Cursor may have been switched off without calling starttermcap()
3176 * when doing "vim -u vimrc" and vimrc contains ":q". */
3177 if (full_screen)
3178 cursor_on();
3179 }
3180 out_flush();
3181 ml_close_all(TRUE); /* remove all memfiles */
3182 may_core_dump();
3183#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003184 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003185 gui_exit(r);
3186#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003187
Bram Moolenaar56718732006-03-15 22:53:57 +00003188#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003189 mac_conv_cleanup();
3190#endif
3191
Bram Moolenaar071d4272004-06-13 20:20:40 +00003192#ifdef __QNX__
3193 /* A core dump won't be created if the signal handler
3194 * doesn't return, so we can't call exit() */
3195 if (deadly_signal != 0)
3196 return;
3197#endif
3198
Bram Moolenaar009b2592004-10-24 19:18:58 +00003199#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003200 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003201#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003202
3203#ifdef EXITFREE
3204 free_all_mem();
3205#endif
3206
Bram Moolenaar071d4272004-06-13 20:20:40 +00003207 exit(r);
3208}
3209
3210 static void
3211may_core_dump()
3212{
3213 if (deadly_signal != 0)
3214 {
3215 signal(deadly_signal, SIG_DFL);
3216 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3217 }
3218}
3219
3220#ifndef VMS
3221
3222 void
3223mch_settmode(tmode)
3224 int tmode;
3225{
3226 static int first = TRUE;
3227
3228 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3229#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3230 /*
3231 * for "new" tty systems
3232 */
3233# ifdef HAVE_TERMIOS_H
3234 static struct termios told;
3235 struct termios tnew;
3236# else
3237 static struct termio told;
3238 struct termio tnew;
3239# endif
3240
3241 if (first)
3242 {
3243 first = FALSE;
3244# if defined(HAVE_TERMIOS_H)
3245 tcgetattr(read_cmd_fd, &told);
3246# else
3247 ioctl(read_cmd_fd, TCGETA, &told);
3248# endif
3249 }
3250
3251 tnew = told;
3252 if (tmode == TMODE_RAW)
3253 {
3254 /*
3255 * ~ICRNL enables typing ^V^M
3256 */
3257 tnew.c_iflag &= ~ICRNL;
3258 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3259# if defined(IEXTEN) && !defined(__MINT__)
3260 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3261 /* but it breaks function keys on MINT */
3262# endif
3263 );
3264# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3265 tnew.c_oflag &= ~ONLCR;
3266# endif
3267 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3268 tnew.c_cc[VTIME] = 0; /* don't wait */
3269 }
3270 else if (tmode == TMODE_SLEEP)
3271 tnew.c_lflag &= ~(ECHO);
3272
3273# if defined(HAVE_TERMIOS_H)
3274 {
3275 int n = 10;
3276
3277 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3278 * few times. */
3279 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3280 && errno == EINTR && n > 0)
3281 --n;
3282 }
3283# else
3284 ioctl(read_cmd_fd, TCSETA, &tnew);
3285# endif
3286
3287#else
3288
3289 /*
3290 * for "old" tty systems
3291 */
3292# ifndef TIOCSETN
3293# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3294# endif
3295 static struct sgttyb ttybold;
3296 struct sgttyb ttybnew;
3297
3298 if (first)
3299 {
3300 first = FALSE;
3301 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3302 }
3303
3304 ttybnew = ttybold;
3305 if (tmode == TMODE_RAW)
3306 {
3307 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3308 ttybnew.sg_flags |= RAW;
3309 }
3310 else if (tmode == TMODE_SLEEP)
3311 ttybnew.sg_flags &= ~(ECHO);
3312 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3313#endif
3314 curr_tmode = tmode;
3315}
3316
3317/*
3318 * Try to get the code for "t_kb" from the stty setting
3319 *
3320 * Even if termcap claims a backspace key, the user's setting *should*
3321 * prevail. stty knows more about reality than termcap does, and if
3322 * somebody's usual erase key is DEL (which, for most BSD users, it will
3323 * be), they're going to get really annoyed if their erase key starts
3324 * doing forward deletes for no reason. (Eric Fischer)
3325 */
3326 void
3327get_stty()
3328{
3329 char_u buf[2];
3330 char_u *p;
3331
3332 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3333#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3334 /* for "new" tty systems */
3335# ifdef HAVE_TERMIOS_H
3336 struct termios keys;
3337# else
3338 struct termio keys;
3339# endif
3340
3341# if defined(HAVE_TERMIOS_H)
3342 if (tcgetattr(read_cmd_fd, &keys) != -1)
3343# else
3344 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3345# endif
3346 {
3347 buf[0] = keys.c_cc[VERASE];
3348 intr_char = keys.c_cc[VINTR];
3349#else
3350 /* for "old" tty systems */
3351 struct sgttyb keys;
3352
3353 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3354 {
3355 buf[0] = keys.sg_erase;
3356 intr_char = keys.sg_kill;
3357#endif
3358 buf[1] = NUL;
3359 add_termcode((char_u *)"kb", buf, FALSE);
3360
3361 /*
3362 * If <BS> and <DEL> are now the same, redefine <DEL>.
3363 */
3364 p = find_termcode((char_u *)"kD");
3365 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3366 do_fixdel(NULL);
3367 }
3368#if 0
3369 } /* to keep cindent happy */
3370#endif
3371}
3372
3373#endif /* VMS */
3374
3375#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3376/*
3377 * Set mouse clicks on or off.
3378 */
3379 void
3380mch_setmouse(on)
3381 int on;
3382{
3383 static int ison = FALSE;
3384 int xterm_mouse_vers;
3385
3386 if (on == ison) /* return quickly if nothing to do */
3387 return;
3388
3389 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003390
3391# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003392 if (ttym_flags == TTYM_URXVT)
3393 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003394 out_str_nf((char_u *)
3395 (on
3396 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3397 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
3398 ison = on;
3399 }
3400# endif
3401
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003402# ifdef FEAT_MOUSE_SGR
3403 if (ttym_flags == TTYM_SGR)
3404 {
3405 out_str_nf((char_u *)
3406 (on
3407 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3408 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
3409 ison = on;
3410 }
3411# endif
3412
Bram Moolenaar071d4272004-06-13 20:20:40 +00003413 if (xterm_mouse_vers > 0)
3414 {
3415 if (on) /* enable mouse events, use mouse tracking if available */
3416 out_str_nf((char_u *)
3417 (xterm_mouse_vers > 1
3418 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3419 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3420 else /* disable mouse events, could probably always send the same */
3421 out_str_nf((char_u *)
3422 (xterm_mouse_vers > 1
3423 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3424 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3425 ison = on;
3426 }
3427
3428# ifdef FEAT_MOUSE_DEC
3429 else if (ttym_flags == TTYM_DEC)
3430 {
3431 if (on) /* enable mouse events */
3432 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3433 else /* disable mouse events */
3434 out_str_nf((char_u *)"\033['z");
3435 ison = on;
3436 }
3437# endif
3438
3439# ifdef FEAT_MOUSE_GPM
3440 else
3441 {
3442 if (on)
3443 {
3444 if (gpm_open())
3445 ison = TRUE;
3446 }
3447 else
3448 {
3449 gpm_close();
3450 ison = FALSE;
3451 }
3452 }
3453# endif
3454
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003455# ifdef FEAT_SYSMOUSE
3456 else
3457 {
3458 if (on)
3459 {
3460 if (sysmouse_open() == OK)
3461 ison = TRUE;
3462 }
3463 else
3464 {
3465 sysmouse_close();
3466 ison = FALSE;
3467 }
3468 }
3469# endif
3470
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471# ifdef FEAT_MOUSE_JSB
3472 else
3473 {
3474 if (on)
3475 {
3476 /* D - Enable Mouse up/down messages
3477 * L - Enable Left Button Reporting
3478 * M - Enable Middle Button Reporting
3479 * R - Enable Right Button Reporting
3480 * K - Enable SHIFT and CTRL key Reporting
3481 * + - Enable Advanced messaging of mouse moves and up/down messages
3482 * Q - Quiet No Ack
3483 * # - Numeric value of mouse pointer required
3484 * 0 = Multiview 2000 cursor, used as standard
3485 * 1 = Windows Arrow
3486 * 2 = Windows I Beam
3487 * 3 = Windows Hour Glass
3488 * 4 = Windows Cross Hair
3489 * 5 = Windows UP Arrow
3490 */
3491#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3492 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3493 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3494#else
3495 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3496 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3497#endif
3498 ison = TRUE;
3499 }
3500 else
3501 {
3502 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3503 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3504 ison = FALSE;
3505 }
3506 }
3507# endif
3508# ifdef FEAT_MOUSE_PTERM
3509 else
3510 {
3511 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3512 if (on)
3513 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3514 else
3515 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3516 ison = on;
3517 }
3518# endif
3519}
3520
3521/*
3522 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3523 */
3524 void
3525check_mouse_termcode()
3526{
3527# ifdef FEAT_MOUSE_XTERM
3528 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003529# ifdef FEAT_MOUSE_URXVT
3530 && use_xterm_mouse() != 3
3531# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532# ifdef FEAT_GUI
3533 && !gui.in_use
3534# endif
3535 )
3536 {
3537 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003538 ? IF_EB("\233M", CSI_STR "M")
3539 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540 if (*p_mouse != NUL)
3541 {
3542 /* force mouse off and maybe on to send possibly new mouse
3543 * activation sequence to the xterm, with(out) drag tracing. */
3544 mch_setmouse(FALSE);
3545 setmouse();
3546 }
3547 }
3548 else
3549 del_mouse_termcode(KS_MOUSE);
3550# endif
3551
3552# ifdef FEAT_MOUSE_GPM
3553 if (!use_xterm_mouse()
3554# ifdef FEAT_GUI
3555 && !gui.in_use
3556# endif
3557 )
3558 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3559# endif
3560
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003561# ifdef FEAT_SYSMOUSE
3562 if (!use_xterm_mouse()
3563# ifdef FEAT_GUI
3564 && !gui.in_use
3565# endif
3566 )
3567 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3568# endif
3569
Bram Moolenaar071d4272004-06-13 20:20:40 +00003570# ifdef FEAT_MOUSE_JSB
3571 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3572 if (!use_xterm_mouse()
3573# ifdef FEAT_GUI
3574 && !gui.in_use
3575# endif
3576 )
3577 set_mouse_termcode(KS_JSBTERM_MOUSE,
3578 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3579 else
3580 del_mouse_termcode(KS_JSBTERM_MOUSE);
3581# endif
3582
3583# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003584 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003585 * define it in the GUI or when using an xterm. */
3586 if (!use_xterm_mouse()
3587# ifdef FEAT_GUI
3588 && !gui.in_use
3589# endif
3590 )
3591 set_mouse_termcode(KS_NETTERM_MOUSE,
3592 (char_u *)IF_EB("\033}", ESC_STR "}"));
3593 else
3594 del_mouse_termcode(KS_NETTERM_MOUSE);
3595# endif
3596
3597# ifdef FEAT_MOUSE_DEC
3598 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3599 if (!use_xterm_mouse()
3600# ifdef FEAT_GUI
3601 && !gui.in_use
3602# endif
3603 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003604 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3605 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003606 else
3607 del_mouse_termcode(KS_DEC_MOUSE);
3608# endif
3609# ifdef FEAT_MOUSE_PTERM
3610 /* same as the dec mouse */
3611 if (!use_xterm_mouse()
3612# ifdef FEAT_GUI
3613 && !gui.in_use
3614# endif
3615 )
3616 set_mouse_termcode(KS_PTERM_MOUSE,
3617 (char_u *) IF_EB("\033[", ESC_STR "["));
3618 else
3619 del_mouse_termcode(KS_PTERM_MOUSE);
3620# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003621# ifdef FEAT_MOUSE_URXVT
3622 /* same as the dec mouse */
3623 if (use_xterm_mouse() == 3
3624# ifdef FEAT_GUI
3625 && !gui.in_use
3626# endif
3627 )
3628 {
3629 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3630 ? IF_EB("\233", CSI_STR)
3631 : IF_EB("\033[", ESC_STR "[")));
3632
3633 if (*p_mouse != NUL)
3634 {
3635 mch_setmouse(FALSE);
3636 setmouse();
3637 }
3638 }
3639 else
3640 del_mouse_termcode(KS_URXVT_MOUSE);
3641# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003642# ifdef FEAT_MOUSE_SGR
3643 /* same as the dec mouse */
3644 if (use_xterm_mouse() == 4
3645# ifdef FEAT_GUI
3646 && !gui.in_use
3647# endif
3648 )
3649 {
3650 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3651 ? IF_EB("\233<", CSI_STR "<")
3652 : IF_EB("\033[<", ESC_STR "[<")));
3653
3654 if (*p_mouse != NUL)
3655 {
3656 mch_setmouse(FALSE);
3657 setmouse();
3658 }
3659 }
3660 else
3661 del_mouse_termcode(KS_SGR_MOUSE);
3662# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663}
3664#endif
3665
3666/*
3667 * set screen mode, always fails.
3668 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669 int
3670mch_screenmode(arg)
Bram Moolenaar78a15312009-05-15 19:33:18 +00003671 char_u *arg UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003672{
3673 EMSG(_(e_screenmode));
3674 return FAIL;
3675}
3676
3677#ifndef VMS
3678
3679/*
3680 * Try to get the current window size:
3681 * 1. with an ioctl(), most accurate method
3682 * 2. from the environment variables LINES and COLUMNS
3683 * 3. from the termcap
3684 * 4. keep using the old values
3685 * Return OK when size could be determined, FAIL otherwise.
3686 */
3687 int
3688mch_get_shellsize()
3689{
3690 long rows = 0;
3691 long columns = 0;
3692 char_u *p;
3693
3694 /*
3695 * For OS/2 use _scrsize().
3696 */
3697# ifdef __EMX__
3698 {
3699 int s[2];
3700
3701 _scrsize(s);
3702 columns = s[0];
3703 rows = s[1];
3704 }
3705# endif
3706
3707 /*
3708 * 1. try using an ioctl. It is the most accurate method.
3709 *
3710 * Try using TIOCGWINSZ first, some systems that have it also define
3711 * TIOCGSIZE but don't have a struct ttysize.
3712 */
3713# ifdef TIOCGWINSZ
3714 {
3715 struct winsize ws;
3716 int fd = 1;
3717
3718 /* When stdout is not a tty, use stdin for the ioctl(). */
3719 if (!isatty(fd) && isatty(read_cmd_fd))
3720 fd = read_cmd_fd;
3721 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3722 {
3723 columns = ws.ws_col;
3724 rows = ws.ws_row;
3725 }
3726 }
3727# else /* TIOCGWINSZ */
3728# ifdef TIOCGSIZE
3729 {
3730 struct ttysize ts;
3731 int fd = 1;
3732
3733 /* When stdout is not a tty, use stdin for the ioctl(). */
3734 if (!isatty(fd) && isatty(read_cmd_fd))
3735 fd = read_cmd_fd;
3736 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3737 {
3738 columns = ts.ts_cols;
3739 rows = ts.ts_lines;
3740 }
3741 }
3742# endif /* TIOCGSIZE */
3743# endif /* TIOCGWINSZ */
3744
3745 /*
3746 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003747 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3748 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003749 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003750 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751 {
3752 if ((p = (char_u *)getenv("LINES")))
3753 rows = atoi((char *)p);
3754 if ((p = (char_u *)getenv("COLUMNS")))
3755 columns = atoi((char *)p);
3756 }
3757
3758#ifdef HAVE_TGETENT
3759 /*
3760 * 3. try reading "co" and "li" entries from termcap
3761 */
3762 if (columns == 0 || rows == 0)
3763 getlinecol(&columns, &rows);
3764#endif
3765
3766 /*
3767 * 4. If everything fails, use the old values
3768 */
3769 if (columns <= 0 || rows <= 0)
3770 return FAIL;
3771
3772 Rows = rows;
3773 Columns = columns;
3774 return OK;
3775}
3776
3777/*
3778 * Try to set the window size to Rows and Columns.
3779 */
3780 void
3781mch_set_shellsize()
3782{
3783 if (*T_CWS)
3784 {
3785 /*
3786 * NOTE: if you get an error here that term_set_winsize() is
3787 * undefined, check the output of configure. It could probably not
3788 * find a ncurses, termcap or termlib library.
3789 */
3790 term_set_winsize((int)Rows, (int)Columns);
3791 out_flush();
3792 screen_start(); /* don't know where cursor is now */
3793 }
3794}
3795
3796#endif /* VMS */
3797
3798/*
3799 * Rows and/or Columns has changed.
3800 */
3801 void
3802mch_new_shellsize()
3803{
3804 /* Nothing to do. */
3805}
3806
Bram Moolenaar205b8862011-09-07 15:04:31 +02003807/*
3808 * Wait for process "child" to end.
3809 * Return "child" if it exited properly, <= 0 on error.
3810 */
3811 static pid_t
3812wait4pid(child, status)
3813 pid_t child;
3814 waitstatus *status;
3815{
3816 pid_t wait_pid = 0;
3817
3818 while (wait_pid != child)
3819 {
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003820 /* When compiled with Python threads are probably used, in which case
3821 * wait() sometimes hangs for no obvious reason. Use waitpid()
3822 * instead and loop (like the GUI). Also needed for other interfaces,
3823 * they might call system(). */
3824# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02003825 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003826# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02003827 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003828# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02003829 if (wait_pid == 0)
3830 {
Bram Moolenaar75676462013-01-30 14:55:42 +01003831 /* Wait for 10 msec before trying again. */
Bram Moolenaar205b8862011-09-07 15:04:31 +02003832 mch_delay(10L, TRUE);
3833 continue;
3834 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02003835 if (wait_pid <= 0
3836# ifdef ECHILD
3837 && errno == ECHILD
3838# endif
3839 )
3840 break;
3841 }
3842 return wait_pid;
3843}
3844
Bram Moolenaar071d4272004-06-13 20:20:40 +00003845 int
3846mch_call_shell(cmd, options)
3847 char_u *cmd;
3848 int options; /* SHELL_*, see vim.h */
3849{
3850#ifdef VMS
3851 char *ifn = NULL;
3852 char *ofn = NULL;
3853#endif
3854 int tmode = cur_tmode;
3855#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3856 int x;
3857# ifndef __EMX__
3858 char_u *newcmd; /* only needed for unix */
3859# else
3860 /*
3861 * Set the preferred shell in the EMXSHELL environment variable (but
3862 * only if it is different from what is already in the environment).
3863 * Emx then takes care of whether to use "/c" or "-c" in an
3864 * intelligent way. Simply pass the whole thing to emx's system() call.
3865 * Emx also starts an interactive shell if system() is passed an empty
3866 * string.
3867 */
3868 char_u *p, *old;
3869
3870 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3871 {
3872 /* should check HAVE_SETENV, but I know we don't have it. */
3873 p = alloc(10 + strlen(p_sh));
3874 if (p)
3875 {
3876 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3877 putenv((char *)p); /* don't free the pointer! */
3878 }
3879 }
3880# endif
3881
3882 out_flush();
3883
3884 if (options & SHELL_COOKED)
3885 settmode(TMODE_COOK); /* set to normal mode */
3886
Bram Moolenaar62b42182010-09-21 22:09:37 +02003887# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01003888 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02003889 loose_clipboard();
3890# endif
3891
Bram Moolenaar071d4272004-06-13 20:20:40 +00003892# ifdef __EMX__
3893 if (cmd == NULL)
3894 x = system(""); /* this starts an interactive shell in emx */
3895 else
3896 x = system((char *)cmd);
3897 /* system() returns -1 when error occurs in starting shell */
3898 if (x == -1 && !emsg_silent)
3899 {
3900 MSG_PUTS(_("\nCannot execute shell "));
3901 msg_outtrans(p_sh);
3902 msg_putchar('\n');
3903 }
3904# else /* not __EMX__ */
3905 if (cmd == NULL)
3906 x = system((char *)p_sh);
3907 else
3908 {
3909# ifdef VMS
3910 if (ofn = strchr((char *)cmd, '>'))
3911 *ofn++ = '\0';
3912 if (ifn = strchr((char *)cmd, '<'))
3913 {
3914 char *p;
3915
3916 *ifn++ = '\0';
3917 p = strchr(ifn,' '); /* chop off any trailing spaces */
3918 if (p)
3919 *p = '\0';
3920 }
3921 if (ofn)
3922 x = vms_sys((char *)cmd, ofn, ifn);
3923 else
3924 x = system((char *)cmd);
3925# else
3926 newcmd = lalloc(STRLEN(p_sh)
3927 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3928 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3929 if (newcmd == NULL)
3930 x = 0;
3931 else
3932 {
3933 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3934 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3935 (char *)p_shcf,
3936 (char *)cmd);
3937 x = system((char *)newcmd);
3938 vim_free(newcmd);
3939 }
3940# endif
3941 }
3942# ifdef VMS
3943 x = vms_sys_status(x);
3944# endif
3945 if (emsg_silent)
3946 ;
3947 else if (x == 127)
3948 MSG_PUTS(_("\nCannot execute shell sh\n"));
3949# endif /* __EMX__ */
3950 else if (x && !(options & SHELL_SILENT))
3951 {
3952 MSG_PUTS(_("\nshell returned "));
3953 msg_outnum((long)x);
3954 msg_putchar('\n');
3955 }
3956
3957 if (tmode == TMODE_RAW)
3958 settmode(TMODE_RAW); /* set to raw mode */
3959# ifdef FEAT_TITLE
3960 resettitle();
3961# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01003962# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3963 restore_clipboard();
3964# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003965 return x;
3966
3967#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3968
Bram Moolenaardf177f62005-02-22 08:39:57 +00003969# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3970 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003971
3972 char_u *newcmd = NULL;
3973 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003974 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003975 pid_t wait_pid = 0;
3976# ifdef HAVE_UNION_WAIT
3977 union wait status;
3978# else
3979 int status = -1;
3980# endif
3981 int retval = -1;
3982 char **argv = NULL;
3983 int argc;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02003984 char_u *p_shcf_copy = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003985 int i;
3986 char_u *p;
3987 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003988 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003989# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003990 int pty_slave_fd = -1;
3991 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003992# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003993 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994 int fd_fromshell[2];
3995 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003996# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003997 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003998# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003999 static char envbuf_Rows[20];
4000 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004001# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004002 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004003
Bram Moolenaar62b42182010-09-21 22:09:37 +02004004 newcmd = vim_strsave(p_sh);
4005 if (newcmd == NULL) /* out of memory */
4006 goto error;
4007
Bram Moolenaar071d4272004-06-13 20:20:40 +00004008 out_flush();
4009 if (options & SHELL_COOKED)
4010 settmode(TMODE_COOK); /* set to normal mode */
4011
Bram Moolenaar62b42182010-09-21 22:09:37 +02004012# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004013 /* Disown the clipboard, because is the executed command tries to obtain a
4014 * selection and we own it we get a deadlock. */
4015 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02004016 loose_clipboard();
4017# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004018
4019 /*
4020 * Do this loop twice:
4021 * 1: find number of arguments
4022 * 2: separate them and build argv[]
4023 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024 for (i = 0; i < 2; ++i)
4025 {
4026 p = newcmd;
4027 inquote = FALSE;
4028 argc = 0;
4029 for (;;)
4030 {
4031 if (i == 1)
4032 argv[argc] = (char *)p;
4033 ++argc;
4034 while (*p && (inquote || (*p != ' ' && *p != TAB)))
4035 {
4036 if (*p == '"')
4037 inquote = !inquote;
4038 ++p;
4039 }
4040 if (*p == NUL)
4041 break;
4042 if (i == 1)
4043 *p++ = NUL;
4044 p = skipwhite(p);
4045 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00004046 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004047 {
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004048 /*
4049 * Account for possible multiple args in p_shcf.
4050 */
4051 p = p_shcf;
4052 for (;;)
4053 {
4054 p = skiptowhite(p);
4055 if (*p == NUL)
4056 break;
4057 ++argc;
4058 p = skipwhite(p);
4059 }
4060
Bram Moolenaar071d4272004-06-13 20:20:40 +00004061 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
4062 if (argv == NULL) /* out of memory */
4063 goto error;
4064 }
4065 }
4066 if (cmd != NULL)
4067 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004068 char_u *s;
4069
Bram Moolenaar071d4272004-06-13 20:20:40 +00004070 if (extra_shell_arg != NULL)
4071 argv[argc++] = (char *)extra_shell_arg;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004072
4073 /* Break 'shellcmdflag' into white separated parts. This doesn't
4074 * handle quoted strings, they are very unlikely to appear. */
4075 p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
4076 if (p_shcf_copy == NULL) /* out of memory */
4077 goto error;
4078 s = p_shcf_copy;
4079 p = p_shcf;
4080 while (*p != NUL)
4081 {
4082 argv[argc++] = (char *)s;
4083 while (*p && *p != ' ' && *p != TAB)
4084 *s++ = *p++;
4085 *s++ = NUL;
4086 p = skipwhite(p);
4087 }
4088
Bram Moolenaar071d4272004-06-13 20:20:40 +00004089 argv[argc++] = (char *)cmd;
4090 }
4091 argv[argc] = NULL;
4092
Bram Moolenaar071d4272004-06-13 20:20:40 +00004093 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004094 * For the GUI, when writing the output into the buffer and when reading
4095 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4096 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004097 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004098 if ((options & (SHELL_READ|SHELL_WRITE))
4099# ifdef FEAT_GUI
4100 || (gui.in_use && show_shell_mess)
4101# endif
4102 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004103 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004104# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004105 /*
4106 * Try to open a master pty.
4107 * If this works, open the slave pty.
4108 * If the slave can't be opened, close the master pty.
4109 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004110 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004111 {
4112 pty_master_fd = OpenPTY(&tty_name); /* open pty */
Bram Moolenaare70172e2011-08-04 19:36:52 +02004113 if (pty_master_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114 {
Bram Moolenaare70172e2011-08-04 19:36:52 +02004115 /* Leaving out O_NOCTTY may lead to waitpid() always returning
4116 * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4117 * adding O_NOCTTY always works when defined. */
4118#ifdef O_NOCTTY
4119 pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4120#else
4121 pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4122#endif
4123 if (pty_slave_fd < 0)
4124 {
4125 close(pty_master_fd);
4126 pty_master_fd = -1;
4127 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004128 }
4129 }
4130 /*
4131 * If not opening a pty or it didn't work, try using pipes.
4132 */
4133 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004134# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135 {
4136 pipe_error = (pipe(fd_toshell) < 0);
4137 if (!pipe_error) /* pipe create OK */
4138 {
4139 pipe_error = (pipe(fd_fromshell) < 0);
4140 if (pipe_error) /* pipe create failed */
4141 {
4142 close(fd_toshell[0]);
4143 close(fd_toshell[1]);
4144 }
4145 }
4146 if (pipe_error)
4147 {
4148 MSG_PUTS(_("\nCannot create pipes\n"));
4149 out_flush();
4150 }
4151 }
4152 }
4153
4154 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004155 {
4156# ifdef __BEOS__
4157 beos_cleanup_read_thread();
4158# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004159
Bram Moolenaar071d4272004-06-13 20:20:40 +00004160 if ((pid = fork()) == -1) /* maybe we should use vfork() */
4161 {
4162 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004163 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004164# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004165 || (gui.in_use && show_shell_mess)
4166# endif
4167 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004168 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004169# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004170 if (pty_master_fd >= 0) /* close the pseudo tty */
4171 {
4172 close(pty_master_fd);
4173 close(pty_slave_fd);
4174 }
4175 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004176# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177 {
4178 close(fd_toshell[0]);
4179 close(fd_toshell[1]);
4180 close(fd_fromshell[0]);
4181 close(fd_fromshell[1]);
4182 }
4183 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184 }
4185 else if (pid == 0) /* child */
4186 {
4187 reset_signals(); /* handle signals normally */
4188
4189 if (!show_shell_mess || (options & SHELL_EXPAND))
4190 {
4191 int fd;
4192
4193 /*
4194 * Don't want to show any message from the shell. Can't just
4195 * close stdout and stderr though, because some systems will
4196 * break if you try to write to them after that, so we must
4197 * use dup() to replace them with something else -- webb
4198 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4199 * waiting for input.
4200 */
4201 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4202 fclose(stdin);
4203 fclose(stdout);
4204 fclose(stderr);
4205
4206 /*
4207 * If any of these open()'s and dup()'s fail, we just continue
4208 * anyway. It's not fatal, and on most systems it will make
4209 * no difference at all. On a few it will cause the execvp()
4210 * to exit with a non-zero status even when the completion
4211 * could be done, which is nothing too serious. If the open()
4212 * or dup() failed we'd just do the same thing ourselves
4213 * anyway -- webb
4214 */
4215 if (fd >= 0)
4216 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004217 ignored = dup(fd); /* To replace stdin (fd 0) */
4218 ignored = dup(fd); /* To replace stdout (fd 1) */
4219 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220
4221 /* Don't need this now that we've duplicated it */
4222 close(fd);
4223 }
4224 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004225 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004226# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004227 || gui.in_use
4228# endif
4229 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004230 {
4231
Bram Moolenaardf177f62005-02-22 08:39:57 +00004232# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004233 /* Create our own process group, so that the child and all its
4234 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004235 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004236 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004237 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004238 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004239# if defined(SIGHUP)
4240 /* When doing "!xterm&" and 'shell' is bash: the shell
4241 * will exit and send SIGHUP to all processes in its
4242 * group, killing the just started process. Ignore SIGHUP
4243 * to avoid that. (suggested by Simon Schubert)
4244 */
4245 signal(SIGHUP, SIG_IGN);
4246# endif
4247 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004248# endif
4249# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004250 if (pty_slave_fd >= 0)
4251 {
4252 /* push stream discipline modules */
4253 if (options & SHELL_COOKED)
4254 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004255# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004256 /* Try to become controlling tty (probably doesn't work,
4257 * unless run by root) */
4258 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004259# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004260 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004261# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004262 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004263# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004264 setenv("TERM", "dumb", 1);
4265 sprintf((char *)envbuf, "%ld", Rows);
4266 setenv("ROWS", (char *)envbuf, 1);
4267 sprintf((char *)envbuf, "%ld", Rows);
4268 setenv("LINES", (char *)envbuf, 1);
4269 sprintf((char *)envbuf, "%ld", Columns);
4270 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004271# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004272 /*
4273 * Putenv does not copy the string, it has to remain valid.
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004274 * Use a static array to avoid losing allocated memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004275 */
4276 putenv("TERM=dumb");
4277 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
4278 putenv(envbuf_Rows);
4279 sprintf(envbuf_Rows, "LINES=%ld", Rows);
4280 putenv(envbuf_Rows);
4281 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
4282 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004283# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004284
Bram Moolenaara5792f52005-11-23 21:25:05 +00004285 /*
4286 * stderr is only redirected when using the GUI, so that a
4287 * program like gpg can still access the terminal to get a
4288 * passphrase using stderr.
4289 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004290# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004291 if (pty_master_fd >= 0)
4292 {
4293 close(pty_master_fd); /* close master side of pty */
4294
4295 /* set up stdin/stdout/stderr for the child */
4296 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004297 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004298 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004299 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004300 if (gui.in_use)
4301 {
4302 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004303 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004304 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004305
4306 close(pty_slave_fd); /* has been dupped, close it now */
4307 }
4308 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004309# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004310 {
4311 /* set up stdin for the child */
4312 close(fd_toshell[1]);
4313 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004314 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004315 close(fd_toshell[0]);
4316
4317 /* set up stdout for the child */
4318 close(fd_fromshell[0]);
4319 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004320 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 close(fd_fromshell[1]);
4322
Bram Moolenaara5792f52005-11-23 21:25:05 +00004323# ifdef FEAT_GUI
4324 if (gui.in_use)
4325 {
4326 /* set up stderr for the child */
4327 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004328 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004329 }
4330# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004331 }
4332 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004333
Bram Moolenaar071d4272004-06-13 20:20:40 +00004334 /*
4335 * There is no type cast for the argv, because the type may be
4336 * different on different machines. This may cause a warning
4337 * message with strict compilers, don't worry about it.
4338 * Call _exit() instead of exit() to avoid closing the connection
4339 * to the X server (esp. with GTK, which uses atexit()).
4340 */
4341 execvp(argv[0], argv);
4342 _exit(EXEC_FAILED); /* exec failed, return failure code */
4343 }
4344 else /* parent */
4345 {
4346 /*
4347 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004348 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349 */
4350 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004351 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004352
4353 /*
4354 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004355 * This is also used to pipe stdin/stdout to/from the external
4356 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004358 if ((options & (SHELL_READ|SHELL_WRITE))
4359# ifdef FEAT_GUI
4360 || (gui.in_use && show_shell_mess)
4361# endif
4362 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004363 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004364# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004365 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004366# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004367 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004368# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4370 int ta_len = 0; /* valid bytes in ta_buf[] */
4371 int len;
4372 int p_more_save;
4373 int old_State;
4374 int c;
4375 int toshell_fd;
4376 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004377 garray_T ga;
4378 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004379# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4380 struct timeval start_tv;
4381# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382
Bram Moolenaardf177f62005-02-22 08:39:57 +00004383# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004384 if (pty_master_fd >= 0)
4385 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004386 fromshell_fd = pty_master_fd;
4387 toshell_fd = dup(pty_master_fd);
4388 }
4389 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004390# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004391 {
4392 close(fd_toshell[0]);
4393 close(fd_fromshell[1]);
4394 toshell_fd = fd_toshell[1];
4395 fromshell_fd = fd_fromshell[0];
4396 }
4397
4398 /*
4399 * Write to the child if there are typed characters.
4400 * Read from the child if there are characters available.
4401 * Repeat the reading a few times if more characters are
4402 * available. Need to check for typed keys now and then, but
4403 * not too often (delays when no chars are available).
4404 * This loop is quit if no characters can be read from the pty
4405 * (WaitForChar detected special condition), or there are no
4406 * characters available and the child has exited.
4407 * Only check if the child has exited when there is no more
4408 * output. The child may exit before all the output has
4409 * been printed.
4410 *
4411 * Currently this busy loops!
4412 * This can probably dead-lock when the write blocks!
4413 */
4414 p_more_save = p_more;
4415 p_more = FALSE;
4416 old_State = State;
4417 State = EXTERNCMD; /* don't redraw at window resize */
4418
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004419 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004420 {
4421 /* Fork a process that will write the lines to the
4422 * external program. */
4423 if ((wpid = fork()) == -1)
4424 {
4425 MSG_PUTS(_("\nCannot fork\n"));
4426 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004427 else if (wpid == 0) /* child */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004428 {
4429 linenr_T lnum = curbuf->b_op_start.lnum;
4430 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004431 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004432 size_t l;
4433
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004434 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004435 for (;;)
4436 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004437 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004438 if (l == 0)
4439 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004440 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004441 /* NL -> NUL translation */
4442 len = write(toshell_fd, "", (size_t)1);
4443 else
4444 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004445 char_u *s = vim_strchr(lp + written, NL);
4446
Bram Moolenaar89d40322006-08-29 15:30:07 +00004447 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004448 s == NULL ? l
4449 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004450 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004451 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004452 {
4453 /* Finished a line, add a NL, unless this line
4454 * should not have one. */
4455 if (lnum != curbuf->b_op_end.lnum
4456 || !curbuf->b_p_bin
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004457 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004458 && (lnum !=
4459 curbuf->b_ml.ml_line_count
4460 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004461 ignored = write(toshell_fd, "\n",
4462 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004463 ++lnum;
4464 if (lnum > curbuf->b_op_end.lnum)
4465 {
4466 /* finished all the lines, close pipe */
4467 close(toshell_fd);
4468 toshell_fd = -1;
4469 break;
4470 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004471 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004472 written = 0;
4473 }
4474 else if (len > 0)
4475 written += len;
4476 }
4477 _exit(0);
4478 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004479 else /* parent */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004480 {
4481 close(toshell_fd);
4482 toshell_fd = -1;
4483 }
4484 }
4485
4486 if (options & SHELL_READ)
4487 ga_init2(&ga, 1, BUFLEN);
4488
4489 noread_cnt = 0;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004490# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4491 gettimeofday(&start_tv, NULL);
4492# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004493 for (;;)
4494 {
4495 /*
4496 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004497 * if there are any.
4498 * Don't do this if we are expanding wild cards (would eat
4499 * typeahead).
4500 * Don't do this when filtering and terminal is in cooked
4501 * mode, the shell command will handle the I/O. Avoids
4502 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004503 * Don't get characters when the child has already
4504 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004505 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004506 * while (noread_cnt > 4), avoids that ":r !ls" eats
4507 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004508 */
4509 len = 0;
4510 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004511 && ((options &
4512 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4513 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004514# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004515 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004516# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004517 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004518 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004519 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004520 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004521 if (ta_len == 0)
4522 {
4523 /* Get extra characters when we don't have any.
4524 * Reset the counter and timer. */
4525 noread_cnt = 0;
4526# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4527 gettimeofday(&start_tv, NULL);
4528# endif
4529 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4530 }
4531 if (ta_len > 0 || len > 0)
4532 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004533 /*
4534 * For pipes:
4535 * Check for CTRL-C: send interrupt signal to child.
4536 * Check for CTRL-D: EOF, close pipe to child.
4537 */
4538 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4539 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004540# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004541 /*
4542 * Send SIGINT to the child's group or all
4543 * processes in our group.
4544 */
4545 if (ta_buf[ta_len] == Ctrl_C
4546 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004547 {
4548# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004550# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004552# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004553 if (wpid > 0)
4554 kill(wpid, SIGINT);
4555 }
4556# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557 if (pty_master_fd < 0 && toshell_fd >= 0
4558 && ta_buf[ta_len] == Ctrl_D)
4559 {
4560 close(toshell_fd);
4561 toshell_fd = -1;
4562 }
4563 }
4564
4565 /* replace K_BS by <BS> and K_DEL by <DEL> */
4566 for (i = ta_len; i < ta_len + len; ++i)
4567 {
4568 if (ta_buf[i] == CSI && len - i > 2)
4569 {
4570 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4571 if (c == K_DEL || c == K_KDEL || c == K_BS)
4572 {
4573 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4574 (size_t)(len - i - 2));
4575 if (c == K_DEL || c == K_KDEL)
4576 ta_buf[i] = DEL;
4577 else
4578 ta_buf[i] = Ctrl_H;
4579 len -= 2;
4580 }
4581 }
4582 else if (ta_buf[i] == '\r')
4583 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004584# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004585 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00004586 i += (*mb_ptr2len_len)(ta_buf + i,
4587 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004588# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004589 }
4590
4591 /*
4592 * For pipes: echo the typed characters.
4593 * For a pty this does not seem to work.
4594 */
4595 if (pty_master_fd < 0)
4596 {
4597 for (i = ta_len; i < ta_len + len; ++i)
4598 {
4599 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4600 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004601# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004602 else if (has_mbyte)
4603 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004604 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605
4606 msg_outtrans_len(ta_buf + i, l);
4607 i += l - 1;
4608 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004609# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004610 else
4611 msg_outtrans_len(ta_buf + i, 1);
4612 }
4613 windgoto(msg_row, msg_col);
4614 out_flush();
4615 }
4616
4617 ta_len += len;
4618
4619 /*
4620 * Write the characters to the child, unless EOF has
4621 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004622 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004623 * When writing buffer lines, drop the typed
4624 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004625 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004626 if (options & SHELL_WRITE)
4627 ta_len = 0;
4628 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004629 {
4630 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4631 if (len > 0)
4632 {
4633 ta_len -= len;
4634 mch_memmove(ta_buf, ta_buf + len, ta_len);
4635 }
4636 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004637 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004638 }
4639
Bram Moolenaardf177f62005-02-22 08:39:57 +00004640 if (got_int)
4641 {
4642 /* CTRL-C sends a signal to the child, we ignore it
4643 * ourselves */
4644# ifdef HAVE_SETSID
4645 kill(-pid, SIGINT);
4646# else
4647 kill(0, SIGINT);
4648# endif
4649 if (wpid > 0)
4650 kill(wpid, SIGINT);
4651 got_int = FALSE;
4652 }
4653
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654 /*
4655 * Check if the child has any characters to be printed.
4656 * Read them and write them to our window. Repeat this as
4657 * long as there is something to do, avoid the 10ms wait
4658 * for mch_inchar(), or sending typeahead characters to
4659 * the external process.
4660 * TODO: This should handle escape sequences, compatible
4661 * to some terminal (vt52?).
4662 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004663 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004664 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4665 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004666 len = read_eintr(fromshell_fd, buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004667# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004668 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004669# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004670 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004671# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004672 );
4673 if (len <= 0) /* end of file or error */
4674 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004675
4676 noread_cnt = 0;
4677 if (options & SHELL_READ)
4678 {
4679 /* Do NUL -> NL translation, append NL separated
4680 * lines to the current buffer. */
4681 for (i = 0; i < len; ++i)
4682 {
4683 if (buffer[i] == NL)
4684 append_ga_line(&ga);
4685 else if (buffer[i] == NUL)
4686 ga_append(&ga, NL);
4687 else
4688 ga_append(&ga, buffer[i]);
4689 }
4690 }
4691# ifdef FEAT_MBYTE
4692 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004693 {
4694 int l;
4695
Bram Moolenaardf177f62005-02-22 08:39:57 +00004696 len += buffer_off;
4697 buffer[len] = NUL;
4698
Bram Moolenaar071d4272004-06-13 20:20:40 +00004699 /* Check if the last character in buffer[] is
4700 * incomplete, keep these bytes for the next
4701 * round. */
4702 for (p = buffer; p < buffer + len; p += l)
4703 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004704 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705 if (l == 0)
4706 l = 1; /* NUL byte? */
4707 else if (MB_BYTE2LEN(*p) != l)
4708 break;
4709 }
4710 if (p == buffer) /* no complete character */
4711 {
4712 /* avoid getting stuck at an illegal byte */
4713 if (len >= 12)
4714 ++p;
4715 else
4716 {
4717 buffer_off = len;
4718 continue;
4719 }
4720 }
4721 c = *p;
4722 *p = NUL;
4723 msg_puts(buffer);
4724 if (p < buffer + len)
4725 {
4726 *p = c;
4727 buffer_off = (buffer + len) - p;
4728 mch_memmove(buffer, p, buffer_off);
4729 continue;
4730 }
4731 buffer_off = 0;
4732 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004733# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004734 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735 {
4736 buffer[len] = NUL;
4737 msg_puts(buffer);
4738 }
4739
4740 windgoto(msg_row, msg_col);
4741 cursor_on();
4742 out_flush();
4743 if (got_int)
4744 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004745
4746# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4747 {
4748 struct timeval now_tv;
4749 long msec;
4750
4751 /* Avoid that we keep looping here without
4752 * checking for a CTRL-C for a long time. Don't
4753 * break out too often to avoid losing typeahead. */
4754 gettimeofday(&now_tv, NULL);
4755 msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
4756 + (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
4757 if (msec > 2000)
4758 {
4759 noread_cnt = 5;
4760 break;
4761 }
4762 }
4763# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004764 }
4765
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004766 /* If we already detected the child has finished break the
4767 * loop now. */
4768 if (wait_pid == pid)
4769 break;
4770
Bram Moolenaar071d4272004-06-13 20:20:40 +00004771 /*
4772 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004773 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004774 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004775# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004776 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004777# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004778 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004779# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004780 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4781 || (wait_pid == pid && WIFEXITED(status)))
4782 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004783 /* Don't break the loop yet, try reading more
4784 * characters from "fromshell_fd" first. When using
4785 * pipes there might still be something to read and
4786 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004787 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004788 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004789 else
4790 wait_pid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004791 }
4792finished:
4793 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004794 if (options & SHELL_READ)
4795 {
4796 if (ga.ga_len > 0)
4797 {
4798 append_ga_line(&ga);
4799 /* remember that the NL was missing */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004800 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004801 }
4802 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004803 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004804 ga_clear(&ga);
4805 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004806
Bram Moolenaar071d4272004-06-13 20:20:40 +00004807 /*
4808 * Give all typeahead that wasn't used back to ui_inchar().
4809 */
4810 if (ta_len)
4811 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004812 State = old_State;
4813 if (toshell_fd >= 0)
4814 close(toshell_fd);
4815 close(fromshell_fd);
4816 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004817
4818 /*
4819 * Wait until our child has exited.
4820 * Ignore wait() returning pids of other children and returning
4821 * because of some signal like SIGWINCH.
4822 * Don't wait if wait_pid was already set above, indicating the
4823 * child already exited.
4824 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02004825 if (wait_pid != pid)
4826 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004827
Bram Moolenaar624891f2010-10-13 16:22:09 +02004828# ifdef FEAT_GUI
4829 /* Close slave side of pty. Only do this after the child has
4830 * exited, otherwise the child may hang when it tries to write on
4831 * the pty. */
4832 if (pty_master_fd >= 0)
4833 close(pty_slave_fd);
4834# endif
4835
Bram Moolenaardf177f62005-02-22 08:39:57 +00004836 /* Make sure the child that writes to the external program is
4837 * dead. */
4838 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02004839 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004840 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02004841 wait4pid(wpid, NULL);
4842 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004843
Bram Moolenaar071d4272004-06-13 20:20:40 +00004844 /*
4845 * Set to raw mode right now, otherwise a CTRL-C after
4846 * catch_signals() will kill Vim.
4847 */
4848 if (tmode == TMODE_RAW)
4849 settmode(TMODE_RAW);
4850 did_settmode = TRUE;
4851 set_signals();
4852
4853 if (WIFEXITED(status))
4854 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004855 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004856 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01004857 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004858 {
4859 if (retval == EXEC_FAILED)
4860 {
4861 MSG_PUTS(_("\nCannot execute shell "));
4862 msg_outtrans(p_sh);
4863 msg_putchar('\n');
4864 }
4865 else if (!(options & SHELL_SILENT))
4866 {
4867 MSG_PUTS(_("\nshell returned "));
4868 msg_outnum((long)retval);
4869 msg_putchar('\n');
4870 }
4871 }
4872 }
4873 else
4874 MSG_PUTS(_("\nCommand terminated\n"));
4875 }
4876 }
4877 vim_free(argv);
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004878 vim_free(p_shcf_copy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004879
4880error:
4881 if (!did_settmode)
4882 if (tmode == TMODE_RAW)
4883 settmode(TMODE_RAW); /* set to raw mode */
4884# ifdef FEAT_TITLE
4885 resettitle();
4886# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004887# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4888 restore_clipboard();
4889# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004890 vim_free(newcmd);
4891
4892 return retval;
4893
4894#endif /* USE_SYSTEM */
4895}
4896
4897/*
4898 * Check for CTRL-C typed by reading all available characters.
4899 * In cooked mode we should get SIGINT, no need to check.
4900 */
4901 void
4902mch_breakcheck()
4903{
4904 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4905 fill_input_buf(FALSE);
4906}
4907
4908/*
4909 * Wait "msec" msec until a character is available from the keyboard or from
4910 * inbuf[]. msec == -1 will block forever.
4911 * When a GUI is being used, this will never get called -- webb
4912 */
4913 static int
4914WaitForChar(msec)
4915 long msec;
4916{
4917#ifdef FEAT_MOUSE_GPM
4918 int gpm_process_wanted;
4919#endif
4920#ifdef FEAT_XCLIPBOARD
4921 int rest;
4922#endif
4923 int avail;
4924
4925 if (input_available()) /* something in inbuf[] */
4926 return 1;
4927
4928#if defined(FEAT_MOUSE_DEC)
4929 /* May need to query the mouse position. */
4930 if (WantQueryMouse)
4931 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004932 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4934 }
4935#endif
4936
4937 /*
4938 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4939 * events. This is a bit complicated, because they might both be defined.
4940 */
4941#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4942# ifdef FEAT_XCLIPBOARD
4943 rest = 0;
4944 if (do_xterm_trace())
4945 rest = msec;
4946# endif
4947 do
4948 {
4949# ifdef FEAT_XCLIPBOARD
4950 if (rest != 0)
4951 {
4952 msec = XT_TRACE_DELAY;
4953 if (rest >= 0 && rest < XT_TRACE_DELAY)
4954 msec = rest;
4955 if (rest >= 0)
4956 rest -= msec;
4957 }
4958# endif
4959# ifdef FEAT_MOUSE_GPM
4960 gpm_process_wanted = 0;
4961 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4962# else
4963 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4964# endif
4965 if (!avail)
4966 {
4967 if (input_available())
4968 return 1;
4969# ifdef FEAT_XCLIPBOARD
4970 if (rest == 0 || !do_xterm_trace())
4971# endif
4972 break;
4973 }
4974 }
4975 while (FALSE
4976# ifdef FEAT_MOUSE_GPM
4977 || (gpm_process_wanted && mch_gpm_process() == 0)
4978# endif
4979# ifdef FEAT_XCLIPBOARD
4980 || (!avail && rest != 0)
4981# endif
4982 );
4983
4984#else
4985 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4986#endif
4987 return avail;
4988}
4989
4990/*
4991 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02004992 * "msec" == 0 will check for characters once.
4993 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004994 * When a GUI is being used, this will not be used for input -- webb
4995 * Returns also, when a request from Sniff is waiting -- toni.
4996 * Or when a Linux GPM mouse event is waiting.
4997 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004998#if defined(__BEOS__)
4999 int
5000#else
5001 static int
5002#endif
5003RealWaitForChar(fd, msec, check_for_gpm)
5004 int fd;
5005 long msec;
Bram Moolenaar78a15312009-05-15 19:33:18 +00005006 int *check_for_gpm UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005007{
5008 int ret;
Bram Moolenaar67c53842010-05-22 18:28:27 +02005009#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02005010 int nb_fd = netbeans_filedesc();
Bram Moolenaar67c53842010-05-22 18:28:27 +02005011#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005012#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005013 static int busy = FALSE;
5014
5015 /* May retry getting characters after an event was handled. */
5016# define MAY_LOOP
5017
5018# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5019 /* Remember at what time we started, so that we know how much longer we
5020 * should wait after being interrupted. */
5021# define USE_START_TV
5022 struct timeval start_tv;
5023
5024 if (msec > 0 && (
5025# ifdef FEAT_XCLIPBOARD
5026 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005027# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005028 ||
5029# endif
5030# endif
5031# ifdef USE_XSMP
5032 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005033# ifdef FEAT_MZSCHEME
5034 ||
5035# endif
5036# endif
5037# ifdef FEAT_MZSCHEME
5038 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005039# endif
5040 ))
5041 gettimeofday(&start_tv, NULL);
5042# endif
5043
5044 /* Handle being called recursively. This may happen for the session
5045 * manager stuff, it may save the file, which does a breakcheck. */
5046 if (busy)
5047 return 0;
5048#endif
5049
5050#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00005051 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005052#endif
5053 {
5054#ifdef MAY_LOOP
5055 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005056# ifdef FEAT_MZSCHEME
5057 int mzquantum_used = FALSE;
5058# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005059#endif
5060#ifndef HAVE_SELECT
Bram Moolenaar67c53842010-05-22 18:28:27 +02005061 struct pollfd fds[6];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005062 int nfd;
5063# ifdef FEAT_XCLIPBOARD
5064 int xterm_idx = -1;
5065# endif
5066# ifdef FEAT_MOUSE_GPM
5067 int gpm_idx = -1;
5068# endif
5069# ifdef USE_XSMP
5070 int xsmp_idx = -1;
5071# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005072# ifdef FEAT_NETBEANS_INTG
5073 int nb_idx = -1;
5074# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005075 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005076
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005077# ifdef FEAT_MZSCHEME
5078 mzvim_check_threads();
5079 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5080 {
5081 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
5082 mzquantum_used = TRUE;
5083 }
5084# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005085 fds[0].fd = fd;
5086 fds[0].events = POLLIN;
5087 nfd = 1;
5088
5089# ifdef FEAT_SNIFF
5090# define SNIFF_IDX 1
5091 if (want_sniff_request)
5092 {
5093 fds[SNIFF_IDX].fd = fd_from_sniff;
5094 fds[SNIFF_IDX].events = POLLIN;
5095 nfd++;
5096 }
5097# endif
5098# ifdef FEAT_XCLIPBOARD
5099 if (xterm_Shell != (Widget)0)
5100 {
5101 xterm_idx = nfd;
5102 fds[nfd].fd = ConnectionNumber(xterm_dpy);
5103 fds[nfd].events = POLLIN;
5104 nfd++;
5105 }
5106# endif
5107# ifdef FEAT_MOUSE_GPM
5108 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5109 {
5110 gpm_idx = nfd;
5111 fds[nfd].fd = gpm_fd;
5112 fds[nfd].events = POLLIN;
5113 nfd++;
5114 }
5115# endif
5116# ifdef USE_XSMP
5117 if (xsmp_icefd != -1)
5118 {
5119 xsmp_idx = nfd;
5120 fds[nfd].fd = xsmp_icefd;
5121 fds[nfd].events = POLLIN;
5122 nfd++;
5123 }
5124# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005125#ifdef FEAT_NETBEANS_INTG
5126 if (nb_fd != -1)
5127 {
5128 nb_idx = nfd;
5129 fds[nfd].fd = nb_fd;
5130 fds[nfd].events = POLLIN;
5131 nfd++;
5132 }
5133#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005134
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005135 ret = poll(fds, nfd, towait);
5136# ifdef FEAT_MZSCHEME
5137 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005138 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005139 finished = FALSE;
5140# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005141
5142# ifdef FEAT_SNIFF
5143 if (ret < 0)
5144 sniff_disconnect(1);
5145 else if (want_sniff_request)
5146 {
5147 if (fds[SNIFF_IDX].revents & POLLHUP)
5148 sniff_disconnect(1);
5149 if (fds[SNIFF_IDX].revents & POLLIN)
5150 sniff_request_waiting = 1;
5151 }
5152# endif
5153# ifdef FEAT_XCLIPBOARD
5154 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
5155 {
5156 xterm_update(); /* Maybe we should hand out clipboard */
5157 if (--ret == 0 && !input_available())
5158 /* Try again */
5159 finished = FALSE;
5160 }
5161# endif
5162# ifdef FEAT_MOUSE_GPM
5163 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
5164 {
5165 *check_for_gpm = 1;
5166 }
5167# endif
5168# ifdef USE_XSMP
5169 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
5170 {
5171 if (fds[xsmp_idx].revents & POLLIN)
5172 {
5173 busy = TRUE;
5174 xsmp_handle_requests();
5175 busy = FALSE;
5176 }
5177 else if (fds[xsmp_idx].revents & POLLHUP)
5178 {
5179 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005180 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005181 xsmp_close();
5182 }
5183 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005184 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005185 }
5186# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005187#ifdef FEAT_NETBEANS_INTG
5188 if (ret > 0 && nb_idx != -1 && fds[nb_idx].revents & POLLIN)
5189 {
5190 netbeans_read();
5191 --ret;
5192 }
5193#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005194
5195
5196#else /* HAVE_SELECT */
5197
5198 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005199 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005200 fd_set rfds, efds;
5201 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005202 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005203
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005204# ifdef FEAT_MZSCHEME
5205 mzvim_check_threads();
5206 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5207 {
5208 towait = p_mzq; /* don't wait longer than 'mzquantum' */
5209 mzquantum_used = TRUE;
5210 }
5211# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005212# ifdef __EMX__
5213 /* don't check for incoming chars if not in raw mode, because select()
5214 * always returns TRUE then (in some version of emx.dll) */
5215 if (curr_tmode != TMODE_RAW)
5216 return 0;
5217# endif
5218
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005219 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005220 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005221 tv.tv_sec = towait / 1000;
5222 tv.tv_usec = (towait % 1000) * (1000000/1000);
5223 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005224 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005225 else
5226 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005227
5228 /*
5229 * Select on ready for reading and exceptional condition (end of file).
5230 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005231select_eintr:
5232 FD_ZERO(&rfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005233 FD_ZERO(&efds);
5234 FD_SET(fd, &rfds);
5235# if !defined(__QNX__) && !defined(__CYGWIN32__)
5236 /* For QNX select() always returns 1 if this is set. Why? */
5237 FD_SET(fd, &efds);
5238# endif
5239 maxfd = fd;
5240
5241# ifdef FEAT_SNIFF
5242 if (want_sniff_request)
5243 {
5244 FD_SET(fd_from_sniff, &rfds);
5245 FD_SET(fd_from_sniff, &efds);
5246 if (maxfd < fd_from_sniff)
5247 maxfd = fd_from_sniff;
5248 }
5249# endif
5250# ifdef FEAT_XCLIPBOARD
5251 if (xterm_Shell != (Widget)0)
5252 {
5253 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
5254 if (maxfd < ConnectionNumber(xterm_dpy))
5255 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02005256
5257 /* An event may have already been read but not handled. In
5258 * particulary, XFlush may cause this. */
5259 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005260 }
5261# endif
5262# ifdef FEAT_MOUSE_GPM
5263 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5264 {
5265 FD_SET(gpm_fd, &rfds);
5266 FD_SET(gpm_fd, &efds);
5267 if (maxfd < gpm_fd)
5268 maxfd = gpm_fd;
5269 }
5270# endif
5271# ifdef USE_XSMP
5272 if (xsmp_icefd != -1)
5273 {
5274 FD_SET(xsmp_icefd, &rfds);
5275 FD_SET(xsmp_icefd, &efds);
5276 if (maxfd < xsmp_icefd)
5277 maxfd = xsmp_icefd;
5278 }
5279# endif
Bram Moolenaardd82d692012-08-15 17:26:57 +02005280# ifdef FEAT_NETBEANS_INTG
Bram Moolenaar67c53842010-05-22 18:28:27 +02005281 if (nb_fd != -1)
5282 {
5283 FD_SET(nb_fd, &rfds);
5284 if (maxfd < nb_fd)
5285 maxfd = nb_fd;
5286 }
Bram Moolenaardd82d692012-08-15 17:26:57 +02005287# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288
5289# ifdef OLD_VMS
5290 /* Old VMS as v6.2 and older have broken select(). It waits more than
5291 * required. Should not be used */
5292 ret = 0;
5293# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005294 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
5295# endif
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005296# ifdef EINTR
5297 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005298 {
5299 /* Check whether window has been resized, EINTR may be caused by
5300 * SIGWINCH. */
5301 if (do_resize)
5302 handle_resize();
5303
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005304 /* Interrupted by a signal, need to try again. We ignore msec
5305 * here, because we do want to check even after a timeout if
5306 * characters are available. Needed for reading output of an
5307 * external command after the process has finished. */
5308 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005309 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005310# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00005311# ifdef __TANDEM
5312 if (ret == -1 && errno == ENOTSUP)
5313 {
5314 FD_ZERO(&rfds);
5315 FD_ZERO(&efds);
5316 ret = 0;
5317 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005318# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005319# ifdef FEAT_MZSCHEME
5320 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005321 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005322 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005323# endif
5324
5325# ifdef FEAT_SNIFF
5326 if (ret < 0 )
5327 sniff_disconnect(1);
5328 else if (ret > 0 && want_sniff_request)
5329 {
5330 if (FD_ISSET(fd_from_sniff, &efds))
5331 sniff_disconnect(1);
5332 if (FD_ISSET(fd_from_sniff, &rfds))
5333 sniff_request_waiting = 1;
5334 }
5335# endif
5336# ifdef FEAT_XCLIPBOARD
5337 if (ret > 0 && xterm_Shell != (Widget)0
5338 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
5339 {
5340 xterm_update(); /* Maybe we should hand out clipboard */
5341 /* continue looping when we only got the X event and the input
5342 * buffer is empty */
5343 if (--ret == 0 && !input_available())
5344 {
5345 /* Try again */
5346 finished = FALSE;
5347 }
5348 }
5349# endif
5350# ifdef FEAT_MOUSE_GPM
5351 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
5352 {
5353 if (FD_ISSET(gpm_fd, &efds))
5354 gpm_close();
5355 else if (FD_ISSET(gpm_fd, &rfds))
5356 *check_for_gpm = 1;
5357 }
5358# endif
5359# ifdef USE_XSMP
5360 if (ret > 0 && xsmp_icefd != -1)
5361 {
5362 if (FD_ISSET(xsmp_icefd, &efds))
5363 {
5364 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005365 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005366 xsmp_close();
5367 if (--ret == 0)
5368 finished = FALSE; /* keep going if event was only one */
5369 }
5370 else if (FD_ISSET(xsmp_icefd, &rfds))
5371 {
5372 busy = TRUE;
5373 xsmp_handle_requests();
5374 busy = FALSE;
5375 if (--ret == 0)
5376 finished = FALSE; /* keep going if event was only one */
5377 }
5378 }
5379# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005380#ifdef FEAT_NETBEANS_INTG
5381 if (ret > 0 && nb_fd != -1 && FD_ISSET(nb_fd, &rfds))
5382 {
5383 netbeans_read();
5384 --ret;
5385 }
5386#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005387
5388#endif /* HAVE_SELECT */
5389
5390#ifdef MAY_LOOP
5391 if (finished || msec == 0)
5392 break;
5393
5394 /* We're going to loop around again, find out for how long */
5395 if (msec > 0)
5396 {
5397# ifdef USE_START_TV
5398 struct timeval mtv;
5399
5400 /* Compute remaining wait time. */
5401 gettimeofday(&mtv, NULL);
5402 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
5403 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
5404# else
5405 /* Guess we got interrupted halfway. */
5406 msec = msec / 2;
5407# endif
5408 if (msec <= 0)
5409 break; /* waited long enough */
5410 }
5411#endif
5412 }
5413
5414 return (ret > 0);
5415}
5416
5417#ifndef VMS
5418
5419#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00005420/*
Bram Moolenaar02743632005-07-25 20:42:36 +00005421 * Expand a path into all matching files and/or directories. Handles "*",
5422 * "?", "[a-z]", "**", etc.
5423 * "path" has backslashes before chars that are not to be expanded.
5424 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005425 */
5426 int
5427mch_expandpath(gap, path, flags)
5428 garray_T *gap;
5429 char_u *path;
5430 int flags; /* EW_* flags */
5431{
Bram Moolenaar02743632005-07-25 20:42:36 +00005432 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005433}
5434#endif
5435
5436/*
5437 * mch_expand_wildcards() - this code does wild-card pattern matching using
5438 * the shell
5439 *
5440 * return OK for success, FAIL for error (you may lose some memory) and put
5441 * an error message in *file.
5442 *
5443 * num_pat is number of input patterns
5444 * pat is array of pointers to input patterns
5445 * num_file is pointer to number of matched file names
5446 * file is pointer to array of pointers to matched file names
5447 */
5448
5449#ifndef SEEK_SET
5450# define SEEK_SET 0
5451#endif
5452#ifndef SEEK_END
5453# define SEEK_END 2
5454#endif
5455
Bram Moolenaar5555acc2006-04-07 21:33:12 +00005456#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00005457
Bram Moolenaar071d4272004-06-13 20:20:40 +00005458 int
5459mch_expand_wildcards(num_pat, pat, num_file, file, flags)
5460 int num_pat;
5461 char_u **pat;
5462 int *num_file;
5463 char_u ***file;
5464 int flags; /* EW_* flags */
5465{
5466 int i;
5467 size_t len;
5468 char_u *p;
5469 int dir;
5470#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00005471 /*
5472 * This is the OS/2 implementation.
5473 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005474# define EXPL_ALLOC_INC 16
5475 char_u **expl_files;
5476 size_t files_alloced, files_free;
5477 char_u *buf;
5478 int has_wildcard;
5479
5480 *num_file = 0; /* default: no files found */
5481 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
5482 files_free = EXPL_ALLOC_INC; /* how much space is not used */
5483 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
5484 if (*file == NULL)
5485 return FAIL;
5486
5487 for (; num_pat > 0; num_pat--, pat++)
5488 {
5489 expl_files = NULL;
5490 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
5491 /* expand environment var or home dir */
5492 buf = expand_env_save(*pat);
5493 else
5494 buf = vim_strsave(*pat);
5495 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005496 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005497 if (has_wildcard) /* yes, so expand them */
5498 expl_files = (char_u **)_fnexplode(buf);
5499
5500 /*
5501 * return value of buf if no wildcards left,
5502 * OR if no match AND EW_NOTFOUND is set.
5503 */
5504 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
5505 || (expl_files == NULL && (flags & EW_NOTFOUND)))
5506 { /* simply save the current contents of *buf */
5507 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
5508 if (expl_files != NULL)
5509 {
5510 expl_files[0] = vim_strsave(buf);
5511 expl_files[1] = NULL;
5512 }
5513 }
5514 vim_free(buf);
5515
5516 /*
5517 * Count number of names resulting from expansion,
5518 * At the same time add a backslash to the end of names that happen to
5519 * be directories, and replace slashes with backslashes.
5520 */
5521 if (expl_files)
5522 {
5523 for (i = 0; (p = expl_files[i]) != NULL; i++)
5524 {
5525 dir = mch_isdir(p);
5526 /* If we don't want dirs and this is one, skip it */
5527 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5528 continue;
5529
Bram Moolenaara2031822006-03-07 22:29:51 +00005530 /* Skip files that are not executable if we check for that. */
5531 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
5532 continue;
5533
Bram Moolenaar071d4272004-06-13 20:20:40 +00005534 if (--files_free == 0)
5535 {
5536 /* need more room in table of pointers */
5537 files_alloced += EXPL_ALLOC_INC;
5538 *file = (char_u **)vim_realloc(*file,
5539 sizeof(char_u **) * files_alloced);
5540 if (*file == NULL)
5541 {
5542 EMSG(_(e_outofmem));
5543 *num_file = 0;
5544 return FAIL;
5545 }
5546 files_free = EXPL_ALLOC_INC;
5547 }
5548 slash_adjust(p);
5549 if (dir)
5550 {
5551 /* For a directory we add a '/', unless it's already
5552 * there. */
5553 len = STRLEN(p);
5554 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5555 {
5556 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005557 if (!after_pathsep((*file)[*num_file],
5558 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005559 {
5560 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005561 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005562 }
5563 }
5564 }
5565 else
5566 {
5567 (*file)[*num_file] = vim_strsave(p);
5568 }
5569
5570 /*
5571 * Error message already given by either alloc or vim_strsave.
5572 * Should return FAIL, but returning OK works also.
5573 */
5574 if ((*file)[*num_file] == NULL)
5575 break;
5576 (*num_file)++;
5577 }
5578 _fnexplodefree((char **)expl_files);
5579 }
5580 }
5581 return OK;
5582
5583#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005584 /*
5585 * This is the non-OS/2 implementation (really Unix).
5586 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005587 int j;
5588 char_u *tempname;
5589 char_u *command;
5590 FILE *fd;
5591 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005592#define STYLE_ECHO 0 /* use "echo", the default */
5593#define STYLE_GLOB 1 /* use "glob", for csh */
5594#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5595#define STYLE_PRINT 3 /* use "print -N", for zsh */
5596#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5597 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005598 int shell_style = STYLE_ECHO;
5599 int check_spaces;
5600 static int did_find_nul = FALSE;
5601 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005602 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005603 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005604
5605 *num_file = 0; /* default: no files found */
5606 *file = NULL;
5607
5608 /*
5609 * If there are no wildcards, just copy the names to allocated memory.
5610 * Saves a lot of time, because we don't have to start a new shell.
5611 */
5612 if (!have_wildcard(num_pat, pat))
5613 return save_patterns(num_pat, pat, num_file, file);
5614
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005615# ifdef HAVE_SANDBOX
5616 /* Don't allow any shell command in the sandbox. */
5617 if (sandbox != 0 && check_secure())
5618 return FAIL;
5619# endif
5620
Bram Moolenaar071d4272004-06-13 20:20:40 +00005621 /*
5622 * Don't allow the use of backticks in secure and restricted mode.
5623 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005624 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005625 for (i = 0; i < num_pat; ++i)
5626 if (vim_strchr(pat[i], '`') != NULL
5627 && (check_restricted() || check_secure()))
5628 return FAIL;
5629
5630 /*
5631 * get a name for the temp file
5632 */
5633 if ((tempname = vim_tempname('o')) == NULL)
5634 {
5635 EMSG(_(e_notmp));
5636 return FAIL;
5637 }
5638
5639 /*
5640 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005641 * file.
5642 * STYLE_BT: NL separated
5643 * If expanding `cmd` execute it directly.
5644 * STYLE_GLOB: NUL separated
5645 * If we use *csh, "glob" will work better than "echo".
5646 * STYLE_PRINT: NL or NUL separated
5647 * If we use *zsh, "print -N" will work better than "glob".
5648 * STYLE_VIMGLOB: NL separated
5649 * If we use *sh*, we define "vimglob()".
5650 * STYLE_ECHO: space separated.
5651 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005652 */
5653 if (num_pat == 1 && *pat[0] == '`'
5654 && (len = STRLEN(pat[0])) > 2
5655 && *(pat[0] + len - 1) == '`')
5656 shell_style = STYLE_BT;
5657 else if ((len = STRLEN(p_sh)) >= 3)
5658 {
5659 if (STRCMP(p_sh + len - 3, "csh") == 0)
5660 shell_style = STYLE_GLOB;
5661 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5662 shell_style = STYLE_PRINT;
5663 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005664 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5665 "sh") != NULL)
5666 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005667
Bram Moolenaarc7247912008-01-13 12:54:11 +00005668 /* Compute the length of the command. We need 2 extra bytes: for the
5669 * optional '&' and for the NUL.
5670 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005671 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005672 if (shell_style == STYLE_VIMGLOB)
5673 len += STRLEN(sh_vimglob_func);
5674
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005675 for (i = 0; i < num_pat; ++i)
5676 {
5677 /* Count the length of the patterns in the same way as they are put in
5678 * "command" below. */
5679#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005680 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005681#else
5682 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005683 for (j = 0; pat[i][j] != NUL; ++j)
5684 {
5685 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5686 ++len; /* may add a backslash */
5687 ++len;
5688 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005689#endif
5690 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005691 command = alloc(len);
5692 if (command == NULL)
5693 {
5694 /* out of memory */
5695 vim_free(tempname);
5696 return FAIL;
5697 }
5698
5699 /*
5700 * Build the shell command:
5701 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5702 * recognizes this).
5703 * - Add the shell command to print the expanded names.
5704 * - Add the temp file name.
5705 * - Add the file name patterns.
5706 */
5707 if (shell_style == STYLE_BT)
5708 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005709 /* change `command; command& ` to (command; command ) */
5710 STRCPY(command, "(");
5711 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005712 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005713 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005714 while (p > command && vim_iswhite(*p))
5715 --p;
5716 if (*p == '&') /* remove trailing '&' */
5717 {
5718 ampersent = TRUE;
5719 *p = ' ';
5720 }
5721 STRCAT(command, ">");
5722 }
5723 else
5724 {
5725 if (flags & EW_NOTFOUND)
5726 STRCPY(command, "set nonomatch; ");
5727 else
5728 STRCPY(command, "unset nonomatch; ");
5729 if (shell_style == STYLE_GLOB)
5730 STRCAT(command, "glob >");
5731 else if (shell_style == STYLE_PRINT)
5732 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005733 else if (shell_style == STYLE_VIMGLOB)
5734 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005735 else
5736 STRCAT(command, "echo >");
5737 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005738
Bram Moolenaar071d4272004-06-13 20:20:40 +00005739 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005740
Bram Moolenaar071d4272004-06-13 20:20:40 +00005741 if (shell_style != STYLE_BT)
5742 for (i = 0; i < num_pat; ++i)
5743 {
5744 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005745 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005746 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005747#ifdef USE_SYSTEM
5748 STRCAT(command, " \"");
5749 STRCAT(command, pat[i]);
5750 STRCAT(command, "\"");
5751#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005752 int intick = FALSE;
5753
Bram Moolenaar071d4272004-06-13 20:20:40 +00005754 p = command + STRLEN(command);
5755 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005756 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005757 {
5758 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005759 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005760 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5761 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005762 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005763 * backslash inside backticks, before a special character
5764 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005765 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005766 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5767 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005768 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005769 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005770 }
5771 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005772 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005773 /* Put a backslash before a special character, but not
5774 * when inside ``. */
5775 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005776
5777 /* Copy one character. */
5778 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005779 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005780 *p = NUL;
5781#endif
5782 }
5783 if (flags & EW_SILENT)
5784 show_shell_mess = FALSE;
5785 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00005786 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005787
5788 /*
5789 * Using zsh -G: If a pattern has no matches, it is just deleted from
5790 * the argument list, otherwise zsh gives an error message and doesn't
5791 * expand any other pattern.
5792 */
5793 if (shell_style == STYLE_PRINT)
5794 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5795
5796 /*
5797 * If we use -f then shell variables set in .cshrc won't get expanded.
5798 * vi can do it, so we will too, but it is only necessary if there is a "$"
5799 * in one of the patterns, otherwise we can still use the fast option.
5800 */
5801 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5802 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5803
5804 /*
5805 * execute the shell command
5806 */
5807 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5808
5809 /* When running in the background, give it some time to create the temp
5810 * file, but don't wait for it to finish. */
5811 if (ampersent)
5812 mch_delay(10L, TRUE);
5813
5814 extra_shell_arg = NULL; /* cleanup */
5815 show_shell_mess = TRUE;
5816 vim_free(command);
5817
Bram Moolenaarc7247912008-01-13 12:54:11 +00005818 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005819 {
5820 mch_remove(tempname);
5821 vim_free(tempname);
5822 /*
5823 * With interactive completion, the error message is not printed.
5824 * However with USE_SYSTEM, I don't know how to turn off error messages
5825 * from the shell, so screen may still get messed up -- webb.
5826 */
5827#ifndef USE_SYSTEM
5828 if (!(flags & EW_SILENT))
5829#endif
5830 {
5831 redraw_later_clear(); /* probably messed up screen */
5832 msg_putchar('\n'); /* clear bottom line quickly */
5833 cmdline_row = Rows - 1; /* continue on last line */
5834#ifdef USE_SYSTEM
5835 if (!(flags & EW_SILENT))
5836#endif
5837 {
5838 MSG(_(e_wildexpand));
5839 msg_start(); /* don't overwrite this message */
5840 }
5841 }
5842 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5843 * EW_NOTFOUND is given */
5844 if (shell_style == STYLE_BT)
5845 return FAIL;
5846 goto notfound;
5847 }
5848
5849 /*
5850 * read the names from the file into memory
5851 */
5852 fd = fopen((char *)tempname, READBIN);
5853 if (fd == NULL)
5854 {
5855 /* Something went wrong, perhaps a file name with a special char. */
5856 if (!(flags & EW_SILENT))
5857 {
5858 MSG(_(e_wildexpand));
5859 msg_start(); /* don't overwrite this message */
5860 }
5861 vim_free(tempname);
5862 goto notfound;
5863 }
5864 fseek(fd, 0L, SEEK_END);
5865 len = ftell(fd); /* get size of temp file */
5866 fseek(fd, 0L, SEEK_SET);
5867 buffer = alloc(len + 1);
5868 if (buffer == NULL)
5869 {
5870 /* out of memory */
5871 mch_remove(tempname);
5872 vim_free(tempname);
5873 fclose(fd);
5874 return FAIL;
5875 }
5876 i = fread((char *)buffer, 1, len, fd);
5877 fclose(fd);
5878 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00005879 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005880 {
5881 /* unexpected read error */
5882 EMSG2(_(e_notread), tempname);
5883 vim_free(tempname);
5884 vim_free(buffer);
5885 return FAIL;
5886 }
5887 vim_free(tempname);
5888
Bram Moolenaarc7247912008-01-13 12:54:11 +00005889# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005890 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5891 p = buffer;
5892 for (i = 0; i < len; ++i)
5893 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5894 *p++ = buffer[i];
5895 len = p - buffer;
5896# endif
5897
5898
5899 /* file names are separated with Space */
5900 if (shell_style == STYLE_ECHO)
5901 {
5902 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5903 p = buffer;
5904 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5905 {
5906 while (*p != ' ' && *p != '\n')
5907 ++p;
5908 p = skipwhite(p); /* skip to next entry */
5909 }
5910 }
5911 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005912 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005913 {
5914 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5915 p = buffer;
5916 for (i = 0; *p != NUL; ++i) /* count number of entries */
5917 {
5918 while (*p != '\n' && *p != NUL)
5919 ++p;
5920 if (*p != NUL)
5921 ++p;
5922 p = skipwhite(p); /* skip leading white space */
5923 }
5924 }
5925 /* file names are separated with NUL */
5926 else
5927 {
5928 /*
5929 * Some versions of zsh use spaces instead of NULs to separate
5930 * results. Only do this when there is no NUL before the end of the
5931 * buffer, otherwise we would never be able to use file names with
5932 * embedded spaces when zsh does use NULs.
5933 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5934 * don't check for spaces again.
5935 */
5936 check_spaces = FALSE;
5937 if (shell_style == STYLE_PRINT && !did_find_nul)
5938 {
5939 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02005940 buffer[len] = NUL;
Bram Moolenaar78a15312009-05-15 19:33:18 +00005941 if (len && (int)STRLEN(buffer) < (int)len - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005942 did_find_nul = TRUE;
5943 else
5944 check_spaces = TRUE;
5945 }
5946
5947 /*
5948 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5949 * already is one, for STYLE_GLOB it needs to be added.
5950 */
5951 if (len && buffer[len - 1] == NUL)
5952 --len;
5953 else
5954 buffer[len] = NUL;
5955 i = 0;
5956 for (p = buffer; p < buffer + len; ++p)
5957 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5958 {
5959 ++i;
5960 *p = NUL;
5961 }
5962 if (len)
5963 ++i; /* count last entry */
5964 }
5965 if (i == 0)
5966 {
5967 /*
5968 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5969 * /bin/sh will happily expand it to nothing rather than returning an
5970 * error; and hey, it's good to check anyway -- webb.
5971 */
5972 vim_free(buffer);
5973 goto notfound;
5974 }
5975 *num_file = i;
5976 *file = (char_u **)alloc(sizeof(char_u *) * i);
5977 if (*file == NULL)
5978 {
5979 /* out of memory */
5980 vim_free(buffer);
5981 return FAIL;
5982 }
5983
5984 /*
5985 * Isolate the individual file names.
5986 */
5987 p = buffer;
5988 for (i = 0; i < *num_file; ++i)
5989 {
5990 (*file)[i] = p;
5991 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005992 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
5993 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005994 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00005995 while (!(shell_style == STYLE_ECHO && *p == ' ')
5996 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005997 ++p;
5998 if (p == buffer + len) /* last entry */
5999 *p = NUL;
6000 else
6001 {
6002 *p++ = NUL;
6003 p = skipwhite(p); /* skip to next entry */
6004 }
6005 }
6006 else /* NUL separates */
6007 {
6008 while (*p && p < buffer + len) /* skip entry */
6009 ++p;
6010 ++p; /* skip NUL */
6011 }
6012 }
6013
6014 /*
6015 * Move the file names to allocated memory.
6016 */
6017 for (j = 0, i = 0; i < *num_file; ++i)
6018 {
6019 /* Require the files to exist. Helps when using /bin/sh */
6020 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6021 continue;
6022
6023 /* check if this entry should be included */
6024 dir = (mch_isdir((*file)[i]));
6025 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6026 continue;
6027
Bram Moolenaara2031822006-03-07 22:29:51 +00006028 /* Skip files that are not executable if we check for that. */
6029 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
6030 continue;
6031
Bram Moolenaar071d4272004-06-13 20:20:40 +00006032 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
6033 if (p)
6034 {
6035 STRCPY(p, (*file)[i]);
6036 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00006037 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006038 (*file)[j++] = p;
6039 }
6040 }
6041 vim_free(buffer);
6042 *num_file = j;
6043
6044 if (*num_file == 0) /* rejected all entries */
6045 {
6046 vim_free(*file);
6047 *file = NULL;
6048 goto notfound;
6049 }
6050
6051 return OK;
6052
6053notfound:
6054 if (flags & EW_NOTFOUND)
6055 return save_patterns(num_pat, pat, num_file, file);
6056 return FAIL;
6057
6058#endif /* __EMX__ */
6059}
6060
6061#endif /* VMS */
6062
6063#ifndef __EMX__
6064 static int
6065save_patterns(num_pat, pat, num_file, file)
6066 int num_pat;
6067 char_u **pat;
6068 int *num_file;
6069 char_u ***file;
6070{
6071 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006072 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006073
6074 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
6075 if (*file == NULL)
6076 return FAIL;
6077 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006078 {
6079 s = vim_strsave(pat[i]);
6080 if (s != NULL)
6081 /* Be compatible with expand_filename(): halve the number of
6082 * backslashes. */
6083 backslash_halve(s);
6084 (*file)[i] = s;
6085 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006086 *num_file = num_pat;
6087 return OK;
6088}
6089#endif
6090
6091
6092/*
6093 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
6094 * expand.
6095 */
6096 int
6097mch_has_exp_wildcard(p)
6098 char_u *p;
6099{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006100 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006101 {
6102#ifndef OS2
6103 if (*p == '\\' && p[1] != NUL)
6104 ++p;
6105 else
6106#endif
6107 if (vim_strchr((char_u *)
6108#ifdef VMS
6109 "*?%"
6110#else
6111# ifdef OS2
6112 "*?"
6113# else
6114 "*?[{'"
6115# endif
6116#endif
6117 , *p) != NULL)
6118 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006119 }
6120 return FALSE;
6121}
6122
6123/*
6124 * Return TRUE if the string "p" contains a wildcard.
6125 * Don't recognize '~' at the end as a wildcard.
6126 */
6127 int
6128mch_has_wildcard(p)
6129 char_u *p;
6130{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006131 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006132 {
6133#ifndef OS2
6134 if (*p == '\\' && p[1] != NUL)
6135 ++p;
6136 else
6137#endif
6138 if (vim_strchr((char_u *)
6139#ifdef VMS
6140 "*?%$"
6141#else
6142# ifdef OS2
6143# ifdef VIM_BACKTICK
6144 "*?$`"
6145# else
6146 "*?$"
6147# endif
6148# else
6149 "*?[{`'$"
6150# endif
6151#endif
6152 , *p) != NULL
6153 || (*p == '~' && p[1] != NUL))
6154 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006155 }
6156 return FALSE;
6157}
6158
6159#ifndef __EMX__
6160 static int
6161have_wildcard(num, file)
6162 int num;
6163 char_u **file;
6164{
6165 int i;
6166
6167 for (i = 0; i < num; i++)
6168 if (mch_has_wildcard(file[i]))
6169 return 1;
6170 return 0;
6171}
6172
6173 static int
6174have_dollars(num, file)
6175 int num;
6176 char_u **file;
6177{
6178 int i;
6179
6180 for (i = 0; i < num; i++)
6181 if (vim_strchr(file[i], '$') != NULL)
6182 return TRUE;
6183 return FALSE;
6184}
6185#endif /* ifndef __EMX__ */
6186
6187#ifndef HAVE_RENAME
6188/*
6189 * Scaled-down version of rename(), which is missing in Xenix.
6190 * This version can only move regular files and will fail if the
6191 * destination exists.
6192 */
6193 int
6194mch_rename(src, dest)
6195 const char *src, *dest;
6196{
6197 struct stat st;
6198
6199 if (stat(dest, &st) >= 0) /* fail if destination exists */
6200 return -1;
6201 if (link(src, dest) != 0) /* link file to new name */
6202 return -1;
6203 if (mch_remove(src) == 0) /* delete link to old name */
6204 return 0;
6205 return -1;
6206}
6207#endif /* !HAVE_RENAME */
6208
6209#ifdef FEAT_MOUSE_GPM
6210/*
6211 * Initializes connection with gpm (if it isn't already opened)
6212 * Return 1 if succeeded (or connection already opened), 0 if failed
6213 */
6214 static int
6215gpm_open()
6216{
6217 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
6218
6219 if (!gpm_flag)
6220 {
6221 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
6222 gpm_connect.defaultMask = ~GPM_HARD;
6223 /* Default handling for mouse move*/
6224 gpm_connect.minMod = 0; /* Handle any modifier keys */
6225 gpm_connect.maxMod = 0xffff;
6226 if (Gpm_Open(&gpm_connect, 0) > 0)
6227 {
6228 /* gpm library tries to handling TSTP causes
6229 * problems. Anyways, we close connection to Gpm whenever
6230 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006231 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00006232 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006233# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00006234 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006235# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006236 return 1; /* succeed */
6237 }
6238 if (gpm_fd == -2)
6239 Gpm_Close(); /* We don't want to talk to xterm via gpm */
6240 return 0;
6241 }
6242 return 1; /* already open */
6243}
6244
6245/*
6246 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00006247 */
6248 static void
6249gpm_close()
6250{
6251 if (gpm_flag && gpm_fd >= 0) /* if Open */
6252 Gpm_Close();
6253}
6254
6255/* Reads gpm event and adds special keys to input buf. Returns length of
6256 * generated key sequence.
6257 * This function is made after gui_send_mouse_event
6258 */
6259 static int
6260mch_gpm_process()
6261{
6262 int button;
6263 static Gpm_Event gpm_event;
6264 char_u string[6];
6265 int_u vim_modifiers;
6266 int row,col;
6267 unsigned char buttons_mask;
6268 unsigned char gpm_modifiers;
6269 static unsigned char old_buttons = 0;
6270
6271 Gpm_GetEvent(&gpm_event);
6272
6273#ifdef FEAT_GUI
6274 /* Don't put events in the input queue now. */
6275 if (hold_gui_events)
6276 return 0;
6277#endif
6278
6279 row = gpm_event.y - 1;
6280 col = gpm_event.x - 1;
6281
6282 string[0] = ESC; /* Our termcode */
6283 string[1] = 'M';
6284 string[2] = 'G';
6285 switch (GPM_BARE_EVENTS(gpm_event.type))
6286 {
6287 case GPM_DRAG:
6288 string[3] = MOUSE_DRAG;
6289 break;
6290 case GPM_DOWN:
6291 buttons_mask = gpm_event.buttons & ~old_buttons;
6292 old_buttons = gpm_event.buttons;
6293 switch (buttons_mask)
6294 {
6295 case GPM_B_LEFT:
6296 button = MOUSE_LEFT;
6297 break;
6298 case GPM_B_MIDDLE:
6299 button = MOUSE_MIDDLE;
6300 break;
6301 case GPM_B_RIGHT:
6302 button = MOUSE_RIGHT;
6303 break;
6304 default:
6305 return 0;
6306 /*Don't know what to do. Can more than one button be
6307 * reported in one event? */
6308 }
6309 string[3] = (char_u)(button | 0x20);
6310 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
6311 break;
6312 case GPM_UP:
6313 string[3] = MOUSE_RELEASE;
6314 old_buttons &= ~gpm_event.buttons;
6315 break;
6316 default:
6317 return 0;
6318 }
6319 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
6320 gpm_modifiers = gpm_event.modifiers;
6321 vim_modifiers = 0x0;
6322 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
6323 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
6324 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
6325 */
6326 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
6327 vim_modifiers |= MOUSE_SHIFT;
6328
6329 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
6330 vim_modifiers |= MOUSE_CTRL;
6331 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
6332 vim_modifiers |= MOUSE_ALT;
6333 string[3] |= vim_modifiers;
6334 string[4] = (char_u)(col + ' ' + 1);
6335 string[5] = (char_u)(row + ' ' + 1);
6336 add_to_input_buf(string, 6);
6337 return 6;
6338}
6339#endif /* FEAT_MOUSE_GPM */
6340
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006341#ifdef FEAT_SYSMOUSE
6342/*
6343 * Initialize connection with sysmouse.
6344 * Let virtual console inform us with SIGUSR2 for pending sysmouse
6345 * output, any sysmouse output than will be processed via sig_sysmouse().
6346 * Return OK if succeeded, FAIL if failed.
6347 */
6348 static int
6349sysmouse_open()
6350{
6351 struct mouse_info mouse;
6352
6353 mouse.operation = MOUSE_MODE;
6354 mouse.u.mode.mode = 0;
6355 mouse.u.mode.signal = SIGUSR2;
6356 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
6357 {
6358 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
6359 mouse.operation = MOUSE_SHOW;
6360 ioctl(1, CONS_MOUSECTL, &mouse);
6361 return OK;
6362 }
6363 return FAIL;
6364}
6365
6366/*
6367 * Stop processing SIGUSR2 signals, and also make sure that
6368 * virtual console do not send us any sysmouse related signal.
6369 */
6370 static void
6371sysmouse_close()
6372{
6373 struct mouse_info mouse;
6374
6375 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
6376 mouse.operation = MOUSE_MODE;
6377 mouse.u.mode.mode = 0;
6378 mouse.u.mode.signal = 0;
6379 ioctl(1, CONS_MOUSECTL, &mouse);
6380}
6381
6382/*
6383 * Gets info from sysmouse and adds special keys to input buf.
6384 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006385 static RETSIGTYPE
6386sig_sysmouse SIGDEFARG(sigarg)
6387{
6388 struct mouse_info mouse;
6389 struct video_info video;
6390 char_u string[6];
6391 int row, col;
6392 int button;
6393 int buttons;
6394 static int oldbuttons = 0;
6395
6396#ifdef FEAT_GUI
6397 /* Don't put events in the input queue now. */
6398 if (hold_gui_events)
6399 return;
6400#endif
6401
6402 mouse.operation = MOUSE_GETINFO;
6403 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
6404 && ioctl(1, FBIO_MODEINFO, &video) != -1
6405 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
6406 && video.vi_cheight > 0 && video.vi_cwidth > 0)
6407 {
6408 row = mouse.u.data.y / video.vi_cheight;
6409 col = mouse.u.data.x / video.vi_cwidth;
6410 buttons = mouse.u.data.buttons;
6411 string[0] = ESC; /* Our termcode */
6412 string[1] = 'M';
6413 string[2] = 'S';
6414 if (oldbuttons == buttons && buttons != 0)
6415 {
6416 button = MOUSE_DRAG;
6417 }
6418 else
6419 {
6420 switch (buttons)
6421 {
6422 case 0:
6423 button = MOUSE_RELEASE;
6424 break;
6425 case 1:
6426 button = MOUSE_LEFT;
6427 break;
6428 case 2:
6429 button = MOUSE_MIDDLE;
6430 break;
6431 case 4:
6432 button = MOUSE_RIGHT;
6433 break;
6434 default:
6435 return;
6436 }
6437 oldbuttons = buttons;
6438 }
6439 string[3] = (char_u)(button);
6440 string[4] = (char_u)(col + ' ' + 1);
6441 string[5] = (char_u)(row + ' ' + 1);
6442 add_to_input_buf(string, 6);
6443 }
6444 return;
6445}
6446#endif /* FEAT_SYSMOUSE */
6447
Bram Moolenaar071d4272004-06-13 20:20:40 +00006448#if defined(FEAT_LIBCALL) || defined(PROTO)
6449typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
6450typedef char_u * (*INTPROCSTR)__ARGS((int));
6451typedef int (*STRPROCINT)__ARGS((char_u *));
6452typedef int (*INTPROCINT)__ARGS((int));
6453
6454/*
6455 * Call a DLL routine which takes either a string or int param
6456 * and returns an allocated string.
6457 */
6458 int
6459mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
6460 char_u *libname;
6461 char_u *funcname;
6462 char_u *argstring; /* NULL when using a argint */
6463 int argint;
6464 char_u **string_result;/* NULL when using number_result */
6465 int *number_result;
6466{
6467# if defined(USE_DLOPEN)
6468 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006469 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006470# else
6471 shl_t hinstLib;
6472# endif
6473 STRPROCSTR ProcAdd;
6474 INTPROCSTR ProcAddI;
6475 char_u *retval_str = NULL;
6476 int retval_int = 0;
6477 int success = FALSE;
6478
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006479 /*
6480 * Get a handle to the DLL module.
6481 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006482# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006483 /* First clear any error, it's not cleared by the dlopen() call. */
6484 (void)dlerror();
6485
Bram Moolenaar071d4272004-06-13 20:20:40 +00006486 hinstLib = dlopen((char *)libname, RTLD_LAZY
6487# ifdef RTLD_LOCAL
6488 | RTLD_LOCAL
6489# endif
6490 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006491 if (hinstLib == NULL)
6492 {
6493 /* "dlerr" must be used before dlclose() */
6494 dlerr = (char *)dlerror();
6495 if (dlerr != NULL)
6496 EMSG2(_("dlerror = \"%s\""), dlerr);
6497 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006498# else
6499 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
6500# endif
6501
6502 /* If the handle is valid, try to get the function address. */
6503 if (hinstLib != NULL)
6504 {
6505# ifdef HAVE_SETJMP_H
6506 /*
6507 * Catch a crash when calling the library function. For example when
6508 * using a number where a string pointer is expected.
6509 */
6510 mch_startjmp();
6511 if (SETJMP(lc_jump_env) != 0)
6512 {
6513 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006514# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006515 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006516# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006517 mch_didjmp();
6518 }
6519 else
6520# endif
6521 {
6522 retval_str = NULL;
6523 retval_int = 0;
6524
6525 if (argstring != NULL)
6526 {
6527# if defined(USE_DLOPEN)
6528 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006529 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006530# else
6531 if (shl_findsym(&hinstLib, (const char *)funcname,
6532 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
6533 ProcAdd = NULL;
6534# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006535 if ((success = (ProcAdd != NULL
6536# if defined(USE_DLOPEN)
6537 && dlerr == NULL
6538# endif
6539 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006540 {
6541 if (string_result == NULL)
6542 retval_int = ((STRPROCINT)ProcAdd)(argstring);
6543 else
6544 retval_str = (ProcAdd)(argstring);
6545 }
6546 }
6547 else
6548 {
6549# if defined(USE_DLOPEN)
6550 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006551 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006552# else
6553 if (shl_findsym(&hinstLib, (const char *)funcname,
6554 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
6555 ProcAddI = NULL;
6556# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006557 if ((success = (ProcAddI != NULL
6558# if defined(USE_DLOPEN)
6559 && dlerr == NULL
6560# endif
6561 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006562 {
6563 if (string_result == NULL)
6564 retval_int = ((INTPROCINT)ProcAddI)(argint);
6565 else
6566 retval_str = (ProcAddI)(argint);
6567 }
6568 }
6569
6570 /* Save the string before we free the library. */
6571 /* Assume that a "1" or "-1" result is an illegal pointer. */
6572 if (string_result == NULL)
6573 *number_result = retval_int;
6574 else if (retval_str != NULL
6575 && retval_str != (char_u *)1
6576 && retval_str != (char_u *)-1)
6577 *string_result = vim_strsave(retval_str);
6578 }
6579
6580# ifdef HAVE_SETJMP_H
6581 mch_endjmp();
6582# ifdef SIGHASARG
6583 if (lc_signal != 0)
6584 {
6585 int i;
6586
6587 /* try to find the name of this signal */
6588 for (i = 0; signal_info[i].sig != -1; i++)
6589 if (lc_signal == signal_info[i].sig)
6590 break;
6591 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6592 }
6593# endif
6594# endif
6595
Bram Moolenaar071d4272004-06-13 20:20:40 +00006596# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006597 /* "dlerr" must be used before dlclose() */
6598 if (dlerr != NULL)
6599 EMSG2(_("dlerror = \"%s\""), dlerr);
6600
6601 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006602 (void)dlclose(hinstLib);
6603# else
6604 (void)shl_unload(hinstLib);
6605# endif
6606 }
6607
6608 if (!success)
6609 {
6610 EMSG2(_(e_libcall), funcname);
6611 return FAIL;
6612 }
6613
6614 return OK;
6615}
6616#endif
6617
6618#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6619static int xterm_trace = -1; /* default: disabled */
6620static int xterm_button;
6621
6622/*
6623 * Setup a dummy window for X selections in a terminal.
6624 */
6625 void
6626setup_term_clip()
6627{
6628 int z = 0;
6629 char *strp = "";
6630 Widget AppShell;
6631
6632 if (!x_connect_to_server())
6633 return;
6634
6635 open_app_context();
6636 if (app_context != NULL && xterm_Shell == (Widget)0)
6637 {
6638 int (*oldhandler)();
6639#if defined(HAVE_SETJMP_H)
6640 int (*oldIOhandler)();
6641#endif
6642# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6643 struct timeval start_tv;
6644
6645 if (p_verbose > 0)
6646 gettimeofday(&start_tv, NULL);
6647# endif
6648
6649 /* Ignore X errors while opening the display */
6650 oldhandler = XSetErrorHandler(x_error_check);
6651
6652#if defined(HAVE_SETJMP_H)
6653 /* Ignore X IO errors while opening the display */
6654 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6655 mch_startjmp();
6656 if (SETJMP(lc_jump_env) != 0)
6657 {
6658 mch_didjmp();
6659 xterm_dpy = NULL;
6660 }
6661 else
6662#endif
6663 {
6664 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6665 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6666#if defined(HAVE_SETJMP_H)
6667 mch_endjmp();
6668#endif
6669 }
6670
6671#if defined(HAVE_SETJMP_H)
6672 /* Now handle X IO errors normally. */
6673 (void)XSetIOErrorHandler(oldIOhandler);
6674#endif
6675 /* Now handle X errors normally. */
6676 (void)XSetErrorHandler(oldhandler);
6677
6678 if (xterm_dpy == NULL)
6679 {
6680 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006681 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006682 return;
6683 }
6684
6685 /* Catch terminating error of the X server connection. */
6686 (void)XSetIOErrorHandler(x_IOerror_handler);
6687
6688# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6689 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006690 {
6691 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006692 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006693 verbose_leave();
6694 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006695# endif
6696
6697 /* Create a Shell to make converters work. */
6698 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6699 applicationShellWidgetClass, xterm_dpy,
6700 NULL);
6701 if (AppShell == (Widget)0)
6702 return;
6703 xterm_Shell = XtVaCreatePopupShell("VIM",
6704 topLevelShellWidgetClass, AppShell,
6705 XtNmappedWhenManaged, 0,
6706 XtNwidth, 1,
6707 XtNheight, 1,
6708 NULL);
6709 if (xterm_Shell == (Widget)0)
6710 return;
6711
6712 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02006713 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006714 if (x11_display == NULL)
6715 x11_display = xterm_dpy;
6716
6717 XtRealizeWidget(xterm_Shell);
6718 XSync(xterm_dpy, False);
6719 xterm_update();
6720 }
6721 if (xterm_Shell != (Widget)0)
6722 {
6723 clip_init(TRUE);
6724 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6725 x11_window = (Window)atol(strp);
6726 /* Check if $WINDOWID is valid. */
6727 if (test_x11_window(xterm_dpy) == FAIL)
6728 x11_window = 0;
6729 if (x11_window != 0)
6730 xterm_trace = 0;
6731 }
6732}
6733
6734 void
6735start_xterm_trace(button)
6736 int button;
6737{
6738 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6739 return;
6740 xterm_trace = 1;
6741 xterm_button = button;
6742 do_xterm_trace();
6743}
6744
6745
6746 void
6747stop_xterm_trace()
6748{
6749 if (xterm_trace < 0)
6750 return;
6751 xterm_trace = 0;
6752}
6753
6754/*
6755 * Query the xterm pointer and generate mouse termcodes if necessary
6756 * return TRUE if dragging is active, else FALSE
6757 */
6758 static int
6759do_xterm_trace()
6760{
6761 Window root, child;
6762 int root_x, root_y;
6763 int win_x, win_y;
6764 int row, col;
6765 int_u mask_return;
6766 char_u buf[50];
6767 char_u *strp;
6768 long got_hints;
6769 static char_u *mouse_code;
6770 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6771 static int prev_row = 0, prev_col = 0;
6772 static XSizeHints xterm_hints;
6773
6774 if (xterm_trace <= 0)
6775 return FALSE;
6776
6777 if (xterm_trace == 1)
6778 {
6779 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006780 * have changed recently. */
6781 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6782 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006783 || xterm_hints.width_inc <= 1
6784 || xterm_hints.height_inc <= 1)
6785 {
6786 xterm_trace = -1; /* Not enough data -- disable tracing */
6787 return FALSE;
6788 }
6789
6790 /* Rely on the same mouse code for the duration of this */
6791 mouse_code = find_termcode(mouse_name);
6792 prev_row = mouse_row;
6793 prev_row = mouse_col;
6794 xterm_trace = 2;
6795
6796 /* Find the offset of the chars, there might be a scrollbar on the
6797 * left of the window and/or a menu on the top (eterm etc.) */
6798 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6799 &win_x, &win_y, &mask_return);
6800 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6801 - (xterm_hints.height_inc / 2);
6802 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6803 xterm_hints.y = 2;
6804 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6805 - (xterm_hints.width_inc / 2);
6806 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6807 xterm_hints.x = 2;
6808 return TRUE;
6809 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006810 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006811 {
6812 xterm_trace = 0;
6813 return FALSE;
6814 }
6815
6816 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6817 &win_x, &win_y, &mask_return);
6818
6819 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6820 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6821 if (row == prev_row && col == prev_col)
6822 return TRUE;
6823
6824 STRCPY(buf, mouse_code);
6825 strp = buf + STRLEN(buf);
6826 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6827 *strp++ = (char_u)(col + ' ' + 1);
6828 *strp++ = (char_u)(row + ' ' + 1);
6829 *strp = 0;
6830 add_to_input_buf(buf, STRLEN(buf));
6831
6832 prev_row = row;
6833 prev_col = col;
6834 return TRUE;
6835}
6836
6837# if defined(FEAT_GUI) || defined(PROTO)
6838/*
6839 * Destroy the display, window and app_context. Required for GTK.
6840 */
6841 void
6842clear_xterm_clip()
6843{
6844 if (xterm_Shell != (Widget)0)
6845 {
6846 XtDestroyWidget(xterm_Shell);
6847 xterm_Shell = (Widget)0;
6848 }
6849 if (xterm_dpy != NULL)
6850 {
Bram Moolenaare8208012008-06-20 09:59:25 +00006851# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006852 /* Lesstif and Solaris crash here, lose some memory */
6853 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00006854# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006855 if (x11_display == xterm_dpy)
6856 x11_display = NULL;
6857 xterm_dpy = NULL;
6858 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006859# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006860 if (app_context != (XtAppContext)NULL)
6861 {
6862 /* Lesstif and Solaris crash here, lose some memory */
6863 XtDestroyApplicationContext(app_context);
6864 app_context = (XtAppContext)NULL;
6865 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006866# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006867}
6868# endif
6869
6870/*
6871 * Catch up with any queued X events. This may put keyboard input into the
6872 * input buffer, call resize call-backs, trigger timers etc. If there is
6873 * nothing in the X event queue (& no timers pending), then we return
6874 * immediately.
6875 */
6876 static void
6877xterm_update()
6878{
6879 XEvent event;
6880
6881 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6882 {
6883 XtAppNextEvent(app_context, &event);
6884#ifdef FEAT_CLIENTSERVER
6885 {
6886 XPropertyEvent *e = (XPropertyEvent *)&event;
6887
6888 if (e->type == PropertyNotify && e->window == commWindow
6889 && e->atom == commProperty && e->state == PropertyNewValue)
6890 serverEventProc(xterm_dpy, &event);
6891 }
6892#endif
6893 XtDispatchEvent(&event);
6894 }
6895}
6896
6897 int
6898clip_xterm_own_selection(cbd)
6899 VimClipboard *cbd;
6900{
6901 if (xterm_Shell != (Widget)0)
6902 return clip_x11_own_selection(xterm_Shell, cbd);
6903 return FAIL;
6904}
6905
6906 void
6907clip_xterm_lose_selection(cbd)
6908 VimClipboard *cbd;
6909{
6910 if (xterm_Shell != (Widget)0)
6911 clip_x11_lose_selection(xterm_Shell, cbd);
6912}
6913
6914 void
6915clip_xterm_request_selection(cbd)
6916 VimClipboard *cbd;
6917{
6918 if (xterm_Shell != (Widget)0)
6919 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6920}
6921
6922 void
6923clip_xterm_set_selection(cbd)
6924 VimClipboard *cbd;
6925{
6926 clip_x11_set_selection(cbd);
6927}
6928#endif
6929
6930
6931#if defined(USE_XSMP) || defined(PROTO)
6932/*
6933 * Code for X Session Management Protocol.
6934 */
6935static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6936static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6937static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6938static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6939static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6940
6941
6942# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6943static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6944
6945/*
6946 * This is our chance to ask the user if they want to save,
6947 * or abort the logout
6948 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006949 static void
6950xsmp_handle_interaction(smc_conn, client_data)
6951 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006952 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006953{
6954 cmdmod_T save_cmdmod;
6955 int cancel_shutdown = False;
6956
6957 save_cmdmod = cmdmod;
6958 cmdmod.confirm = TRUE;
6959 if (check_changed_any(FALSE))
6960 /* Mustn't logout */
6961 cancel_shutdown = True;
6962 cmdmod = save_cmdmod;
6963 setcursor(); /* position cursor */
6964 out_flush();
6965
6966 /* Done interaction */
6967 SmcInteractDone(smc_conn, cancel_shutdown);
6968
6969 /* Finish off
6970 * Only end save-yourself here if we're not cancelling shutdown;
6971 * we'll get a cancelled callback later in which we'll end it.
6972 * Hopefully get around glitchy SMs (like GNOME-1)
6973 */
6974 if (!cancel_shutdown)
6975 {
6976 xsmp.save_yourself = False;
6977 SmcSaveYourselfDone(smc_conn, True);
6978 }
6979}
6980# endif
6981
6982/*
6983 * Callback that starts save-yourself.
6984 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006985 static void
6986xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6987 shutdown, interact_style, fast)
6988 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006989 SmPointer client_data UNUSED;
6990 int save_type UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006991 Bool shutdown;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006992 int interact_style UNUSED;
6993 Bool fast UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006994{
6995 /* Handle already being in saveyourself */
6996 if (xsmp.save_yourself)
6997 SmcSaveYourselfDone(smc_conn, True);
6998 xsmp.save_yourself = True;
6999 xsmp.shutdown = shutdown;
7000
7001 /* First up, preserve all files */
7002 out_flush();
7003 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
7004
7005 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007006 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007007
7008# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7009 /* Now see if we can ask about unsaved files */
7010 if (shutdown && !fast && gui.in_use)
7011 /* Need to interact with user, but need SM's permission */
7012 SmcInteractRequest(smc_conn, SmDialogError,
7013 xsmp_handle_interaction, client_data);
7014 else
7015# endif
7016 {
7017 /* Can stop the cycle here */
7018 SmcSaveYourselfDone(smc_conn, True);
7019 xsmp.save_yourself = False;
7020 }
7021}
7022
7023
7024/*
7025 * Callback to warn us of imminent death.
7026 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007027 static void
7028xsmp_die(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007029 SmcConn smc_conn UNUSED;
7030 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007031{
7032 xsmp_close();
7033
7034 /* quit quickly leaving swapfiles for modified buffers behind */
7035 getout_preserve_modified(0);
7036}
7037
7038
7039/*
7040 * Callback to tell us that save-yourself has completed.
7041 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007042 static void
7043xsmp_save_complete(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007044 SmcConn smc_conn UNUSED;
7045 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007046{
7047 xsmp.save_yourself = False;
7048}
7049
7050
7051/*
7052 * Callback to tell us that an instigated shutdown was cancelled
7053 * (maybe even by us)
7054 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007055 static void
7056xsmp_shutdown_cancelled(smc_conn, client_data)
7057 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007058 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007059{
7060 if (xsmp.save_yourself)
7061 SmcSaveYourselfDone(smc_conn, True);
7062 xsmp.save_yourself = False;
7063 xsmp.shutdown = False;
7064}
7065
7066
7067/*
7068 * Callback to tell us that a new ICE connection has been established.
7069 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007070 static void
7071xsmp_ice_connection(iceConn, clientData, opening, watchData)
7072 IceConn iceConn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007073 IcePointer clientData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007074 Bool opening;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007075 IcePointer *watchData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007076{
7077 /* Intercept creation of ICE connection fd */
7078 if (opening)
7079 {
7080 xsmp_icefd = IceConnectionNumber(iceConn);
7081 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7082 }
7083}
7084
7085
7086/* Handle any ICE processing that's required; return FAIL if SM lost */
7087 int
7088xsmp_handle_requests()
7089{
7090 Bool rep;
7091
7092 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7093 == IceProcessMessagesIOError)
7094 {
7095 /* Lost ICE */
7096 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007097 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007098 xsmp_close();
7099 return FAIL;
7100 }
7101 else
7102 return OK;
7103}
7104
7105static int dummy;
7106
7107/* Set up X Session Management Protocol */
7108 void
7109xsmp_init(void)
7110{
7111 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007112 SmcCallbacks smcallbacks;
7113#if 0
7114 SmPropValue smname;
7115 SmProp smnameprop;
7116 SmProp *smprops[1];
7117#endif
7118
7119 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007120 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007121
7122 xsmp.save_yourself = xsmp.shutdown = False;
7123
7124 /* Set up SM callbacks - must have all, even if they're not used */
7125 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
7126 smcallbacks.save_yourself.client_data = NULL;
7127 smcallbacks.die.callback = xsmp_die;
7128 smcallbacks.die.client_data = NULL;
7129 smcallbacks.save_complete.callback = xsmp_save_complete;
7130 smcallbacks.save_complete.client_data = NULL;
7131 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
7132 smcallbacks.shutdown_cancelled.client_data = NULL;
7133
7134 /* Set up a watch on ICE connection creations. The "dummy" argument is
7135 * apparently required for FreeBSD (we get a BUS error when using NULL). */
7136 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
7137 {
7138 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007139 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007140 return;
7141 }
7142
7143 /* Create an SM connection */
7144 xsmp.smcconn = SmcOpenConnection(
7145 NULL,
7146 NULL,
7147 SmProtoMajor,
7148 SmProtoMinor,
7149 SmcSaveYourselfProcMask | SmcDieProcMask
7150 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
7151 &smcallbacks,
7152 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00007153 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007154 sizeof(errorstring),
7155 errorstring);
7156 if (xsmp.smcconn == NULL)
7157 {
7158 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00007159
Bram Moolenaar071d4272004-06-13 20:20:40 +00007160 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007161 {
7162 vim_snprintf(errorreport, sizeof(errorreport),
7163 _("XSMP SmcOpenConnection failed: %s"), errorstring);
7164 verb_msg((char_u *)errorreport);
7165 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007166 return;
7167 }
7168 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
7169
7170#if 0
7171 /* ID ourselves */
7172 smname.value = "vim";
7173 smname.length = 3;
7174 smnameprop.name = "SmProgram";
7175 smnameprop.type = "SmARRAY8";
7176 smnameprop.num_vals = 1;
7177 smnameprop.vals = &smname;
7178
7179 smprops[0] = &smnameprop;
7180 SmcSetProperties(xsmp.smcconn, 1, smprops);
7181#endif
7182}
7183
7184
7185/* Shut down XSMP comms. */
7186 void
7187xsmp_close()
7188{
7189 if (xsmp_icefd != -1)
7190 {
7191 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00007192 if (xsmp.clientid != NULL)
7193 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00007194 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007195 xsmp_icefd = -1;
7196 }
7197}
7198#endif /* USE_XSMP */
7199
7200
7201#ifdef EBCDIC
7202/* Translate character to its CTRL- value */
7203char CtrlTable[] =
7204{
7205/* 00 - 5E */
7206 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7207 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7208 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7209 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7210 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7211 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7212/* ^ */ 0x1E,
7213/* - */ 0x1F,
7214/* 61 - 6C */
7215 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7216/* _ */ 0x1F,
7217/* 6E - 80 */
7218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7219/* a */ 0x01,
7220/* b */ 0x02,
7221/* c */ 0x03,
7222/* d */ 0x37,
7223/* e */ 0x2D,
7224/* f */ 0x2E,
7225/* g */ 0x2F,
7226/* h */ 0x16,
7227/* i */ 0x05,
7228/* 8A - 90 */
7229 0, 0, 0, 0, 0, 0, 0,
7230/* j */ 0x15,
7231/* k */ 0x0B,
7232/* l */ 0x0C,
7233/* m */ 0x0D,
7234/* n */ 0x0E,
7235/* o */ 0x0F,
7236/* p */ 0x10,
7237/* q */ 0x11,
7238/* r */ 0x12,
7239/* 9A - A1 */
7240 0, 0, 0, 0, 0, 0, 0, 0,
7241/* s */ 0x13,
7242/* t */ 0x3C,
7243/* u */ 0x3D,
7244/* v */ 0x32,
7245/* w */ 0x26,
7246/* x */ 0x18,
7247/* y */ 0x19,
7248/* z */ 0x3F,
7249/* AA - AC */
7250 0, 0, 0,
7251/* [ */ 0x27,
7252/* AE - BC */
7253 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7254/* ] */ 0x1D,
7255/* BE - C0 */ 0, 0, 0,
7256/* A */ 0x01,
7257/* B */ 0x02,
7258/* C */ 0x03,
7259/* D */ 0x37,
7260/* E */ 0x2D,
7261/* F */ 0x2E,
7262/* G */ 0x2F,
7263/* H */ 0x16,
7264/* I */ 0x05,
7265/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
7266/* J */ 0x15,
7267/* K */ 0x0B,
7268/* L */ 0x0C,
7269/* M */ 0x0D,
7270/* N */ 0x0E,
7271/* O */ 0x0F,
7272/* P */ 0x10,
7273/* Q */ 0x11,
7274/* R */ 0x12,
7275/* DA - DF */ 0, 0, 0, 0, 0, 0,
7276/* \ */ 0x1C,
7277/* E1 */ 0,
7278/* S */ 0x13,
7279/* T */ 0x3C,
7280/* U */ 0x3D,
7281/* V */ 0x32,
7282/* W */ 0x26,
7283/* X */ 0x18,
7284/* Y */ 0x19,
7285/* Z */ 0x3F,
7286/* EA - FF*/ 0, 0, 0, 0, 0, 0,
7287 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7288};
7289
7290char MetaCharTable[]=
7291{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7292 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
7293 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
7294 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
7295 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
7296};
7297
7298
7299/* TODO: Use characters NOT numbers!!! */
7300char CtrlCharTable[]=
7301{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7302 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
7303 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
7304 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
7305 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
7306};
7307
7308
7309#endif