blob: 4cb1d4a7e7a0eb8d79a599e34dc67ce920e1c9e0 [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 Moolenaara2442432007-04-26 14:26:37 +000064# endif
65#endif
66
Bram Moolenaar071d4272004-06-13 20:20:40 +000067#if defined(HAVE_SELECT)
68extern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
69#endif
70
71#ifdef FEAT_MOUSE_GPM
72# include <gpm.h>
73/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
74 * I just copied relevant defines here. A cleaner solution would be to put gpm
75 * code into separate file and include there linux/keyboard.h
76 */
77/* #include <linux/keyboard.h> */
78# define KG_SHIFT 0
79# define KG_CTRL 2
80# define KG_ALT 3
81# define KG_ALTGR 1
82# define KG_SHIFTL 4
83# define KG_SHIFTR 5
84# define KG_CTRLL 6
85# define KG_CTRLR 7
86# define KG_CAPSSHIFT 8
87
88static void gpm_close __ARGS((void));
89static int gpm_open __ARGS((void));
90static int mch_gpm_process __ARGS((void));
91#endif
92
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000093#ifdef FEAT_SYSMOUSE
94# include <sys/consio.h>
95# include <sys/fbio.h>
96
97static int sysmouse_open __ARGS((void));
98static void sysmouse_close __ARGS((void));
99static RETSIGTYPE sig_sysmouse __ARGS(SIGPROTOARG);
100#endif
101
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102/*
103 * end of autoconf section. To be extended...
104 */
105
106/* Are the following #ifdefs still required? And why? Is that for X11? */
107
108#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
109# ifdef SIGWINCH
110# undef SIGWINCH
111# endif
112# ifdef TIOCGWINSZ
113# undef TIOCGWINSZ
114# endif
115#endif
116
117#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
118# define SIGWINCH SIGWINDOW
119#endif
120
121#ifdef FEAT_X11
122# include <X11/Xlib.h>
123# include <X11/Xutil.h>
124# include <X11/Xatom.h>
125# ifdef FEAT_XCLIPBOARD
126# include <X11/Intrinsic.h>
127# include <X11/Shell.h>
128# include <X11/StringDefs.h>
129static Widget xterm_Shell = (Widget)0;
130static void xterm_update __ARGS((void));
131# endif
132
133# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
134Window x11_window = 0;
135# endif
136Display *x11_display = NULL;
137
138# ifdef FEAT_TITLE
139static int get_x11_windis __ARGS((void));
140static void set_x11_title __ARGS((char_u *));
141static void set_x11_icon __ARGS((char_u *));
142# endif
143#endif
144
145#ifdef FEAT_TITLE
146static int get_x11_title __ARGS((int));
147static int get_x11_icon __ARGS((int));
148
149static char_u *oldtitle = NULL;
150static int did_set_title = FALSE;
151static char_u *oldicon = NULL;
152static int did_set_icon = FALSE;
153#endif
154
155static void may_core_dump __ARGS((void));
156
157static int WaitForChar __ARGS((long));
158#if defined(__BEOS__)
159int RealWaitForChar __ARGS((int, long, int *));
160#else
161static int RealWaitForChar __ARGS((int, long, int *));
162#endif
163
164#ifdef FEAT_XCLIPBOARD
165static int do_xterm_trace __ARGS((void));
Bram Moolenaarcf851ce2005-06-16 21:52:47 +0000166# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167#endif
168
169static void handle_resize __ARGS((void));
170
171#if defined(SIGWINCH)
172static RETSIGTYPE sig_winch __ARGS(SIGPROTOARG);
173#endif
174#if defined(SIGINT)
175static RETSIGTYPE catch_sigint __ARGS(SIGPROTOARG);
176#endif
177#if defined(SIGPWR)
178static RETSIGTYPE catch_sigpwr __ARGS(SIGPROTOARG);
179#endif
180#if defined(SIGALRM) && defined(FEAT_X11) \
181 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
182# define SET_SIG_ALARM
183static RETSIGTYPE sig_alarm __ARGS(SIGPROTOARG);
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000184/* volatile because it is used in signal handler sig_alarm(). */
185static volatile int sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000186#endif
187static RETSIGTYPE deathtrap __ARGS(SIGPROTOARG);
188
Bram Moolenaardf177f62005-02-22 08:39:57 +0000189static void catch_int_signal __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000190static void set_signals __ARGS((void));
191static void catch_signals __ARGS((RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)()));
192#ifndef __EMX__
193static int have_wildcard __ARGS((int, char_u **));
194static int have_dollars __ARGS((int, char_u **));
195#endif
196
Bram Moolenaar071d4272004-06-13 20:20:40 +0000197#ifndef __EMX__
198static int save_patterns __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file));
199#endif
200
201#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000202# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000203#endif
204
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000205/* volatile because it is used in signal handler sig_winch(). */
206static volatile int do_resize = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000207#ifndef __EMX__
208static char_u *extra_shell_arg = NULL;
209static int show_shell_mess = TRUE;
210#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000211/* volatile because it is used in signal handler deathtrap(). */
212static volatile int deadly_signal = 0; /* The signal we caught */
213/* volatile because it is used in signal handler deathtrap(). */
214static volatile int in_mch_delay = FALSE; /* sleeping in mch_delay() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000215
216static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
217
218#ifdef USE_XSMP
219typedef struct
220{
221 SmcConn smcconn; /* The SM connection ID */
222 IceConn iceconn; /* The ICE connection ID */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200223 char *clientid; /* The client ID for the current smc session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000224 Bool save_yourself; /* If we're in the middle of a save_yourself */
225 Bool shutdown; /* If we're in shutdown mode */
226} xsmp_config_T;
227
228static xsmp_config_T xsmp;
229#endif
230
231#ifdef SYS_SIGLIST_DECLARED
232/*
233 * I have seen
234 * extern char *_sys_siglist[NSIG];
235 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
236 * that describe the signals. That is nearly what we want here. But
237 * autoconf does only check for sys_siglist (without the underscore), I
238 * do not want to change everything today.... jw.
239 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.in
240 */
241#endif
242
243static struct signalinfo
244{
245 int sig; /* Signal number, eg. SIGSEGV etc */
246 char *name; /* Signal name (not char_u!). */
247 char deadly; /* Catch as a deadly signal? */
248} signal_info[] =
249{
250#ifdef SIGHUP
251 {SIGHUP, "HUP", TRUE},
252#endif
253#ifdef SIGQUIT
254 {SIGQUIT, "QUIT", TRUE},
255#endif
256#ifdef SIGILL
257 {SIGILL, "ILL", TRUE},
258#endif
259#ifdef SIGTRAP
260 {SIGTRAP, "TRAP", TRUE},
261#endif
262#ifdef SIGABRT
263 {SIGABRT, "ABRT", TRUE},
264#endif
265#ifdef SIGEMT
266 {SIGEMT, "EMT", TRUE},
267#endif
268#ifdef SIGFPE
269 {SIGFPE, "FPE", TRUE},
270#endif
271#ifdef SIGBUS
272 {SIGBUS, "BUS", TRUE},
273#endif
274#ifdef SIGSEGV
275 {SIGSEGV, "SEGV", TRUE},
276#endif
277#ifdef SIGSYS
278 {SIGSYS, "SYS", TRUE},
279#endif
280#ifdef SIGALRM
281 {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
282#endif
283#ifdef SIGTERM
284 {SIGTERM, "TERM", TRUE},
285#endif
286#ifdef SIGVTALRM
287 {SIGVTALRM, "VTALRM", TRUE},
288#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000289#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
290 /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
291 * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000292 {SIGPROF, "PROF", TRUE},
293#endif
294#ifdef SIGXCPU
295 {SIGXCPU, "XCPU", TRUE},
296#endif
297#ifdef SIGXFSZ
298 {SIGXFSZ, "XFSZ", TRUE},
299#endif
300#ifdef SIGUSR1
301 {SIGUSR1, "USR1", TRUE},
302#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000303#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
304 /* Used for sysmouse handling */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000305 {SIGUSR2, "USR2", TRUE},
306#endif
307#ifdef SIGINT
308 {SIGINT, "INT", FALSE},
309#endif
310#ifdef SIGWINCH
311 {SIGWINCH, "WINCH", FALSE},
312#endif
313#ifdef SIGTSTP
314 {SIGTSTP, "TSTP", FALSE},
315#endif
316#ifdef SIGPIPE
317 {SIGPIPE, "PIPE", FALSE},
318#endif
319 {-1, "Unknown!", FALSE}
320};
321
Bram Moolenaar25724922009-07-14 15:38:41 +0000322 int
323mch_chdir(path)
324 char *path;
325{
326 if (p_verbose >= 5)
327 {
328 verbose_enter();
329 smsg((char_u *)"chdir(%s)", path);
330 verbose_leave();
331 }
332# ifdef VMS
333 return chdir(vms_fixfilename(path));
334# else
335 return chdir(path);
336# endif
337}
338
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000339/*
340 * Write s[len] to the screen.
341 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 void
343mch_write(s, len)
344 char_u *s;
345 int len;
346{
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000347 ignored = (int)write(1, (char *)s, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000348 if (p_wd) /* Unix is too fast, slow down a bit more */
349 RealWaitForChar(read_cmd_fd, p_wd, NULL);
350}
351
352/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000353 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354 * Get a characters from the keyboard.
355 * Return the number of characters that are available.
356 * If wtime == 0 do not wait for characters.
357 * If wtime == n wait a short time for characters.
358 * If wtime == -1 wait forever for characters.
359 */
360 int
361mch_inchar(buf, maxlen, wtime, tb_change_cnt)
362 char_u *buf;
363 int maxlen;
364 long wtime; /* don't use "time", MIPS cannot handle it */
365 int tb_change_cnt;
366{
367 int len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368
Bram Moolenaar67c53842010-05-22 18:28:27 +0200369#ifdef FEAT_NETBEANS_INTG
370 /* Process the queued netbeans messages. */
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200371 netbeans_parse_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200372#endif
373
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374 /* Check if window changed size while we were busy, perhaps the ":set
375 * columns=99" command was used. */
376 while (do_resize)
377 handle_resize();
378
379 if (wtime >= 0)
380 {
381 while (WaitForChar(wtime) == 0) /* no character available */
382 {
383 if (!do_resize) /* return if not interrupted by resize */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000384 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000385 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200386#ifdef FEAT_NETBEANS_INTG
387 /* Process the queued netbeans messages. */
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200388 netbeans_parse_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200389#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390 }
391 }
392 else /* wtime == -1 */
393 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000394 /*
395 * If there is no character available within 'updatetime' seconds
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000396 * flush all the swap files to disk.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000397 * Also done when interrupted by SIGWINCH.
398 */
399 if (WaitForChar(p_ut) == 0)
400 {
401#ifdef FEAT_AUTOCMD
Bram Moolenaard35f9712005-12-18 22:02:33 +0000402 if (trigger_cursorhold() && maxlen >= 3
403 && !typebuf_changed(tb_change_cnt))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000404 {
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000405 buf[0] = K_SPECIAL;
406 buf[1] = KS_EXTRA;
407 buf[2] = (int)KE_CURSORHOLD;
408 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000409 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410#endif
Bram Moolenaard4098f52005-06-27 22:37:13 +0000411 before_blocking();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412 }
413 }
414
415 for (;;) /* repeat until we got a character */
416 {
417 while (do_resize) /* window changed size */
418 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200419
420#ifdef FEAT_NETBEANS_INTG
421 /* Process the queued netbeans messages. */
Bram Moolenaarb26e6322010-05-22 21:34:09 +0200422 netbeans_parse_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200423#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424 /*
425 * we want to be interrupted by the winch signal
Bram Moolenaar67c53842010-05-22 18:28:27 +0200426 * or by an event on the monitored file descriptors
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427 */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200428 if (WaitForChar(-1L) == 0)
429 {
430 if (do_resize) /* interrupted by SIGWINCH signal */
431 handle_resize();
432 return 0;
433 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000434
435 /* If input was put directly in typeahead buffer bail out here. */
436 if (typebuf_changed(tb_change_cnt))
437 return 0;
438
439 /*
440 * For some terminals we only get one character at a time.
441 * We want the get all available characters, so we could keep on
442 * trying until none is available
443 * For some other terminals this is quite slow, that's why we don't do
444 * it.
445 */
446 len = read_from_input_buf(buf, (long)maxlen);
447 if (len > 0)
448 {
449#ifdef OS2
450 int i;
451
452 for (i = 0; i < len; i++)
453 if (buf[i] == 0)
454 buf[i] = K_NUL;
455#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000456 return len;
457 }
458 }
459}
460
461 static void
462handle_resize()
463{
464 do_resize = FALSE;
465 shell_resized();
466}
467
468/*
469 * return non-zero if a character is available
470 */
471 int
472mch_char_avail()
473{
474 return WaitForChar(0L);
475}
476
477#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
478# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000479# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000480# endif
481# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
482# include <sys/sysctl.h>
483# endif
484# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
485# include <sys/sysinfo.h>
486# endif
487
488/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000489 * Return total amount of memory available in Kbyte.
490 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000491 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000492 long_u
493mch_total_mem(special)
Bram Moolenaar78a15312009-05-15 19:33:18 +0000494 int special UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000495{
496# ifdef __EMX__
Bram Moolenaar914572a2007-05-01 11:37:47 +0000497 return ulimit(3, 0L) >> 10; /* always 32MB? */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498# else
499 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000500 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000501
502# ifdef HAVE_SYSCTL
503 int mib[2], physmem;
504 size_t len;
505
506 /* BSD way of getting the amount of RAM available. */
507 mib[0] = CTL_HW;
508 mib[1] = HW_USERMEM;
509 len = sizeof(physmem);
510 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
511 mem = (long_u)physmem;
512# endif
513
514# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
515 if (mem == 0)
516 {
517 struct sysinfo sinfo;
518
519 /* Linux way of getting amount of RAM available */
520 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000521 {
522# ifdef HAVE_SYSINFO_MEM_UNIT
523 /* avoid overflow as much as possible */
524 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
525 {
526 sinfo.mem_unit = sinfo.mem_unit >> 1;
527 --shiftright;
528 }
529 mem = sinfo.totalram * sinfo.mem_unit;
530# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000531 mem = sinfo.totalram;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000532# endif
533 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534 }
535# endif
536
537# ifdef HAVE_SYSCONF
538 if (mem == 0)
539 {
540 long pagesize, pagecount;
541
542 /* Solaris way of getting amount of RAM available */
543 pagesize = sysconf(_SC_PAGESIZE);
544 pagecount = sysconf(_SC_PHYS_PAGES);
545 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000546 {
547 /* avoid overflow as much as possible */
548 while (shiftright > 0 && (pagesize & 1) == 0)
549 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000550 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000551 --shiftright;
552 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000554 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 }
556# endif
557
558 /* Return the minimum of the physical memory and the user limit, because
559 * using more than the user limit may cause Vim to be terminated. */
560# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
561 {
562 struct rlimit rlp;
563
564 if (getrlimit(RLIMIT_DATA, &rlp) == 0
565 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
566# ifdef RLIM_INFINITY
567 && rlp.rlim_cur != RLIM_INFINITY
568# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000569 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000571 {
572 mem = (long_u)rlp.rlim_cur;
573 shiftright = 10;
574 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000575 }
576# endif
577
578 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000579 return mem >> shiftright;
580 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000581# endif
582}
583#endif
584
585 void
586mch_delay(msec, ignoreinput)
587 long msec;
588 int ignoreinput;
589{
590 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000591#ifdef FEAT_MZSCHEME
592 long total = msec; /* remember original value */
593#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594
595 if (ignoreinput)
596 {
597 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000598 * here. But we don't want QUIT to kill us (CTRL-\ used in a
599 * shell may produce SIGQUIT). */
600 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000601 old_tmode = curr_tmode;
602 if (curr_tmode == TMODE_RAW)
603 settmode(TMODE_SLEEP);
604
605 /*
606 * Everybody sleeps in a different way...
607 * Prefer nanosleep(), some versions of usleep() can only sleep up to
608 * one second.
609 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000610#ifdef FEAT_MZSCHEME
611 do
612 {
613 /* if total is large enough, wait by portions in p_mzq */
614 if (total > p_mzq)
615 msec = p_mzq;
616 else
617 msec = total;
618 total -= msec;
619#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620#ifdef HAVE_NANOSLEEP
621 {
622 struct timespec ts;
623
624 ts.tv_sec = msec / 1000;
625 ts.tv_nsec = (msec % 1000) * 1000000;
626 (void)nanosleep(&ts, NULL);
627 }
628#else
629# ifdef HAVE_USLEEP
630 while (msec >= 1000)
631 {
632 usleep((unsigned int)(999 * 1000));
633 msec -= 999;
634 }
635 usleep((unsigned int)(msec * 1000));
636# else
637# ifndef HAVE_SELECT
638 poll(NULL, 0, (int)msec);
639# else
640# ifdef __EMX__
641 _sleep2(msec);
642# else
643 {
644 struct timeval tv;
645
646 tv.tv_sec = msec / 1000;
647 tv.tv_usec = (msec % 1000) * 1000;
648 /*
649 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
650 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
651 */
652 select(0, NULL, NULL, NULL, &tv);
653 }
654# endif /* __EMX__ */
655# endif /* HAVE_SELECT */
656# endif /* HAVE_NANOSLEEP */
657#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000658#ifdef FEAT_MZSCHEME
659 }
660 while (total > 0);
661#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000662
663 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000664 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665 }
666 else
667 WaitForChar(msec);
668}
669
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000670#if 0 /* disabled, no longer needed now that regmatch() is not recursive */
671# if defined(HAVE_GETRLIMIT)
672# define HAVE_STACK_LIMIT
673# endif
674#endif
675
676#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000677 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
678# define HAVE_CHECK_STACK_GROWTH
679/*
680 * Support for checking for an almost-out-of-stack-space situation.
681 */
682
683/*
684 * Return a pointer to an item on the stack. Used to find out if the stack
685 * grows up or down.
686 */
687static void check_stack_growth __ARGS((char *p));
688static int stack_grows_downwards;
689
690/*
691 * Find out if the stack grows upwards or downwards.
692 * "p" points to a variable on the stack of the caller.
693 */
694 static void
695check_stack_growth(p)
696 char *p;
697{
698 int i;
699
700 stack_grows_downwards = (p > (char *)&i);
701}
702#endif
703
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000704#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705static char *stack_limit = NULL;
706
707#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
708# include <pthread.h>
709# include <pthread_np.h>
710#endif
711
712/*
713 * Find out until how var the stack can grow without getting into trouble.
714 * Called when starting up and when switching to the signal stack in
715 * deathtrap().
716 */
717 static void
718get_stack_limit()
719{
720 struct rlimit rlp;
721 int i;
722 long lim;
723
724 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
725 * limit doesn't fit in a long (rlim_cur might be "long long"). */
726 if (getrlimit(RLIMIT_STACK, &rlp) == 0
727 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
728# ifdef RLIM_INFINITY
729 && rlp.rlim_cur != RLIM_INFINITY
730# endif
731 )
732 {
733 lim = (long)rlp.rlim_cur;
734#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
735 {
736 pthread_attr_t attr;
737 size_t size;
738
739 /* On FreeBSD the initial thread always has a fixed stack size, no
740 * matter what the limits are set to. Normally it's 1 Mbyte. */
741 pthread_attr_init(&attr);
742 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
743 {
744 pthread_attr_getstacksize(&attr, &size);
745 if (lim > (long)size)
746 lim = (long)size;
747 }
748 pthread_attr_destroy(&attr);
749 }
750#endif
751 if (stack_grows_downwards)
752 {
753 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
754 if (stack_limit >= (char *)&i)
755 /* overflow, set to 1/16 of current stack position */
756 stack_limit = (char *)((long)&i / 16L);
757 }
758 else
759 {
760 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
761 if (stack_limit <= (char *)&i)
762 stack_limit = NULL; /* overflow */
763 }
764 }
765}
766
767/*
768 * Return FAIL when running out of stack space.
769 * "p" must point to any variable local to the caller that's on the stack.
770 */
771 int
772mch_stackcheck(p)
773 char *p;
774{
775 if (stack_limit != NULL)
776 {
777 if (stack_grows_downwards)
778 {
779 if (p < stack_limit)
780 return FAIL;
781 }
782 else if (p > stack_limit)
783 return FAIL;
784 }
785 return OK;
786}
787#endif
788
789#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
790/*
791 * Support for using the signal stack.
792 * This helps when we run out of stack space, which causes a SIGSEGV. The
793 * signal handler then must run on another stack, since the normal stack is
794 * completely full.
795 */
796
797#ifndef SIGSTKSZ
798# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
799#endif
800
801# ifdef HAVE_SIGALTSTACK
802static stack_t sigstk; /* for sigaltstack() */
803# else
804static struct sigstack sigstk; /* for sigstack() */
805# endif
806
807static void init_signal_stack __ARGS((void));
808static char *signal_stack;
809
810 static void
811init_signal_stack()
812{
813 if (signal_stack != NULL)
814 {
815# ifdef HAVE_SIGALTSTACK
Bram Moolenaar1a3d0862007-08-30 09:47:38 +0000816# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
817 || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000818 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
819 * "struct sigaltstack" needs to be declared. */
820 extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
821# endif
822
823# ifdef HAVE_SS_BASE
824 sigstk.ss_base = signal_stack;
825# else
826 sigstk.ss_sp = signal_stack;
827# endif
828 sigstk.ss_size = SIGSTKSZ;
829 sigstk.ss_flags = 0;
830 (void)sigaltstack(&sigstk, NULL);
831# else
832 sigstk.ss_sp = signal_stack;
833 if (stack_grows_downwards)
834 sigstk.ss_sp += SIGSTKSZ - 1;
835 sigstk.ss_onstack = 0;
836 (void)sigstack(&sigstk, NULL);
837# endif
838 }
839}
840#endif
841
842/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000843 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844 * will barf when the second argument to signal() is ``wrong''.
845 * Let me try it with a few tricky defines from my own osdef.h (jw).
846 */
847#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848 static RETSIGTYPE
849sig_winch SIGDEFARG(sigarg)
850{
851 /* this is not required on all systems, but it doesn't hurt anybody */
852 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
853 do_resize = TRUE;
854 SIGRETURN;
855}
856#endif
857
858#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000859 static RETSIGTYPE
860catch_sigint SIGDEFARG(sigarg)
861{
862 /* this is not required on all systems, but it doesn't hurt anybody */
863 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
864 got_int = TRUE;
865 SIGRETURN;
866}
867#endif
868
869#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870 static RETSIGTYPE
871catch_sigpwr SIGDEFARG(sigarg)
872{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000873 /* this is not required on all systems, but it doesn't hurt anybody */
874 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875 /*
876 * I'm not sure we get the SIGPWR signal when the system is really going
877 * down or when the batteries are almost empty. Just preserve the swap
878 * files and don't exit, that can't do any harm.
879 */
880 ml_sync_all(FALSE, FALSE);
881 SIGRETURN;
882}
883#endif
884
885#ifdef SET_SIG_ALARM
886/*
887 * signal function for alarm().
888 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889 static RETSIGTYPE
890sig_alarm SIGDEFARG(sigarg)
891{
892 /* doesn't do anything, just to break a system call */
893 sig_alarm_called = TRUE;
894 SIGRETURN;
895}
896#endif
897
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000898#if (defined(HAVE_SETJMP_H) \
899 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
900 || defined(FEAT_LIBCALL))) \
901 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902/*
903 * A simplistic version of setjmp() that only allows one level of using.
904 * Don't call twice before calling mch_endjmp()!.
905 * Usage:
906 * mch_startjmp();
907 * if (SETJMP(lc_jump_env) != 0)
908 * {
909 * mch_didjmp();
910 * EMSG("crash!");
911 * }
912 * else
913 * {
914 * do_the_work;
915 * mch_endjmp();
916 * }
917 * Note: Can't move SETJMP() here, because a function calling setjmp() must
918 * not return before the saved environment is used.
919 * Returns OK for normal return, FAIL when the protected code caused a
920 * problem and LONGJMP() was used.
921 */
922 void
923mch_startjmp()
924{
925#ifdef SIGHASARG
926 lc_signal = 0;
927#endif
928 lc_active = TRUE;
929}
930
931 void
932mch_endjmp()
933{
934 lc_active = FALSE;
935}
936
937 void
938mch_didjmp()
939{
940# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
941 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
942 * otherwise catching the signal only works once. */
943 init_signal_stack();
944# endif
945}
946#endif
947
948/*
949 * This function handles deadly signals.
950 * It tries to preserve any swap file and exit properly.
951 * (partly from Elvis).
952 */
953 static RETSIGTYPE
954deathtrap SIGDEFARG(sigarg)
955{
956 static int entered = 0; /* count the number of times we got here.
957 Note: when memory has been corrupted
958 this may get an arbitrary value! */
959#ifdef SIGHASARG
960 int i;
961#endif
962
963#if defined(HAVE_SETJMP_H)
964 /*
965 * Catch a crash in protected code.
966 * Restores the environment saved in lc_jump_env, which looks like
967 * SETJMP() returns 1.
968 */
969 if (lc_active)
970 {
971# if defined(SIGHASARG)
972 lc_signal = sigarg;
973# endif
974 lc_active = FALSE; /* don't jump again */
975 LONGJMP(lc_jump_env, 1);
976 /* NOTREACHED */
977 }
978#endif
979
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000980#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000981# ifdef SIGQUIT
982 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
983 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
984 * pressing CTRL-\, but we don't want Vim to exit then. */
985 if (in_mch_delay && sigarg == SIGQUIT)
986 SIGRETURN;
987# endif
988
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000989 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
990 * here. This avoids that a non-reentrant function is interrupted, e.g.,
991 * free(). Calling free() again may then cause a crash. */
992 if (entered == 0
993 && (0
994# ifdef SIGHUP
995 || sigarg == SIGHUP
996# endif
997# ifdef SIGQUIT
998 || sigarg == SIGQUIT
999# endif
1000# ifdef SIGTERM
1001 || sigarg == SIGTERM
1002# endif
1003# ifdef SIGPWR
1004 || sigarg == SIGPWR
1005# endif
1006# ifdef SIGUSR1
1007 || sigarg == SIGUSR1
1008# endif
1009# ifdef SIGUSR2
1010 || sigarg == SIGUSR2
1011# endif
1012 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001013 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001014 SIGRETURN;
1015#endif
1016
Bram Moolenaar071d4272004-06-13 20:20:40 +00001017 /* Remember how often we have been called. */
1018 ++entered;
1019
1020#ifdef FEAT_EVAL
1021 /* Set the v:dying variable. */
1022 set_vim_var_nr(VV_DYING, (long)entered);
1023#endif
1024
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001025#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001026 /* Since we are now using the signal stack, need to reset the stack
1027 * limit. Otherwise using a regexp will fail. */
1028 get_stack_limit();
1029#endif
1030
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001031#if 0
1032 /* This is for opening gdb the moment Vim crashes.
1033 * You need to manually adjust the file name and Vim executable name.
1034 * Suggested by SungHyun Nam. */
1035 {
1036# define VI_GDB_FILE "/tmp/vimgdb"
1037# define VIM_NAME "/usr/bin/vim"
1038 FILE *fp = fopen(VI_GDB_FILE, "w");
1039 if (fp)
1040 {
1041 fprintf(fp,
1042 "file %s\n"
1043 "attach %d\n"
1044 "set height 1000\n"
1045 "bt full\n"
1046 , VIM_NAME, getpid());
1047 fclose(fp);
1048 system("xterm -e gdb -x "VI_GDB_FILE);
1049 unlink(VI_GDB_FILE);
1050 }
1051 }
1052#endif
1053
Bram Moolenaar071d4272004-06-13 20:20:40 +00001054#ifdef SIGHASARG
1055 /* try to find the name of this signal */
1056 for (i = 0; signal_info[i].sig != -1; i++)
1057 if (sigarg == signal_info[i].sig)
1058 break;
1059 deadly_signal = sigarg;
1060#endif
1061
1062 full_screen = FALSE; /* don't write message to the GUI, it might be
1063 * part of the problem... */
1064 /*
1065 * If something goes wrong after entering here, we may get here again.
1066 * When this happens, give a message and try to exit nicely (resetting the
1067 * terminal mode, etc.)
1068 * When this happens twice, just exit, don't even try to give a message,
1069 * stack may be corrupt or something weird.
1070 * When this still happens again (or memory was corrupted in such a way
1071 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1072 */
1073 if (entered >= 3)
1074 {
1075 reset_signals(); /* don't catch any signals anymore */
1076 may_core_dump();
1077 if (entered >= 4)
1078 _exit(8);
1079 exit(7);
1080 }
1081 if (entered == 2)
1082 {
1083 OUT_STR(_("Vim: Double signal, exiting\n"));
1084 out_flush();
1085 getout(1);
1086 }
1087
1088#ifdef SIGHASARG
1089 sprintf((char *)IObuff, _("Vim: Caught deadly signal %s\n"),
1090 signal_info[i].name);
1091#else
1092 sprintf((char *)IObuff, _("Vim: Caught deadly signal\n"));
1093#endif
1094 preserve_exit(); /* preserve files and exit */
1095
Bram Moolenaar009b2592004-10-24 19:18:58 +00001096#ifdef NBDEBUG
1097 reset_signals();
1098 may_core_dump();
1099 abort();
1100#endif
1101
Bram Moolenaar071d4272004-06-13 20:20:40 +00001102 SIGRETURN;
1103}
1104
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001105#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001106/*
1107 * On Solaris with multi-threading, suspending might not work immediately.
1108 * Catch the SIGCONT signal, which will be used as an indication whether the
1109 * suspending has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001110 *
1111 * On Linux, signal is not always handled immediately either.
1112 * See https://bugs.launchpad.net/bugs/291373
1113 *
1114 * volatile because it is used in in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001115 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001116static volatile int sigcont_received;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001117static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1118
1119/*
1120 * signal handler for SIGCONT
1121 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001122 static RETSIGTYPE
1123sigcont_handler SIGDEFARG(sigarg)
1124{
1125 sigcont_received = TRUE;
1126 SIGRETURN;
1127}
1128#endif
1129
1130/*
1131 * If the machine has job control, use it to suspend the program,
1132 * otherwise fake it by starting a new shell.
1133 */
1134 void
1135mch_suspend()
1136{
1137 /* BeOS does have SIGTSTP, but it doesn't work. */
1138#if defined(SIGTSTP) && !defined(__BEOS__)
1139 out_flush(); /* needed to make cursor visible on some systems */
1140 settmode(TMODE_COOK);
1141 out_flush(); /* needed to disable mouse on some systems */
1142
1143# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1144 /* Since we are going to sleep, we can't respond to requests for the X
1145 * selections. Lose them, otherwise other applications will hang. But
1146 * first copy the text to cut buffer 0. */
1147 if (clip_star.owned || clip_plus.owned)
1148 {
1149 x11_export_final_selection();
1150 if (clip_star.owned)
1151 clip_lose_selection(&clip_star);
1152 if (clip_plus.owned)
1153 clip_lose_selection(&clip_plus);
1154 if (x11_display != NULL)
1155 XFlush(x11_display);
1156 }
1157# endif
1158
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001159# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160 sigcont_received = FALSE;
1161# endif
1162 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001163# if defined(_REENTRANT) && defined(SIGCONT)
1164 /*
1165 * Wait for the SIGCONT signal to be handled. It generally happens
1166 * immediately, but somehow not all the time. Do not call pause()
1167 * because there would be race condition which would hang Vim if
1168 * signal happened in between the test of sigcont_received and the
1169 * call to pause(). If signal is not yet received, call sleep(0)
1170 * to just yield CPU. Signal should then be received. If somehow
1171 * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
1172 * further if signal is not received after 1+2+3+4 ms (not expected
1173 * to happen).
1174 */
1175 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001176 long wait_time;
1177 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001178 /* Loop is not entered most of the time */
Bram Moolenaar262735e2009-07-14 10:20:22 +00001179 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001180 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181# endif
1182
1183# ifdef FEAT_TITLE
1184 /*
1185 * Set oldtitle to NULL, so the current title is obtained again.
1186 */
1187 vim_free(oldtitle);
1188 oldtitle = NULL;
1189# endif
1190 settmode(TMODE_RAW);
1191 need_check_timestamps = TRUE;
1192 did_check_timestamps = FALSE;
1193#else
1194 suspend_shell();
1195#endif
1196}
1197
1198 void
1199mch_init()
1200{
1201 Columns = 80;
1202 Rows = 24;
1203
1204 out_flush();
1205 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001206
Bram Moolenaar56718732006-03-15 22:53:57 +00001207#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001208 mac_conv_init();
1209#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001210}
1211
1212 static void
1213set_signals()
1214{
1215#if defined(SIGWINCH)
1216 /*
1217 * WINDOW CHANGE signal is handled with sig_winch().
1218 */
1219 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1220#endif
1221
1222 /*
1223 * We want the STOP signal to work, to make mch_suspend() work.
1224 * For "rvim" the STOP signal is ignored.
1225 */
1226#ifdef SIGTSTP
1227 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1228#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001229#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001230 signal(SIGCONT, sigcont_handler);
1231#endif
1232
1233 /*
1234 * We want to ignore breaking of PIPEs.
1235 */
1236#ifdef SIGPIPE
1237 signal(SIGPIPE, SIG_IGN);
1238#endif
1239
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001241 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242#endif
1243
1244 /*
1245 * Ignore alarm signals (Perl's alarm() generates it).
1246 */
1247#ifdef SIGALRM
1248 signal(SIGALRM, SIG_IGN);
1249#endif
1250
1251 /*
1252 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1253 * work will be lost.
1254 */
1255#ifdef SIGPWR
1256 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1257#endif
1258
1259 /*
1260 * Arrange for other signals to gracefully shutdown Vim.
1261 */
1262 catch_signals(deathtrap, SIG_ERR);
1263
1264#if defined(FEAT_GUI) && defined(SIGHUP)
1265 /*
1266 * When the GUI is running, ignore the hangup signal.
1267 */
1268 if (gui.in_use)
1269 signal(SIGHUP, SIG_IGN);
1270#endif
1271}
1272
Bram Moolenaardf177f62005-02-22 08:39:57 +00001273#if defined(SIGINT) || defined(PROTO)
1274/*
1275 * Catch CTRL-C (only works while in Cooked mode).
1276 */
1277 static void
1278catch_int_signal()
1279{
1280 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1281}
1282#endif
1283
Bram Moolenaar071d4272004-06-13 20:20:40 +00001284 void
1285reset_signals()
1286{
1287 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001288#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001289 /* SIGCONT isn't in the list, because its default action is ignore */
1290 signal(SIGCONT, SIG_DFL);
1291#endif
1292}
1293
1294 static void
1295catch_signals(func_deadly, func_other)
1296 RETSIGTYPE (*func_deadly)();
1297 RETSIGTYPE (*func_other)();
1298{
1299 int i;
1300
1301 for (i = 0; signal_info[i].sig != -1; i++)
1302 if (signal_info[i].deadly)
1303 {
1304#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1305 struct sigaction sa;
1306
1307 /* Setup to use the alternate stack for the signal function. */
1308 sa.sa_handler = func_deadly;
1309 sigemptyset(&sa.sa_mask);
1310# if defined(__linux__) && defined(_REENTRANT)
1311 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1312 * thread handling in combination with using the alternate stack:
1313 * pthread library functions try to use the stack pointer to
1314 * identify the current thread, causing a SEGV signal, which
1315 * recursively calls deathtrap() and hangs. */
1316 sa.sa_flags = 0;
1317# else
1318 sa.sa_flags = SA_ONSTACK;
1319# endif
1320 sigaction(signal_info[i].sig, &sa, NULL);
1321#else
1322# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1323 struct sigvec sv;
1324
1325 /* Setup to use the alternate stack for the signal function. */
1326 sv.sv_handler = func_deadly;
1327 sv.sv_mask = 0;
1328 sv.sv_flags = SV_ONSTACK;
1329 sigvec(signal_info[i].sig, &sv, NULL);
1330# else
1331 signal(signal_info[i].sig, func_deadly);
1332# endif
1333#endif
1334 }
1335 else if (func_other != SIG_ERR)
1336 signal(signal_info[i].sig, func_other);
1337}
1338
1339/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001340 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001341 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1342 * return TRUE
1343 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1344 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001345 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001346 * Returns TRUE when Vim should exit.
1347 */
1348 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001349vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001350 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001351{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001352 static int got_signal = 0;
1353 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001354
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001355 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001356 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001357 case SIGNAL_BLOCK: blocked = TRUE;
1358 break;
1359
1360 case SIGNAL_UNBLOCK: blocked = FALSE;
1361 if (got_signal != 0)
1362 {
1363 kill(getpid(), got_signal);
1364 got_signal = 0;
1365 }
1366 break;
1367
1368 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001369 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001370 got_signal = sig;
1371#ifdef SIGPWR
1372 if (sig != SIGPWR)
1373#endif
1374 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001375 break;
1376 }
1377 return FALSE;
1378}
1379
1380/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001381 * Check_win checks whether we have an interactive stdout.
1382 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001383 int
1384mch_check_win(argc, argv)
Bram Moolenaar78a15312009-05-15 19:33:18 +00001385 int argc UNUSED;
1386 char **argv UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001387{
1388#ifdef OS2
1389 /*
1390 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1391 * name, mostly it's just "vim" and found in the path, which is unusable.
1392 */
1393 if (mch_isFullName(argv[0]))
1394 exe_name = vim_strsave((char_u *)argv[0]);
1395#endif
1396 if (isatty(1))
1397 return OK;
1398 return FAIL;
1399}
1400
1401/*
1402 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1403 */
1404 int
1405mch_input_isatty()
1406{
1407 if (isatty(read_cmd_fd))
1408 return TRUE;
1409 return FALSE;
1410}
1411
1412#ifdef FEAT_X11
1413
1414# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1415 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1416
1417static void xopen_message __ARGS((struct timeval *tvp));
1418
1419/*
1420 * Give a message about the elapsed time for opening the X window.
1421 */
1422 static void
1423xopen_message(tvp)
1424 struct timeval *tvp; /* must contain start time */
1425{
1426 struct timeval end_tv;
1427
1428 /* Compute elapsed time. */
1429 gettimeofday(&end_tv, NULL);
1430 smsg((char_u *)_("Opening the X display took %ld msec"),
1431 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001432 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001433}
1434# endif
1435#endif
1436
1437#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1438/*
1439 * A few functions shared by X11 title and clipboard code.
1440 */
1441static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1442static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1443static int x_connect_to_server __ARGS((void));
1444static int test_x11_window __ARGS((Display *dpy));
1445
1446static int got_x_error = FALSE;
1447
1448/*
1449 * X Error handler, otherwise X just exits! (very rude) -- webb
1450 */
1451 static int
1452x_error_handler(dpy, error_event)
1453 Display *dpy;
1454 XErrorEvent *error_event;
1455{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001456 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001457 STRCAT(IObuff, _("\nVim: Got X error\n"));
1458
1459 /* We cannot print a message and continue, because no X calls are allowed
1460 * here (causes my system to hang). Silently continuing might be an
1461 * alternative... */
1462 preserve_exit(); /* preserve files and exit */
1463
1464 return 0; /* NOTREACHED */
1465}
1466
1467/*
1468 * Another X Error handler, just used to check for errors.
1469 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001470 static int
1471x_error_check(dpy, error_event)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001472 Display *dpy UNUSED;
1473 XErrorEvent *error_event UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001474{
1475 got_x_error = TRUE;
1476 return 0;
1477}
1478
1479#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1480# if defined(HAVE_SETJMP_H)
1481/*
1482 * An X IO Error handler, used to catch error while opening the display.
1483 */
1484static int x_IOerror_check __ARGS((Display *dpy));
1485
Bram Moolenaar071d4272004-06-13 20:20:40 +00001486 static int
1487x_IOerror_check(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001488 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001489{
1490 /* This function should not return, it causes exit(). Longjump instead. */
1491 LONGJMP(lc_jump_env, 1);
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001492# ifdef VMS
1493 return 0; /* avoid the compiler complains about missing return value */
1494# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001495}
1496# endif
1497
1498/*
1499 * An X IO Error handler, used to catch terminal errors.
1500 */
1501static int x_IOerror_handler __ARGS((Display *dpy));
1502
Bram Moolenaar071d4272004-06-13 20:20:40 +00001503 static int
1504x_IOerror_handler(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001505 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001506{
1507 xterm_dpy = NULL;
1508 x11_window = 0;
1509 x11_display = NULL;
1510 xterm_Shell = (Widget)0;
1511
1512 /* This function should not return, it causes exit(). Longjump instead. */
1513 LONGJMP(x_jump_env, 1);
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001514# ifdef VMS
1515 return 0; /* avoid the compiler complains about missing return value */
1516# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001517}
1518#endif
1519
1520/*
1521 * Return TRUE when connection to the X server is desired.
1522 */
1523 static int
1524x_connect_to_server()
1525{
1526 regmatch_T regmatch;
1527
1528#if defined(FEAT_CLIENTSERVER)
1529 if (x_force_connect)
1530 return TRUE;
1531#endif
1532 if (x_no_connect)
1533 return FALSE;
1534
1535 /* Check for a match with "exclude:" from 'clipboard'. */
1536 if (clip_exclude_prog != NULL)
1537 {
1538 regmatch.rm_ic = FALSE; /* Don't ignore case */
1539 regmatch.regprog = clip_exclude_prog;
1540 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1541 return FALSE;
1542 }
1543 return TRUE;
1544}
1545
1546/*
1547 * Test if "dpy" and x11_window are valid by getting the window title.
1548 * I don't actually want it yet, so there may be a simpler call to use, but
1549 * this will cause the error handler x_error_check() to be called if anything
1550 * is wrong, such as the window pointer being invalid (as can happen when the
1551 * user changes his DISPLAY, but not his WINDOWID) -- webb
1552 */
1553 static int
1554test_x11_window(dpy)
1555 Display *dpy;
1556{
1557 int (*old_handler)();
1558 XTextProperty text_prop;
1559
1560 old_handler = XSetErrorHandler(x_error_check);
1561 got_x_error = FALSE;
1562 if (XGetWMName(dpy, x11_window, &text_prop))
1563 XFree((void *)text_prop.value);
1564 XSync(dpy, False);
1565 (void)XSetErrorHandler(old_handler);
1566
1567 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001568 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001569
1570 return (got_x_error ? FAIL : OK);
1571}
1572#endif
1573
1574#ifdef FEAT_TITLE
1575
1576#ifdef FEAT_X11
1577
1578static int get_x11_thing __ARGS((int get_title, int test_only));
1579
1580/*
1581 * try to get x11 window and display
1582 *
1583 * return FAIL for failure, OK otherwise
1584 */
1585 static int
1586get_x11_windis()
1587{
1588 char *winid;
1589 static int result = -1;
1590#define XD_NONE 0 /* x11_display not set here */
1591#define XD_HERE 1 /* x11_display opened here */
1592#define XD_GUI 2 /* x11_display used from gui.dpy */
1593#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1594 static int x11_display_from = XD_NONE;
1595 static int did_set_error_handler = FALSE;
1596
1597 if (!did_set_error_handler)
1598 {
1599 /* X just exits if it finds an error otherwise! */
1600 (void)XSetErrorHandler(x_error_handler);
1601 did_set_error_handler = TRUE;
1602 }
1603
Bram Moolenaar9372a112005-12-06 19:59:18 +00001604#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001605 if (gui.in_use)
1606 {
1607 /*
1608 * If the X11 display was opened here before, for the window where Vim
1609 * was started, close that one now to avoid a memory leak.
1610 */
1611 if (x11_display_from == XD_HERE && x11_display != NULL)
1612 {
1613 XCloseDisplay(x11_display);
1614 x11_display_from = XD_NONE;
1615 }
1616 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1617 {
1618 x11_display_from = XD_GUI;
1619 return OK;
1620 }
1621 x11_display = NULL;
1622 return FAIL;
1623 }
1624 else if (x11_display_from == XD_GUI)
1625 {
1626 /* GUI must have stopped somehow, clear x11_display */
1627 x11_window = 0;
1628 x11_display = NULL;
1629 x11_display_from = XD_NONE;
1630 }
1631#endif
1632
1633 /* When started with the "-X" argument, don't try connecting. */
1634 if (!x_connect_to_server())
1635 return FAIL;
1636
1637 /*
1638 * If WINDOWID not set, should try another method to find out
1639 * what the current window number is. The only code I know for
1640 * this is very complicated.
1641 * We assume that zero is invalid for WINDOWID.
1642 */
1643 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1644 x11_window = (Window)atol(winid);
1645
1646#ifdef FEAT_XCLIPBOARD
1647 if (xterm_dpy != NULL && x11_window != 0)
1648 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001649 /* We may have checked it already, but Gnome terminal can move us to
1650 * another window, so we need to check every time. */
1651 if (x11_display_from != XD_XTERM)
1652 {
1653 /*
1654 * If the X11 display was opened here before, for the window where
1655 * Vim was started, close that one now to avoid a memory leak.
1656 */
1657 if (x11_display_from == XD_HERE && x11_display != NULL)
1658 XCloseDisplay(x11_display);
1659 x11_display = xterm_dpy;
1660 x11_display_from = XD_XTERM;
1661 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001662 if (test_x11_window(x11_display) == FAIL)
1663 {
1664 /* probably bad $WINDOWID */
1665 x11_window = 0;
1666 x11_display = NULL;
1667 x11_display_from = XD_NONE;
1668 return FAIL;
1669 }
1670 return OK;
1671 }
1672#endif
1673
1674 if (x11_window == 0 || x11_display == NULL)
1675 result = -1;
1676
1677 if (result != -1) /* Have already been here and set this */
1678 return result; /* Don't do all these X calls again */
1679
1680 if (x11_window != 0 && x11_display == NULL)
1681 {
1682#ifdef SET_SIG_ALARM
1683 RETSIGTYPE (*sig_save)();
1684#endif
1685#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1686 struct timeval start_tv;
1687
1688 if (p_verbose > 0)
1689 gettimeofday(&start_tv, NULL);
1690#endif
1691
1692#ifdef SET_SIG_ALARM
1693 /*
1694 * Opening the Display may hang if the DISPLAY setting is wrong, or
1695 * the network connection is bad. Set an alarm timer to get out.
1696 */
1697 sig_alarm_called = FALSE;
1698 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1699 (RETSIGTYPE (*)())sig_alarm);
1700 alarm(2);
1701#endif
1702 x11_display = XOpenDisplay(NULL);
1703
1704#ifdef SET_SIG_ALARM
1705 alarm(0);
1706 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1707 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001708 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001709#endif
1710 if (x11_display != NULL)
1711 {
1712# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1713 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001714 {
1715 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001716 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001717 verbose_leave();
1718 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719# endif
1720 if (test_x11_window(x11_display) == FAIL)
1721 {
1722 /* Maybe window id is bad */
1723 x11_window = 0;
1724 XCloseDisplay(x11_display);
1725 x11_display = NULL;
1726 }
1727 else
1728 x11_display_from = XD_HERE;
1729 }
1730 }
1731 if (x11_window == 0 || x11_display == NULL)
1732 return (result = FAIL);
1733 return (result = OK);
1734}
1735
1736/*
1737 * Determine original x11 Window Title
1738 */
1739 static int
1740get_x11_title(test_only)
1741 int test_only;
1742{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001743 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001744}
1745
1746/*
1747 * Determine original x11 Window icon
1748 */
1749 static int
1750get_x11_icon(test_only)
1751 int test_only;
1752{
1753 int retval = FALSE;
1754
1755 retval = get_x11_thing(FALSE, test_only);
1756
1757 /* could not get old icon, use terminal name */
1758 if (oldicon == NULL && !test_only)
1759 {
1760 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001761 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001762 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001763 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001764 }
1765
1766 return retval;
1767}
1768
1769 static int
1770get_x11_thing(get_title, test_only)
1771 int get_title; /* get title string */
1772 int test_only;
1773{
1774 XTextProperty text_prop;
1775 int retval = FALSE;
1776 Status status;
1777
1778 if (get_x11_windis() == OK)
1779 {
1780 /* Get window/icon name if any */
1781 if (get_title)
1782 status = XGetWMName(x11_display, x11_window, &text_prop);
1783 else
1784 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1785
1786 /*
1787 * If terminal is xterm, then x11_window may be a child window of the
1788 * outer xterm window that actually contains the window/icon name, so
1789 * keep traversing up the tree until a window with a title/icon is
1790 * found.
1791 */
1792 /* Previously this was only done for xterm and alikes. I don't see a
1793 * reason why it would fail for other terminal emulators.
1794 * if (term_is_xterm) */
1795 {
1796 Window root;
1797 Window parent;
1798 Window win = x11_window;
1799 Window *children;
1800 unsigned int num_children;
1801
1802 while (!status || text_prop.value == NULL)
1803 {
1804 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1805 &num_children))
1806 break;
1807 if (children)
1808 XFree((void *)children);
1809 if (parent == root || parent == 0)
1810 break;
1811
1812 win = parent;
1813 if (get_title)
1814 status = XGetWMName(x11_display, win, &text_prop);
1815 else
1816 status = XGetWMIconName(x11_display, win, &text_prop);
1817 }
1818 }
1819 if (status && text_prop.value != NULL)
1820 {
1821 retval = TRUE;
1822 if (!test_only)
1823 {
1824#ifdef FEAT_XFONTSET
1825 if (text_prop.encoding == XA_STRING)
1826 {
1827#endif
1828 if (get_title)
1829 oldtitle = vim_strsave((char_u *)text_prop.value);
1830 else
1831 oldicon = vim_strsave((char_u *)text_prop.value);
1832#ifdef FEAT_XFONTSET
1833 }
1834 else
1835 {
1836 char **cl;
1837 Status transform_status;
1838 int n = 0;
1839
1840 transform_status = XmbTextPropertyToTextList(x11_display,
1841 &text_prop,
1842 &cl, &n);
1843 if (transform_status >= Success && n > 0 && cl[0])
1844 {
1845 if (get_title)
1846 oldtitle = vim_strsave((char_u *) cl[0]);
1847 else
1848 oldicon = vim_strsave((char_u *) cl[0]);
1849 XFreeStringList(cl);
1850 }
1851 else
1852 {
1853 if (get_title)
1854 oldtitle = vim_strsave((char_u *)text_prop.value);
1855 else
1856 oldicon = vim_strsave((char_u *)text_prop.value);
1857 }
1858 }
1859#endif
1860 }
1861 XFree((void *)text_prop.value);
1862 }
1863 }
1864 return retval;
1865}
1866
1867/* Are Xutf8 functions available? Avoid error from old compilers. */
1868#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1869# if X_HAVE_UTF8_STRING
1870# define USE_UTF8_STRING
1871# endif
1872#endif
1873
1874/*
1875 * Set x11 Window Title
1876 *
1877 * get_x11_windis() must be called before this and have returned OK
1878 */
1879 static void
1880set_x11_title(title)
1881 char_u *title;
1882{
1883 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1884 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1885 * supported everywhere and STRING doesn't work for multi-byte titles.
1886 */
1887#ifdef USE_UTF8_STRING
1888 if (enc_utf8)
1889 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1890 NULL, NULL, 0, NULL, NULL, NULL);
1891 else
1892#endif
1893 {
1894#if XtSpecificationRelease >= 4
1895# ifdef FEAT_XFONTSET
1896 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1897 NULL, NULL, 0, NULL, NULL, NULL);
1898# else
1899 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001900 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001901
1902 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001903 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904 XSetWMProperties(x11_display, x11_window, &text_prop,
1905 NULL, NULL, 0, NULL, NULL, NULL);
1906# endif
1907#else
1908 XStoreName(x11_display, x11_window, (char *)title);
1909#endif
1910 }
1911 XFlush(x11_display);
1912}
1913
1914/*
1915 * Set x11 Window icon
1916 *
1917 * get_x11_windis() must be called before this and have returned OK
1918 */
1919 static void
1920set_x11_icon(icon)
1921 char_u *icon;
1922{
1923 /* See above for comments about using X*SetWMProperties(). */
1924#ifdef USE_UTF8_STRING
1925 if (enc_utf8)
1926 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1927 NULL, 0, NULL, NULL, NULL);
1928 else
1929#endif
1930 {
1931#if XtSpecificationRelease >= 4
1932# ifdef FEAT_XFONTSET
1933 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1934 NULL, 0, NULL, NULL, NULL);
1935# else
1936 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001937 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001939 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001940 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
1941 NULL, 0, NULL, NULL, NULL);
1942# endif
1943#else
1944 XSetIconName(x11_display, x11_window, (char *)icon);
1945#endif
1946 }
1947 XFlush(x11_display);
1948}
1949
1950#else /* FEAT_X11 */
1951
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 static int
1953get_x11_title(test_only)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001954 int test_only UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955{
1956 return FALSE;
1957}
1958
1959 static int
1960get_x11_icon(test_only)
1961 int test_only;
1962{
1963 if (!test_only)
1964 {
1965 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001966 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001967 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001968 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001969 }
1970 return FALSE;
1971}
1972
1973#endif /* FEAT_X11 */
1974
1975 int
1976mch_can_restore_title()
1977{
1978 return get_x11_title(TRUE);
1979}
1980
1981 int
1982mch_can_restore_icon()
1983{
1984 return get_x11_icon(TRUE);
1985}
1986
1987/*
1988 * Set the window title and icon.
1989 */
1990 void
1991mch_settitle(title, icon)
1992 char_u *title;
1993 char_u *icon;
1994{
1995 int type = 0;
1996 static int recursive = 0;
1997
1998 if (T_NAME == NULL) /* no terminal name (yet) */
1999 return;
2000 if (title == NULL && icon == NULL) /* nothing to do */
2001 return;
2002
2003 /* When one of the X11 functions causes a deadly signal, we get here again
2004 * recursively. Avoid hanging then (something is probably locked). */
2005 if (recursive)
2006 return;
2007 ++recursive;
2008
2009 /*
2010 * if the window ID and the display is known, we may use X11 calls
2011 */
2012#ifdef FEAT_X11
2013 if (get_x11_windis() == OK)
2014 type = 1;
2015#else
2016# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2017 if (gui.in_use)
2018 type = 1;
2019# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002020#endif
2021
2022 /*
2023 * Note: if "t_TS" is set, title is set with escape sequence rather
2024 * than x11 calls, because the x11 calls don't always work
2025 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002026 if ((type || *T_TS != NUL) && title != NULL)
2027 {
2028 if (oldtitle == NULL
2029#ifdef FEAT_GUI
2030 && !gui.in_use
2031#endif
2032 ) /* first call but not in GUI, save title */
2033 (void)get_x11_title(FALSE);
2034
2035 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2036 term_settitle(title);
2037#ifdef FEAT_X11
2038 else
2039# ifdef FEAT_GUI_GTK
2040 if (!gui.in_use) /* don't do this if GTK+ is running */
2041# endif
2042 set_x11_title(title); /* x11 */
2043#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002044#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002045 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2046 else
2047 gui_mch_settitle(title, icon);
2048#endif
2049 did_set_title = TRUE;
2050 }
2051
2052 if ((type || *T_CIS != NUL) && icon != NULL)
2053 {
2054 if (oldicon == NULL
2055#ifdef FEAT_GUI
2056 && !gui.in_use
2057#endif
2058 ) /* first call, save icon */
2059 get_x11_icon(FALSE);
2060
2061 if (*T_CIS != NUL)
2062 {
2063 out_str(T_CIS); /* set icon start */
2064 out_str_nf(icon);
2065 out_str(T_CIE); /* set icon end */
2066 out_flush();
2067 }
2068#ifdef FEAT_X11
2069 else
2070# ifdef FEAT_GUI_GTK
2071 if (!gui.in_use) /* don't do this if GTK+ is running */
2072# endif
2073 set_x11_icon(icon); /* x11 */
2074#endif
2075 did_set_icon = TRUE;
2076 }
2077 --recursive;
2078}
2079
2080/*
2081 * Restore the window/icon title.
2082 * "which" is one of:
2083 * 1 only restore title
2084 * 2 only restore icon
2085 * 3 restore title and icon
2086 */
2087 void
2088mch_restore_title(which)
2089 int which;
2090{
2091 /* only restore the title or icon when it has been set */
2092 mch_settitle(((which & 1) && did_set_title) ?
2093 (oldtitle ? oldtitle : p_titleold) : NULL,
2094 ((which & 2) && did_set_icon) ? oldicon : NULL);
2095}
2096
2097#endif /* FEAT_TITLE */
2098
2099/*
2100 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002101 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002102 */
2103 int
2104vim_is_xterm(name)
2105 char_u *name;
2106{
2107 if (name == NULL)
2108 return FALSE;
2109 return (STRNICMP(name, "xterm", 5) == 0
2110 || STRNICMP(name, "nxterm", 6) == 0
2111 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002112 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002113 || STRNICMP(name, "rxvt", 4) == 0
2114 || STRCMP(name, "builtin_xterm") == 0);
2115}
2116
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002117#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2118/*
2119 * Return TRUE if "name" appears to be that of a terminal
2120 * known to support the xterm-style mouse protocol.
2121 * Relies on term_is_xterm having been set to its correct value.
2122 */
2123 int
2124use_xterm_like_mouse(name)
2125 char_u *name;
2126{
2127 return (name != NULL
2128 && (term_is_xterm || STRNICMP(name, "screen", 6) == 0));
2129}
2130#endif
2131
Bram Moolenaar071d4272004-06-13 20:20:40 +00002132#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2133/*
2134 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2135 * Return 1 for "xterm".
2136 * Return 2 for "xterm2".
2137 */
2138 int
2139use_xterm_mouse()
2140{
2141 if (ttym_flags == TTYM_XTERM2)
2142 return 2;
2143 if (ttym_flags == TTYM_XTERM)
2144 return 1;
2145 return 0;
2146}
2147#endif
2148
2149 int
2150vim_is_iris(name)
2151 char_u *name;
2152{
2153 if (name == NULL)
2154 return FALSE;
2155 return (STRNICMP(name, "iris-ansi", 9) == 0
2156 || STRCMP(name, "builtin_iris-ansi") == 0);
2157}
2158
2159 int
2160vim_is_vt300(name)
2161 char_u *name;
2162{
2163 if (name == NULL)
2164 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002165 /* catch VT100 - VT5xx */
2166 return ((STRNICMP(name, "vt", 2) == 0
2167 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002168 || STRCMP(name, "builtin_vt320") == 0);
2169}
2170
2171/*
2172 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2173 * This should include all windowed terminal emulators.
2174 */
2175 int
2176vim_is_fastterm(name)
2177 char_u *name;
2178{
2179 if (name == NULL)
2180 return FALSE;
2181 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2182 return TRUE;
2183 return ( STRNICMP(name, "hpterm", 6) == 0
2184 || STRNICMP(name, "sun-cmd", 7) == 0
2185 || STRNICMP(name, "screen", 6) == 0
2186 || STRNICMP(name, "dtterm", 6) == 0);
2187}
2188
2189/*
2190 * Insert user name in s[len].
2191 * Return OK if a name found.
2192 */
2193 int
2194mch_get_user_name(s, len)
2195 char_u *s;
2196 int len;
2197{
2198#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002199 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200 return OK;
2201#else
2202 return mch_get_uname(getuid(), s, len);
2203#endif
2204}
2205
2206/*
2207 * Insert user name for "uid" in s[len].
2208 * Return OK if a name found.
2209 */
2210 int
2211mch_get_uname(uid, s, len)
2212 uid_t uid;
2213 char_u *s;
2214 int len;
2215{
2216#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2217 struct passwd *pw;
2218
2219 if ((pw = getpwuid(uid)) != NULL
2220 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2221 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002222 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002223 return OK;
2224 }
2225#endif
2226 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2227 return FAIL; /* a number is not a name */
2228}
2229
2230/*
2231 * Insert host name is s[len].
2232 */
2233
2234#ifdef HAVE_SYS_UTSNAME_H
2235 void
2236mch_get_host_name(s, len)
2237 char_u *s;
2238 int len;
2239{
2240 struct utsname vutsname;
2241
2242 if (uname(&vutsname) < 0)
2243 *s = NUL;
2244 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002245 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002246}
2247#else /* HAVE_SYS_UTSNAME_H */
2248
2249# ifdef HAVE_SYS_SYSTEMINFO_H
2250# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2251# endif
2252
2253 void
2254mch_get_host_name(s, len)
2255 char_u *s;
2256 int len;
2257{
2258# ifdef VAXC
2259 vaxc$gethostname((char *)s, len);
2260# else
2261 gethostname((char *)s, len);
2262# endif
2263 s[len - 1] = NUL; /* make sure it's terminated */
2264}
2265#endif /* HAVE_SYS_UTSNAME_H */
2266
2267/*
2268 * return process ID
2269 */
2270 long
2271mch_get_pid()
2272{
2273 return (long)getpid();
2274}
2275
2276#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2277static char *strerror __ARGS((int));
2278
2279 static char *
2280strerror(err)
2281 int err;
2282{
2283 extern int sys_nerr;
2284 extern char *sys_errlist[];
2285 static char er[20];
2286
2287 if (err > 0 && err < sys_nerr)
2288 return (sys_errlist[err]);
2289 sprintf(er, "Error %d", err);
2290 return er;
2291}
2292#endif
2293
2294/*
2295 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2296 * Return OK for success, FAIL for failure.
2297 */
2298 int
2299mch_dirname(buf, len)
2300 char_u *buf;
2301 int len;
2302{
2303#if defined(USE_GETCWD)
2304 if (getcwd((char *)buf, len) == NULL)
2305 {
2306 STRCPY(buf, strerror(errno));
2307 return FAIL;
2308 }
2309 return OK;
2310#else
2311 return (getwd((char *)buf) != NULL ? OK : FAIL);
2312#endif
2313}
2314
2315#if defined(OS2) || defined(PROTO)
2316/*
2317 * Replace all slashes by backslashes.
2318 * When 'shellslash' set do it the other way around.
2319 */
2320 void
2321slash_adjust(p)
2322 char_u *p;
2323{
2324 while (*p)
2325 {
2326 if (*p == psepcN)
2327 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002328 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002329 }
2330}
2331#endif
2332
2333/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002334 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002335 *
2336 * return FAIL for failure, OK for success
2337 */
2338 int
2339mch_FullName(fname, buf, len, force)
2340 char_u *fname, *buf;
2341 int len;
2342 int force; /* also expand when already absolute path */
2343{
2344 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002345#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002347#endif
2348#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349 int fd = -1;
2350 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002351#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352 char_u olddir[MAXPATHL];
2353 char_u *p;
2354 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002355#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002356 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2357 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002358#endif
2359
Bram Moolenaar38323e42007-03-06 19:22:53 +00002360#ifdef VMS
2361 fname = vms_fixfilename(fname);
2362#endif
2363
Bram Moolenaara2442432007-04-26 14:26:37 +00002364#ifdef __CYGWIN__
2365 /*
2366 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2367 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002368# if CYGWIN_VERSION_DLL_MAJOR >= 1007
2369 cygwin_conv_path(CCP_WIN_A_TO_POSIX, fname, posix_fname, MAXPATHL);
2370# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002371 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002372# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002373 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002374#endif
2375
Bram Moolenaar071d4272004-06-13 20:20:40 +00002376 /* expand it if forced or not an absolute path */
2377 if (force || !mch_isFullName(fname))
2378 {
2379 /*
2380 * If the file name has a path, change to that directory for a moment,
2381 * and then do the getwd() (and get back to where we were).
2382 * This will get the correct path name with "../" things.
2383 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002384#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 only_drive = 0;
2386 if (((p = vim_strrchr(fname, '/')) != NULL)
2387 || ((p = vim_strrchr(fname, '\\')) != NULL)
2388 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002389#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002390 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002391#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002392 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002393#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002394 /*
2395 * Use fchdir() if possible, it's said to be faster and more
2396 * reliable. But on SunOS 4 it might not work. Check this by
2397 * doing a fchdir() right now.
2398 */
2399 if (!dont_fchdir)
2400 {
2401 fd = open(".", O_RDONLY | O_EXTRA, 0);
2402 if (fd >= 0 && fchdir(fd) < 0)
2403 {
2404 close(fd);
2405 fd = -1;
2406 dont_fchdir = TRUE; /* don't try again */
2407 }
2408 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002409#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002410
2411 /* Only change directory when we are sure we can return to where
2412 * we are now. After doing "su" chdir(".") might not work. */
2413 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002414#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002415 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002416#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002417 (mch_dirname(olddir, MAXPATHL) == FAIL
2418 || mch_chdir((char *)olddir) != 0))
2419 {
2420 p = NULL; /* can't get current dir: don't chdir */
2421 retval = FAIL;
2422 }
2423 else
2424 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002425#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002426 /*
2427 * compensate for case where ':' from "D:" was the only
2428 * path separator detected in the file name; the _next_
2429 * character has to be removed, and then restored later.
2430 */
2431 if (only_drive)
2432 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002433#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434 /* The directory is copied into buf[], to be able to remove
2435 * the file name without changing it (could be a string in
2436 * read-only memory) */
2437 if (p - fname >= len)
2438 retval = FAIL;
2439 else
2440 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002441 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002442 if (mch_chdir((char *)buf))
2443 retval = FAIL;
2444 else
2445 fname = p + 1;
2446 *buf = NUL;
2447 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002448#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002449 if (only_drive)
2450 {
2451 p--;
2452 if (retval != FAIL)
2453 fname--;
2454 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002455#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 }
2457 }
2458 if (mch_dirname(buf, len) == FAIL)
2459 {
2460 retval = FAIL;
2461 *buf = NUL;
2462 }
2463 if (p != NULL)
2464 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002465#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002466 if (fd >= 0)
2467 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002468 if (p_verbose >= 5)
2469 {
2470 verbose_enter();
2471 MSG("fchdir() to previous dir");
2472 verbose_leave();
2473 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 l = fchdir(fd);
2475 close(fd);
2476 }
2477 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002478#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002479 l = mch_chdir((char *)olddir);
2480 if (l != 0)
2481 EMSG(_(e_prev_dir));
2482 }
2483
2484 l = STRLEN(buf);
2485 if (l >= len)
2486 retval = FAIL;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002487#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002488 else
2489 {
2490 if (l > 0 && buf[l - 1] != '/' && *fname != NUL
2491 && STRCMP(fname, ".") != 0)
2492 STRCAT(buf, "/");
2493 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002494#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002495 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002496
Bram Moolenaar071d4272004-06-13 20:20:40 +00002497 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002498 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002499 return FAIL;
2500
2501 /* Do not append ".", "/dir/." is equal to "/dir". */
2502 if (STRCMP(fname, ".") != 0)
2503 STRCAT(buf, fname);
2504
2505 return OK;
2506}
2507
2508/*
2509 * Return TRUE if "fname" does not depend on the current directory.
2510 */
2511 int
2512mch_isFullName(fname)
2513 char_u *fname;
2514{
2515#ifdef __EMX__
2516 return _fnisabs(fname);
2517#else
2518# ifdef VMS
2519 return ( fname[0] == '/' || fname[0] == '.' ||
2520 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2521 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2522 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2523# else
2524 return (*fname == '/' || *fname == '~');
2525# endif
2526#endif
2527}
2528
Bram Moolenaar24552be2005-12-10 20:17:30 +00002529#if defined(USE_FNAME_CASE) || defined(PROTO)
2530/*
2531 * Set the case of the file name, if it already exists. This will cause the
2532 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002533 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002534 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002535 void
2536fname_case(name, len)
2537 char_u *name;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002538 int len UNUSED; /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002539{
2540 struct stat st;
2541 char_u *slash, *tail;
2542 DIR *dirp;
2543 struct dirent *dp;
2544
2545 if (lstat((char *)name, &st) >= 0)
2546 {
2547 /* Open the directory where the file is located. */
2548 slash = vim_strrchr(name, '/');
2549 if (slash == NULL)
2550 {
2551 dirp = opendir(".");
2552 tail = name;
2553 }
2554 else
2555 {
2556 *slash = NUL;
2557 dirp = opendir((char *)name);
2558 *slash = '/';
2559 tail = slash + 1;
2560 }
2561
2562 if (dirp != NULL)
2563 {
2564 while ((dp = readdir(dirp)) != NULL)
2565 {
2566 /* Only accept names that differ in case and are the same byte
2567 * length. TODO: accept different length name. */
2568 if (STRICMP(tail, dp->d_name) == 0
2569 && STRLEN(tail) == STRLEN(dp->d_name))
2570 {
2571 char_u newname[MAXPATHL + 1];
2572 struct stat st2;
2573
2574 /* Verify the inode is equal. */
2575 vim_strncpy(newname, name, MAXPATHL);
2576 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2577 MAXPATHL - (tail - name));
2578 if (lstat((char *)newname, &st2) >= 0
2579 && st.st_ino == st2.st_ino
2580 && st.st_dev == st2.st_dev)
2581 {
2582 STRCPY(tail, dp->d_name);
2583 break;
2584 }
2585 }
2586 }
2587
2588 closedir(dirp);
2589 }
2590 }
2591}
2592#endif
2593
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594/*
2595 * Get file permissions for 'name'.
2596 * Returns -1 when it doesn't exist.
2597 */
2598 long
2599mch_getperm(name)
2600 char_u *name;
2601{
2602 struct stat statb;
2603
2604 /* Keep the #ifdef outside of stat(), it may be a macro. */
2605#ifdef VMS
2606 if (stat((char *)vms_fixfilename(name), &statb))
2607#else
2608 if (stat((char *)name, &statb))
2609#endif
2610 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002611#ifdef __INTERIX
2612 /* The top bit makes the value negative, which means the file doesn't
2613 * exist. Remove the bit, we don't use it. */
2614 return statb.st_mode & ~S_ADDACE;
2615#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002616 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002617#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002618}
2619
2620/*
2621 * set file permission for 'name' to 'perm'
2622 *
2623 * return FAIL for failure, OK otherwise
2624 */
2625 int
2626mch_setperm(name, perm)
2627 char_u *name;
2628 long perm;
2629{
2630 return (chmod((char *)
2631#ifdef VMS
2632 vms_fixfilename(name),
2633#else
2634 name,
2635#endif
2636 (mode_t)perm) == 0 ? OK : FAIL);
2637}
2638
2639#if defined(HAVE_ACL) || defined(PROTO)
2640# ifdef HAVE_SYS_ACL_H
2641# include <sys/acl.h>
2642# endif
2643# ifdef HAVE_SYS_ACCESS_H
2644# include <sys/access.h>
2645# endif
2646
2647# ifdef HAVE_SOLARIS_ACL
2648typedef struct vim_acl_solaris_T {
2649 int acl_cnt;
2650 aclent_t *acl_entry;
2651} vim_acl_solaris_T;
2652# endif
2653
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002654#if defined(HAVE_SELINUX) || defined(PROTO)
2655/*
2656 * Copy security info from "from_file" to "to_file".
2657 */
2658 void
2659mch_copy_sec(from_file, to_file)
2660 char_u *from_file;
2661 char_u *to_file;
2662{
2663 if (from_file == NULL)
2664 return;
2665
2666 if (selinux_enabled == -1)
2667 selinux_enabled = is_selinux_enabled();
2668
2669 if (selinux_enabled > 0)
2670 {
2671 security_context_t from_context = NULL;
2672 security_context_t to_context = NULL;
2673
2674 if (getfilecon((char *)from_file, &from_context) < 0)
2675 {
2676 /* If the filesystem doesn't support extended attributes,
2677 the original had no special security context and the
2678 target cannot have one either. */
2679 if (errno == EOPNOTSUPP)
2680 return;
2681
2682 MSG_PUTS(_("\nCould not get security context for "));
2683 msg_outtrans(from_file);
2684 msg_putchar('\n');
2685 return;
2686 }
2687 if (getfilecon((char *)to_file, &to_context) < 0)
2688 {
2689 MSG_PUTS(_("\nCould not get security context for "));
2690 msg_outtrans(to_file);
2691 msg_putchar('\n');
2692 freecon (from_context);
2693 return ;
2694 }
2695 if (strcmp(from_context, to_context) != 0)
2696 {
2697 if (setfilecon((char *)to_file, from_context) < 0)
2698 {
2699 MSG_PUTS(_("\nCould not set security context for "));
2700 msg_outtrans(to_file);
2701 msg_putchar('\n');
2702 }
2703 }
2704 freecon(to_context);
2705 freecon(from_context);
2706 }
2707}
2708#endif /* HAVE_SELINUX */
2709
Bram Moolenaar071d4272004-06-13 20:20:40 +00002710/*
2711 * Return a pointer to the ACL of file "fname" in allocated memory.
2712 * Return NULL if the ACL is not available for whatever reason.
2713 */
2714 vim_acl_T
2715mch_get_acl(fname)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002716 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717{
2718 vim_acl_T ret = NULL;
2719#ifdef HAVE_POSIX_ACL
2720 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2721#else
2722#ifdef HAVE_SOLARIS_ACL
2723 vim_acl_solaris_T *aclent;
2724
2725 aclent = malloc(sizeof(vim_acl_solaris_T));
2726 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2727 {
2728 free(aclent);
2729 return NULL;
2730 }
2731 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2732 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2733 {
2734 free(aclent->acl_entry);
2735 free(aclent);
2736 return NULL;
2737 }
2738 ret = (vim_acl_T)aclent;
2739#else
2740#if defined(HAVE_AIX_ACL)
2741 int aclsize;
2742 struct acl *aclent;
2743
2744 aclsize = sizeof(struct acl);
2745 aclent = malloc(aclsize);
2746 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2747 {
2748 if (errno == ENOSPC)
2749 {
2750 aclsize = aclent->acl_len;
2751 aclent = realloc(aclent, aclsize);
2752 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2753 {
2754 free(aclent);
2755 return NULL;
2756 }
2757 }
2758 else
2759 {
2760 free(aclent);
2761 return NULL;
2762 }
2763 }
2764 ret = (vim_acl_T)aclent;
2765#endif /* HAVE_AIX_ACL */
2766#endif /* HAVE_SOLARIS_ACL */
2767#endif /* HAVE_POSIX_ACL */
2768 return ret;
2769}
2770
2771/*
2772 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2773 */
2774 void
2775mch_set_acl(fname, aclent)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002776 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002777 vim_acl_T aclent;
2778{
2779 if (aclent == NULL)
2780 return;
2781#ifdef HAVE_POSIX_ACL
2782 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2783#else
2784#ifdef HAVE_SOLARIS_ACL
2785 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2786 ((vim_acl_solaris_T *)aclent)->acl_entry);
2787#else
2788#ifdef HAVE_AIX_ACL
2789 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2790#endif /* HAVE_AIX_ACL */
2791#endif /* HAVE_SOLARIS_ACL */
2792#endif /* HAVE_POSIX_ACL */
2793}
2794
2795 void
2796mch_free_acl(aclent)
2797 vim_acl_T aclent;
2798{
2799 if (aclent == NULL)
2800 return;
2801#ifdef HAVE_POSIX_ACL
2802 acl_free((acl_t)aclent);
2803#else
2804#ifdef HAVE_SOLARIS_ACL
2805 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2806 free(aclent);
2807#else
2808#ifdef HAVE_AIX_ACL
2809 free(aclent);
2810#endif /* HAVE_AIX_ACL */
2811#endif /* HAVE_SOLARIS_ACL */
2812#endif /* HAVE_POSIX_ACL */
2813}
2814#endif
2815
2816/*
2817 * Set hidden flag for "name".
2818 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002819 void
2820mch_hide(name)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002821 char_u *name UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822{
2823 /* can't hide a file */
2824}
2825
2826/*
2827 * return TRUE if "name" is a directory
2828 * return FALSE if "name" is not a directory
2829 * return FALSE for error
2830 */
2831 int
2832mch_isdir(name)
2833 char_u *name;
2834{
2835 struct stat statb;
2836
2837 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2838 return FALSE;
2839 if (stat((char *)name, &statb))
2840 return FALSE;
2841#ifdef _POSIX_SOURCE
2842 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2843#else
2844 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2845#endif
2846}
2847
Bram Moolenaar071d4272004-06-13 20:20:40 +00002848static int executable_file __ARGS((char_u *name));
2849
2850/*
2851 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2852 */
2853 static int
2854executable_file(name)
2855 char_u *name;
2856{
2857 struct stat st;
2858
2859 if (stat((char *)name, &st))
2860 return 0;
2861 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2862}
2863
2864/*
2865 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2866 * Return -1 if unknown.
2867 */
2868 int
2869mch_can_exe(name)
2870 char_u *name;
2871{
2872 char_u *buf;
2873 char_u *p, *e;
2874 int retval;
2875
2876 /* If it's an absolute or relative path don't need to use $PATH. */
2877 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2878 || (name[1] == '.' && name[2] == '/'))))
2879 return executable_file(name);
2880
2881 p = (char_u *)getenv("PATH");
2882 if (p == NULL || *p == NUL)
2883 return -1;
2884 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2885 if (buf == NULL)
2886 return -1;
2887
2888 /*
2889 * Walk through all entries in $PATH to check if "name" exists there and
2890 * is an executable file.
2891 */
2892 for (;;)
2893 {
2894 e = (char_u *)strchr((char *)p, ':');
2895 if (e == NULL)
2896 e = p + STRLEN(p);
2897 if (e - p <= 1) /* empty entry means current dir */
2898 STRCPY(buf, "./");
2899 else
2900 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002901 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002902 add_pathsep(buf);
2903 }
2904 STRCAT(buf, name);
2905 retval = executable_file(buf);
2906 if (retval == 1)
2907 break;
2908
2909 if (*e != ':')
2910 break;
2911 p = e + 1;
2912 }
2913
2914 vim_free(buf);
2915 return retval;
2916}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917
2918/*
2919 * Check what "name" is:
2920 * NODE_NORMAL: file or directory (or doesn't exist)
2921 * NODE_WRITABLE: writable device, socket, fifo, etc.
2922 * NODE_OTHER: non-writable things
2923 */
2924 int
2925mch_nodetype(name)
2926 char_u *name;
2927{
2928 struct stat st;
2929
2930 if (stat((char *)name, &st))
2931 return NODE_NORMAL;
2932 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2933 return NODE_NORMAL;
2934#ifndef OS2
2935 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2936 return NODE_OTHER;
2937#endif
2938 /* Everything else is writable? */
2939 return NODE_WRITABLE;
2940}
2941
2942 void
2943mch_early_init()
2944{
2945#ifdef HAVE_CHECK_STACK_GROWTH
2946 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002947
Bram Moolenaar071d4272004-06-13 20:20:40 +00002948 check_stack_growth((char *)&i);
2949
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002950# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951 get_stack_limit();
2952# endif
2953
2954#endif
2955
2956 /*
2957 * Setup an alternative stack for signals. Helps to catch signals when
2958 * running out of stack space.
2959 * Use of sigaltstack() is preferred, it's more portable.
2960 * Ignore any errors.
2961 */
2962#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00002963 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002964 init_signal_stack();
2965#endif
2966}
2967
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002968#if defined(EXITFREE) || defined(PROTO)
2969 void
2970mch_free_mem()
2971{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002972# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2973 if (clip_star.owned)
2974 clip_lose_selection(&clip_star);
2975 if (clip_plus.owned)
2976 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002977# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00002978# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002979 if (xterm_Shell != (Widget)0)
2980 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00002981# ifndef LESSTIF_VERSION
2982 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002983 if (xterm_dpy != NULL)
2984 XtCloseDisplay(xterm_dpy);
2985 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00002986 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002987 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00002988# ifdef FEAT_X11
2989 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
2990# endif
2991 }
2992# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002993# endif
Bram Moolenaara8785102008-11-12 13:10:15 +00002994 /* Don't close the display for GTK 1, it is done in exit(). */
2995# if defined(FEAT_X11) && (!defined(FEAT_GUI_GTK) || defined(HAVE_GTK2))
Bram Moolenaare8208012008-06-20 09:59:25 +00002996 if (x11_display != NULL
2997# ifdef FEAT_XCLIPBOARD
2998 && x11_display != xterm_dpy
2999# endif
3000 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003001 XCloseDisplay(x11_display);
3002# endif
3003# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
3004 vim_free(signal_stack);
3005 signal_stack = NULL;
3006# endif
3007# ifdef FEAT_TITLE
3008 vim_free(oldtitle);
3009 vim_free(oldicon);
3010# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003011}
3012#endif
3013
Bram Moolenaar071d4272004-06-13 20:20:40 +00003014static void exit_scroll __ARGS((void));
3015
3016/*
3017 * Output a newline when exiting.
3018 * Make sure the newline goes to the same stream as the text.
3019 */
3020 static void
3021exit_scroll()
3022{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003023 if (silent_mode)
3024 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003025 if (newline_on_exit || msg_didout)
3026 {
3027 if (msg_use_printf())
3028 {
3029 if (info_message)
3030 mch_msg("\n");
3031 else
3032 mch_errmsg("\r\n");
3033 }
3034 else
3035 out_char('\n');
3036 }
3037 else
3038 {
3039 restore_cterm_colors(); /* get original colors back */
3040 msg_clr_eos_force(); /* clear the rest of the display */
3041 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3042 }
3043}
3044
3045 void
3046mch_exit(r)
3047 int r;
3048{
3049 exiting = TRUE;
3050
3051#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3052 x11_export_final_selection();
3053#endif
3054
3055#ifdef FEAT_GUI
3056 if (!gui.in_use)
3057#endif
3058 {
3059 settmode(TMODE_COOK);
3060#ifdef FEAT_TITLE
3061 mch_restore_title(3); /* restore xterm title and icon name */
3062#endif
3063 /*
3064 * When t_ti is not empty but it doesn't cause swapping terminal
3065 * pages, need to output a newline when msg_didout is set. But when
3066 * t_ti does swap pages it should not go to the shell page. Do this
3067 * before stoptermcap().
3068 */
3069 if (swapping_screen() && !newline_on_exit)
3070 exit_scroll();
3071
3072 /* Stop termcap: May need to check for T_CRV response, which
3073 * requires RAW mode. */
3074 stoptermcap();
3075
3076 /*
3077 * A newline is only required after a message in the alternate screen.
3078 * This is set to TRUE by wait_return().
3079 */
3080 if (!swapping_screen() || newline_on_exit)
3081 exit_scroll();
3082
3083 /* Cursor may have been switched off without calling starttermcap()
3084 * when doing "vim -u vimrc" and vimrc contains ":q". */
3085 if (full_screen)
3086 cursor_on();
3087 }
3088 out_flush();
3089 ml_close_all(TRUE); /* remove all memfiles */
3090 may_core_dump();
3091#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003093 gui_exit(r);
3094#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003095
Bram Moolenaar56718732006-03-15 22:53:57 +00003096#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003097 mac_conv_cleanup();
3098#endif
3099
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100#ifdef __QNX__
3101 /* A core dump won't be created if the signal handler
3102 * doesn't return, so we can't call exit() */
3103 if (deadly_signal != 0)
3104 return;
3105#endif
3106
Bram Moolenaar009b2592004-10-24 19:18:58 +00003107#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003108 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003109#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003110
3111#ifdef EXITFREE
3112 free_all_mem();
3113#endif
3114
Bram Moolenaar071d4272004-06-13 20:20:40 +00003115 exit(r);
3116}
3117
3118 static void
3119may_core_dump()
3120{
3121 if (deadly_signal != 0)
3122 {
3123 signal(deadly_signal, SIG_DFL);
3124 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3125 }
3126}
3127
3128#ifndef VMS
3129
3130 void
3131mch_settmode(tmode)
3132 int tmode;
3133{
3134 static int first = TRUE;
3135
3136 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3137#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3138 /*
3139 * for "new" tty systems
3140 */
3141# ifdef HAVE_TERMIOS_H
3142 static struct termios told;
3143 struct termios tnew;
3144# else
3145 static struct termio told;
3146 struct termio tnew;
3147# endif
3148
3149 if (first)
3150 {
3151 first = FALSE;
3152# if defined(HAVE_TERMIOS_H)
3153 tcgetattr(read_cmd_fd, &told);
3154# else
3155 ioctl(read_cmd_fd, TCGETA, &told);
3156# endif
3157 }
3158
3159 tnew = told;
3160 if (tmode == TMODE_RAW)
3161 {
3162 /*
3163 * ~ICRNL enables typing ^V^M
3164 */
3165 tnew.c_iflag &= ~ICRNL;
3166 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3167# if defined(IEXTEN) && !defined(__MINT__)
3168 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3169 /* but it breaks function keys on MINT */
3170# endif
3171 );
3172# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3173 tnew.c_oflag &= ~ONLCR;
3174# endif
3175 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3176 tnew.c_cc[VTIME] = 0; /* don't wait */
3177 }
3178 else if (tmode == TMODE_SLEEP)
3179 tnew.c_lflag &= ~(ECHO);
3180
3181# if defined(HAVE_TERMIOS_H)
3182 {
3183 int n = 10;
3184
3185 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3186 * few times. */
3187 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3188 && errno == EINTR && n > 0)
3189 --n;
3190 }
3191# else
3192 ioctl(read_cmd_fd, TCSETA, &tnew);
3193# endif
3194
3195#else
3196
3197 /*
3198 * for "old" tty systems
3199 */
3200# ifndef TIOCSETN
3201# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3202# endif
3203 static struct sgttyb ttybold;
3204 struct sgttyb ttybnew;
3205
3206 if (first)
3207 {
3208 first = FALSE;
3209 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3210 }
3211
3212 ttybnew = ttybold;
3213 if (tmode == TMODE_RAW)
3214 {
3215 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3216 ttybnew.sg_flags |= RAW;
3217 }
3218 else if (tmode == TMODE_SLEEP)
3219 ttybnew.sg_flags &= ~(ECHO);
3220 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3221#endif
3222 curr_tmode = tmode;
3223}
3224
3225/*
3226 * Try to get the code for "t_kb" from the stty setting
3227 *
3228 * Even if termcap claims a backspace key, the user's setting *should*
3229 * prevail. stty knows more about reality than termcap does, and if
3230 * somebody's usual erase key is DEL (which, for most BSD users, it will
3231 * be), they're going to get really annoyed if their erase key starts
3232 * doing forward deletes for no reason. (Eric Fischer)
3233 */
3234 void
3235get_stty()
3236{
3237 char_u buf[2];
3238 char_u *p;
3239
3240 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3241#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3242 /* for "new" tty systems */
3243# ifdef HAVE_TERMIOS_H
3244 struct termios keys;
3245# else
3246 struct termio keys;
3247# endif
3248
3249# if defined(HAVE_TERMIOS_H)
3250 if (tcgetattr(read_cmd_fd, &keys) != -1)
3251# else
3252 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3253# endif
3254 {
3255 buf[0] = keys.c_cc[VERASE];
3256 intr_char = keys.c_cc[VINTR];
3257#else
3258 /* for "old" tty systems */
3259 struct sgttyb keys;
3260
3261 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3262 {
3263 buf[0] = keys.sg_erase;
3264 intr_char = keys.sg_kill;
3265#endif
3266 buf[1] = NUL;
3267 add_termcode((char_u *)"kb", buf, FALSE);
3268
3269 /*
3270 * If <BS> and <DEL> are now the same, redefine <DEL>.
3271 */
3272 p = find_termcode((char_u *)"kD");
3273 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3274 do_fixdel(NULL);
3275 }
3276#if 0
3277 } /* to keep cindent happy */
3278#endif
3279}
3280
3281#endif /* VMS */
3282
3283#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3284/*
3285 * Set mouse clicks on or off.
3286 */
3287 void
3288mch_setmouse(on)
3289 int on;
3290{
3291 static int ison = FALSE;
3292 int xterm_mouse_vers;
3293
3294 if (on == ison) /* return quickly if nothing to do */
3295 return;
3296
3297 xterm_mouse_vers = use_xterm_mouse();
3298 if (xterm_mouse_vers > 0)
3299 {
3300 if (on) /* enable mouse events, use mouse tracking if available */
3301 out_str_nf((char_u *)
3302 (xterm_mouse_vers > 1
3303 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3304 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3305 else /* disable mouse events, could probably always send the same */
3306 out_str_nf((char_u *)
3307 (xterm_mouse_vers > 1
3308 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3309 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3310 ison = on;
3311 }
3312
3313# ifdef FEAT_MOUSE_DEC
3314 else if (ttym_flags == TTYM_DEC)
3315 {
3316 if (on) /* enable mouse events */
3317 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3318 else /* disable mouse events */
3319 out_str_nf((char_u *)"\033['z");
3320 ison = on;
3321 }
3322# endif
3323
3324# ifdef FEAT_MOUSE_GPM
3325 else
3326 {
3327 if (on)
3328 {
3329 if (gpm_open())
3330 ison = TRUE;
3331 }
3332 else
3333 {
3334 gpm_close();
3335 ison = FALSE;
3336 }
3337 }
3338# endif
3339
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003340# ifdef FEAT_SYSMOUSE
3341 else
3342 {
3343 if (on)
3344 {
3345 if (sysmouse_open() == OK)
3346 ison = TRUE;
3347 }
3348 else
3349 {
3350 sysmouse_close();
3351 ison = FALSE;
3352 }
3353 }
3354# endif
3355
Bram Moolenaar071d4272004-06-13 20:20:40 +00003356# ifdef FEAT_MOUSE_JSB
3357 else
3358 {
3359 if (on)
3360 {
3361 /* D - Enable Mouse up/down messages
3362 * L - Enable Left Button Reporting
3363 * M - Enable Middle Button Reporting
3364 * R - Enable Right Button Reporting
3365 * K - Enable SHIFT and CTRL key Reporting
3366 * + - Enable Advanced messaging of mouse moves and up/down messages
3367 * Q - Quiet No Ack
3368 * # - Numeric value of mouse pointer required
3369 * 0 = Multiview 2000 cursor, used as standard
3370 * 1 = Windows Arrow
3371 * 2 = Windows I Beam
3372 * 3 = Windows Hour Glass
3373 * 4 = Windows Cross Hair
3374 * 5 = Windows UP Arrow
3375 */
3376#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3377 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3378 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3379#else
3380 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3381 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3382#endif
3383 ison = TRUE;
3384 }
3385 else
3386 {
3387 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3388 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3389 ison = FALSE;
3390 }
3391 }
3392# endif
3393# ifdef FEAT_MOUSE_PTERM
3394 else
3395 {
3396 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3397 if (on)
3398 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3399 else
3400 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3401 ison = on;
3402 }
3403# endif
3404}
3405
3406/*
3407 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3408 */
3409 void
3410check_mouse_termcode()
3411{
3412# ifdef FEAT_MOUSE_XTERM
3413 if (use_xterm_mouse()
3414# ifdef FEAT_GUI
3415 && !gui.in_use
3416# endif
3417 )
3418 {
3419 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003420 ? IF_EB("\233M", CSI_STR "M")
3421 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003422 if (*p_mouse != NUL)
3423 {
3424 /* force mouse off and maybe on to send possibly new mouse
3425 * activation sequence to the xterm, with(out) drag tracing. */
3426 mch_setmouse(FALSE);
3427 setmouse();
3428 }
3429 }
3430 else
3431 del_mouse_termcode(KS_MOUSE);
3432# endif
3433
3434# ifdef FEAT_MOUSE_GPM
3435 if (!use_xterm_mouse()
3436# ifdef FEAT_GUI
3437 && !gui.in_use
3438# endif
3439 )
3440 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3441# endif
3442
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003443# ifdef FEAT_SYSMOUSE
3444 if (!use_xterm_mouse()
3445# ifdef FEAT_GUI
3446 && !gui.in_use
3447# endif
3448 )
3449 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3450# endif
3451
Bram Moolenaar071d4272004-06-13 20:20:40 +00003452# ifdef FEAT_MOUSE_JSB
3453 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3454 if (!use_xterm_mouse()
3455# ifdef FEAT_GUI
3456 && !gui.in_use
3457# endif
3458 )
3459 set_mouse_termcode(KS_JSBTERM_MOUSE,
3460 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3461 else
3462 del_mouse_termcode(KS_JSBTERM_MOUSE);
3463# endif
3464
3465# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003466 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003467 * define it in the GUI or when using an xterm. */
3468 if (!use_xterm_mouse()
3469# ifdef FEAT_GUI
3470 && !gui.in_use
3471# endif
3472 )
3473 set_mouse_termcode(KS_NETTERM_MOUSE,
3474 (char_u *)IF_EB("\033}", ESC_STR "}"));
3475 else
3476 del_mouse_termcode(KS_NETTERM_MOUSE);
3477# endif
3478
3479# ifdef FEAT_MOUSE_DEC
3480 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3481 if (!use_xterm_mouse()
3482# ifdef FEAT_GUI
3483 && !gui.in_use
3484# endif
3485 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003486 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3487 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003488 else
3489 del_mouse_termcode(KS_DEC_MOUSE);
3490# endif
3491# ifdef FEAT_MOUSE_PTERM
3492 /* same as the dec mouse */
3493 if (!use_xterm_mouse()
3494# ifdef FEAT_GUI
3495 && !gui.in_use
3496# endif
3497 )
3498 set_mouse_termcode(KS_PTERM_MOUSE,
3499 (char_u *) IF_EB("\033[", ESC_STR "["));
3500 else
3501 del_mouse_termcode(KS_PTERM_MOUSE);
3502# endif
3503}
3504#endif
3505
3506/*
3507 * set screen mode, always fails.
3508 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003509 int
3510mch_screenmode(arg)
Bram Moolenaar78a15312009-05-15 19:33:18 +00003511 char_u *arg UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003512{
3513 EMSG(_(e_screenmode));
3514 return FAIL;
3515}
3516
3517#ifndef VMS
3518
3519/*
3520 * Try to get the current window size:
3521 * 1. with an ioctl(), most accurate method
3522 * 2. from the environment variables LINES and COLUMNS
3523 * 3. from the termcap
3524 * 4. keep using the old values
3525 * Return OK when size could be determined, FAIL otherwise.
3526 */
3527 int
3528mch_get_shellsize()
3529{
3530 long rows = 0;
3531 long columns = 0;
3532 char_u *p;
3533
3534 /*
3535 * For OS/2 use _scrsize().
3536 */
3537# ifdef __EMX__
3538 {
3539 int s[2];
3540
3541 _scrsize(s);
3542 columns = s[0];
3543 rows = s[1];
3544 }
3545# endif
3546
3547 /*
3548 * 1. try using an ioctl. It is the most accurate method.
3549 *
3550 * Try using TIOCGWINSZ first, some systems that have it also define
3551 * TIOCGSIZE but don't have a struct ttysize.
3552 */
3553# ifdef TIOCGWINSZ
3554 {
3555 struct winsize ws;
3556 int fd = 1;
3557
3558 /* When stdout is not a tty, use stdin for the ioctl(). */
3559 if (!isatty(fd) && isatty(read_cmd_fd))
3560 fd = read_cmd_fd;
3561 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3562 {
3563 columns = ws.ws_col;
3564 rows = ws.ws_row;
3565 }
3566 }
3567# else /* TIOCGWINSZ */
3568# ifdef TIOCGSIZE
3569 {
3570 struct ttysize ts;
3571 int fd = 1;
3572
3573 /* When stdout is not a tty, use stdin for the ioctl(). */
3574 if (!isatty(fd) && isatty(read_cmd_fd))
3575 fd = read_cmd_fd;
3576 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3577 {
3578 columns = ts.ts_cols;
3579 rows = ts.ts_lines;
3580 }
3581 }
3582# endif /* TIOCGSIZE */
3583# endif /* TIOCGWINSZ */
3584
3585 /*
3586 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003587 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3588 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003589 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003590 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003591 {
3592 if ((p = (char_u *)getenv("LINES")))
3593 rows = atoi((char *)p);
3594 if ((p = (char_u *)getenv("COLUMNS")))
3595 columns = atoi((char *)p);
3596 }
3597
3598#ifdef HAVE_TGETENT
3599 /*
3600 * 3. try reading "co" and "li" entries from termcap
3601 */
3602 if (columns == 0 || rows == 0)
3603 getlinecol(&columns, &rows);
3604#endif
3605
3606 /*
3607 * 4. If everything fails, use the old values
3608 */
3609 if (columns <= 0 || rows <= 0)
3610 return FAIL;
3611
3612 Rows = rows;
3613 Columns = columns;
3614 return OK;
3615}
3616
3617/*
3618 * Try to set the window size to Rows and Columns.
3619 */
3620 void
3621mch_set_shellsize()
3622{
3623 if (*T_CWS)
3624 {
3625 /*
3626 * NOTE: if you get an error here that term_set_winsize() is
3627 * undefined, check the output of configure. It could probably not
3628 * find a ncurses, termcap or termlib library.
3629 */
3630 term_set_winsize((int)Rows, (int)Columns);
3631 out_flush();
3632 screen_start(); /* don't know where cursor is now */
3633 }
3634}
3635
3636#endif /* VMS */
3637
3638/*
3639 * Rows and/or Columns has changed.
3640 */
3641 void
3642mch_new_shellsize()
3643{
3644 /* Nothing to do. */
3645}
3646
Bram Moolenaardf177f62005-02-22 08:39:57 +00003647#ifndef USE_SYSTEM
3648static void append_ga_line __ARGS((garray_T *gap));
3649
3650/*
3651 * Append the text in "gap" below the cursor line and clear "gap".
3652 */
3653 static void
3654append_ga_line(gap)
3655 garray_T *gap;
3656{
3657 /* Remove trailing CR. */
3658 if (gap->ga_len > 0
3659 && !curbuf->b_p_bin
3660 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3661 --gap->ga_len;
3662 ga_append(gap, NUL);
3663 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3664 gap->ga_len = 0;
3665}
3666#endif
3667
Bram Moolenaar071d4272004-06-13 20:20:40 +00003668 int
3669mch_call_shell(cmd, options)
3670 char_u *cmd;
3671 int options; /* SHELL_*, see vim.h */
3672{
3673#ifdef VMS
3674 char *ifn = NULL;
3675 char *ofn = NULL;
3676#endif
3677 int tmode = cur_tmode;
3678#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3679 int x;
3680# ifndef __EMX__
3681 char_u *newcmd; /* only needed for unix */
3682# else
3683 /*
3684 * Set the preferred shell in the EMXSHELL environment variable (but
3685 * only if it is different from what is already in the environment).
3686 * Emx then takes care of whether to use "/c" or "-c" in an
3687 * intelligent way. Simply pass the whole thing to emx's system() call.
3688 * Emx also starts an interactive shell if system() is passed an empty
3689 * string.
3690 */
3691 char_u *p, *old;
3692
3693 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3694 {
3695 /* should check HAVE_SETENV, but I know we don't have it. */
3696 p = alloc(10 + strlen(p_sh));
3697 if (p)
3698 {
3699 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3700 putenv((char *)p); /* don't free the pointer! */
3701 }
3702 }
3703# endif
3704
3705 out_flush();
3706
3707 if (options & SHELL_COOKED)
3708 settmode(TMODE_COOK); /* set to normal mode */
3709
3710# ifdef __EMX__
3711 if (cmd == NULL)
3712 x = system(""); /* this starts an interactive shell in emx */
3713 else
3714 x = system((char *)cmd);
3715 /* system() returns -1 when error occurs in starting shell */
3716 if (x == -1 && !emsg_silent)
3717 {
3718 MSG_PUTS(_("\nCannot execute shell "));
3719 msg_outtrans(p_sh);
3720 msg_putchar('\n');
3721 }
3722# else /* not __EMX__ */
3723 if (cmd == NULL)
3724 x = system((char *)p_sh);
3725 else
3726 {
3727# ifdef VMS
3728 if (ofn = strchr((char *)cmd, '>'))
3729 *ofn++ = '\0';
3730 if (ifn = strchr((char *)cmd, '<'))
3731 {
3732 char *p;
3733
3734 *ifn++ = '\0';
3735 p = strchr(ifn,' '); /* chop off any trailing spaces */
3736 if (p)
3737 *p = '\0';
3738 }
3739 if (ofn)
3740 x = vms_sys((char *)cmd, ofn, ifn);
3741 else
3742 x = system((char *)cmd);
3743# else
3744 newcmd = lalloc(STRLEN(p_sh)
3745 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3746 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3747 if (newcmd == NULL)
3748 x = 0;
3749 else
3750 {
3751 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3752 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3753 (char *)p_shcf,
3754 (char *)cmd);
3755 x = system((char *)newcmd);
3756 vim_free(newcmd);
3757 }
3758# endif
3759 }
3760# ifdef VMS
3761 x = vms_sys_status(x);
3762# endif
3763 if (emsg_silent)
3764 ;
3765 else if (x == 127)
3766 MSG_PUTS(_("\nCannot execute shell sh\n"));
3767# endif /* __EMX__ */
3768 else if (x && !(options & SHELL_SILENT))
3769 {
3770 MSG_PUTS(_("\nshell returned "));
3771 msg_outnum((long)x);
3772 msg_putchar('\n');
3773 }
3774
3775 if (tmode == TMODE_RAW)
3776 settmode(TMODE_RAW); /* set to raw mode */
3777# ifdef FEAT_TITLE
3778 resettitle();
3779# endif
3780 return x;
3781
3782#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3783
Bram Moolenaardf177f62005-02-22 08:39:57 +00003784# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3785 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003786
3787 char_u *newcmd = NULL;
3788 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003789 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790 pid_t wait_pid = 0;
3791# ifdef HAVE_UNION_WAIT
3792 union wait status;
3793# else
3794 int status = -1;
3795# endif
3796 int retval = -1;
3797 char **argv = NULL;
3798 int argc;
3799 int i;
3800 char_u *p;
3801 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003803# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003804 int pty_slave_fd = -1;
3805 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003806# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003807 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 int fd_fromshell[2];
3809 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003810# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003811 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003812# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813 static char envbuf_Rows[20];
3814 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003816 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003817
3818 out_flush();
3819 if (options & SHELL_COOKED)
3820 settmode(TMODE_COOK); /* set to normal mode */
3821
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822 newcmd = vim_strsave(p_sh);
3823 if (newcmd == NULL) /* out of memory */
3824 goto error;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003825
3826 /*
3827 * Do this loop twice:
3828 * 1: find number of arguments
3829 * 2: separate them and build argv[]
3830 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003831 for (i = 0; i < 2; ++i)
3832 {
3833 p = newcmd;
3834 inquote = FALSE;
3835 argc = 0;
3836 for (;;)
3837 {
3838 if (i == 1)
3839 argv[argc] = (char *)p;
3840 ++argc;
3841 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3842 {
3843 if (*p == '"')
3844 inquote = !inquote;
3845 ++p;
3846 }
3847 if (*p == NUL)
3848 break;
3849 if (i == 1)
3850 *p++ = NUL;
3851 p = skipwhite(p);
3852 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003853 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003854 {
3855 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3856 if (argv == NULL) /* out of memory */
3857 goto error;
3858 }
3859 }
3860 if (cmd != NULL)
3861 {
3862 if (extra_shell_arg != NULL)
3863 argv[argc++] = (char *)extra_shell_arg;
3864 argv[argc++] = (char *)p_shcf;
3865 argv[argc++] = (char *)cmd;
3866 }
3867 argv[argc] = NULL;
3868
Bram Moolenaar071d4272004-06-13 20:20:40 +00003869 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003870 * For the GUI, when writing the output into the buffer and when reading
3871 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3872 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003873 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003874 if ((options & (SHELL_READ|SHELL_WRITE))
3875# ifdef FEAT_GUI
3876 || (gui.in_use && show_shell_mess)
3877# endif
3878 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003879 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003880# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881 /*
3882 * Try to open a master pty.
3883 * If this works, open the slave pty.
3884 * If the slave can't be opened, close the master pty.
3885 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003886 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003887 {
3888 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3889 if (pty_master_fd >= 0 && ((pty_slave_fd =
3890 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3891 {
3892 close(pty_master_fd);
3893 pty_master_fd = -1;
3894 }
3895 }
3896 /*
3897 * If not opening a pty or it didn't work, try using pipes.
3898 */
3899 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003900# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901 {
3902 pipe_error = (pipe(fd_toshell) < 0);
3903 if (!pipe_error) /* pipe create OK */
3904 {
3905 pipe_error = (pipe(fd_fromshell) < 0);
3906 if (pipe_error) /* pipe create failed */
3907 {
3908 close(fd_toshell[0]);
3909 close(fd_toshell[1]);
3910 }
3911 }
3912 if (pipe_error)
3913 {
3914 MSG_PUTS(_("\nCannot create pipes\n"));
3915 out_flush();
3916 }
3917 }
3918 }
3919
3920 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003921 {
3922# ifdef __BEOS__
3923 beos_cleanup_read_thread();
3924# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003925
Bram Moolenaar071d4272004-06-13 20:20:40 +00003926 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3927 {
3928 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003929 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003930# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003931 || (gui.in_use && show_shell_mess)
3932# endif
3933 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003934 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003935# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003936 if (pty_master_fd >= 0) /* close the pseudo tty */
3937 {
3938 close(pty_master_fd);
3939 close(pty_slave_fd);
3940 }
3941 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003942# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003943 {
3944 close(fd_toshell[0]);
3945 close(fd_toshell[1]);
3946 close(fd_fromshell[0]);
3947 close(fd_fromshell[1]);
3948 }
3949 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003950 }
3951 else if (pid == 0) /* child */
3952 {
3953 reset_signals(); /* handle signals normally */
3954
3955 if (!show_shell_mess || (options & SHELL_EXPAND))
3956 {
3957 int fd;
3958
3959 /*
3960 * Don't want to show any message from the shell. Can't just
3961 * close stdout and stderr though, because some systems will
3962 * break if you try to write to them after that, so we must
3963 * use dup() to replace them with something else -- webb
3964 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3965 * waiting for input.
3966 */
3967 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3968 fclose(stdin);
3969 fclose(stdout);
3970 fclose(stderr);
3971
3972 /*
3973 * If any of these open()'s and dup()'s fail, we just continue
3974 * anyway. It's not fatal, and on most systems it will make
3975 * no difference at all. On a few it will cause the execvp()
3976 * to exit with a non-zero status even when the completion
3977 * could be done, which is nothing too serious. If the open()
3978 * or dup() failed we'd just do the same thing ourselves
3979 * anyway -- webb
3980 */
3981 if (fd >= 0)
3982 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00003983 ignored = dup(fd); /* To replace stdin (fd 0) */
3984 ignored = dup(fd); /* To replace stdout (fd 1) */
3985 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003986
3987 /* Don't need this now that we've duplicated it */
3988 close(fd);
3989 }
3990 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003991 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003992# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003993 || gui.in_use
3994# endif
3995 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003996 {
3997
Bram Moolenaardf177f62005-02-22 08:39:57 +00003998# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003999 /* Create our own process group, so that the child and all its
4000 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004001 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004002 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004003 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004004 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004005# if defined(SIGHUP)
4006 /* When doing "!xterm&" and 'shell' is bash: the shell
4007 * will exit and send SIGHUP to all processes in its
4008 * group, killing the just started process. Ignore SIGHUP
4009 * to avoid that. (suggested by Simon Schubert)
4010 */
4011 signal(SIGHUP, SIG_IGN);
4012# endif
4013 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004014# endif
4015# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004016 if (pty_slave_fd >= 0)
4017 {
4018 /* push stream discipline modules */
4019 if (options & SHELL_COOKED)
4020 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004021# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004022 /* Try to become controlling tty (probably doesn't work,
4023 * unless run by root) */
4024 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004025# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004026 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004027# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004029# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004030 setenv("TERM", "dumb", 1);
4031 sprintf((char *)envbuf, "%ld", Rows);
4032 setenv("ROWS", (char *)envbuf, 1);
4033 sprintf((char *)envbuf, "%ld", Rows);
4034 setenv("LINES", (char *)envbuf, 1);
4035 sprintf((char *)envbuf, "%ld", Columns);
4036 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004037# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004038 /*
4039 * Putenv does not copy the string, it has to remain valid.
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004040 * Use a static array to avoid losing allocated memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004041 */
4042 putenv("TERM=dumb");
4043 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
4044 putenv(envbuf_Rows);
4045 sprintf(envbuf_Rows, "LINES=%ld", Rows);
4046 putenv(envbuf_Rows);
4047 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
4048 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004049# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004050
Bram Moolenaara5792f52005-11-23 21:25:05 +00004051 /*
4052 * stderr is only redirected when using the GUI, so that a
4053 * program like gpg can still access the terminal to get a
4054 * passphrase using stderr.
4055 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004056# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004057 if (pty_master_fd >= 0)
4058 {
4059 close(pty_master_fd); /* close master side of pty */
4060
4061 /* set up stdin/stdout/stderr for the child */
4062 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004063 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004064 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004065 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004066 if (gui.in_use)
4067 {
4068 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004069 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004070 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004071
4072 close(pty_slave_fd); /* has been dupped, close it now */
4073 }
4074 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004075# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004076 {
4077 /* set up stdin for the child */
4078 close(fd_toshell[1]);
4079 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004080 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004081 close(fd_toshell[0]);
4082
4083 /* set up stdout for the child */
4084 close(fd_fromshell[0]);
4085 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004086 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004087 close(fd_fromshell[1]);
4088
Bram Moolenaara5792f52005-11-23 21:25:05 +00004089# ifdef FEAT_GUI
4090 if (gui.in_use)
4091 {
4092 /* set up stderr for the child */
4093 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004094 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004095 }
4096# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004097 }
4098 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004099
Bram Moolenaar071d4272004-06-13 20:20:40 +00004100 /*
4101 * There is no type cast for the argv, because the type may be
4102 * different on different machines. This may cause a warning
4103 * message with strict compilers, don't worry about it.
4104 * Call _exit() instead of exit() to avoid closing the connection
4105 * to the X server (esp. with GTK, which uses atexit()).
4106 */
4107 execvp(argv[0], argv);
4108 _exit(EXEC_FAILED); /* exec failed, return failure code */
4109 }
4110 else /* parent */
4111 {
4112 /*
4113 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004114 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004115 */
4116 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004117 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118
4119 /*
4120 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004121 * This is also used to pipe stdin/stdout to/from the external
4122 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004124 if ((options & (SHELL_READ|SHELL_WRITE))
4125# ifdef FEAT_GUI
4126 || (gui.in_use && show_shell_mess)
4127# endif
4128 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004129 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004130# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004131 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004132# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004134# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4136 int ta_len = 0; /* valid bytes in ta_buf[] */
4137 int len;
4138 int p_more_save;
4139 int old_State;
4140 int c;
4141 int toshell_fd;
4142 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004143 garray_T ga;
4144 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004145# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4146 struct timeval start_tv;
4147# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004148
Bram Moolenaardf177f62005-02-22 08:39:57 +00004149# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150 if (pty_master_fd >= 0)
4151 {
4152 close(pty_slave_fd); /* close slave side of pty */
4153 fromshell_fd = pty_master_fd;
4154 toshell_fd = dup(pty_master_fd);
4155 }
4156 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004157# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004158 {
4159 close(fd_toshell[0]);
4160 close(fd_fromshell[1]);
4161 toshell_fd = fd_toshell[1];
4162 fromshell_fd = fd_fromshell[0];
4163 }
4164
4165 /*
4166 * Write to the child if there are typed characters.
4167 * Read from the child if there are characters available.
4168 * Repeat the reading a few times if more characters are
4169 * available. Need to check for typed keys now and then, but
4170 * not too often (delays when no chars are available).
4171 * This loop is quit if no characters can be read from the pty
4172 * (WaitForChar detected special condition), or there are no
4173 * characters available and the child has exited.
4174 * Only check if the child has exited when there is no more
4175 * output. The child may exit before all the output has
4176 * been printed.
4177 *
4178 * Currently this busy loops!
4179 * This can probably dead-lock when the write blocks!
4180 */
4181 p_more_save = p_more;
4182 p_more = FALSE;
4183 old_State = State;
4184 State = EXTERNCMD; /* don't redraw at window resize */
4185
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004186 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004187 {
4188 /* Fork a process that will write the lines to the
4189 * external program. */
4190 if ((wpid = fork()) == -1)
4191 {
4192 MSG_PUTS(_("\nCannot fork\n"));
4193 }
4194 else if (wpid == 0)
4195 {
4196 linenr_T lnum = curbuf->b_op_start.lnum;
4197 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004198 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004199 char_u *s;
4200 size_t l;
4201
4202 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004203 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004204 for (;;)
4205 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004206 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004207 if (l == 0)
4208 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004209 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004210 /* NL -> NUL translation */
4211 len = write(toshell_fd, "", (size_t)1);
4212 else
4213 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004214 s = vim_strchr(lp + written, NL);
4215 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004216 s == NULL ? l
4217 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004218 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004219 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004220 {
4221 /* Finished a line, add a NL, unless this line
4222 * should not have one. */
4223 if (lnum != curbuf->b_op_end.lnum
4224 || !curbuf->b_p_bin
4225 || (lnum != write_no_eol_lnum
4226 && (lnum !=
4227 curbuf->b_ml.ml_line_count
4228 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004229 ignored = write(toshell_fd, "\n",
4230 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004231 ++lnum;
4232 if (lnum > curbuf->b_op_end.lnum)
4233 {
4234 /* finished all the lines, close pipe */
4235 close(toshell_fd);
4236 toshell_fd = -1;
4237 break;
4238 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004239 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004240 written = 0;
4241 }
4242 else if (len > 0)
4243 written += len;
4244 }
4245 _exit(0);
4246 }
4247 else
4248 {
4249 close(toshell_fd);
4250 toshell_fd = -1;
4251 }
4252 }
4253
4254 if (options & SHELL_READ)
4255 ga_init2(&ga, 1, BUFLEN);
4256
4257 noread_cnt = 0;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004258# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4259 gettimeofday(&start_tv, NULL);
4260# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261 for (;;)
4262 {
4263 /*
4264 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004265 * if there are any.
4266 * Don't do this if we are expanding wild cards (would eat
4267 * typeahead).
4268 * Don't do this when filtering and terminal is in cooked
4269 * mode, the shell command will handle the I/O. Avoids
4270 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004271 * Don't get characters when the child has already
4272 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004273 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004274 * while (noread_cnt > 4), avoids that ":r !ls" eats
4275 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004276 */
4277 len = 0;
4278 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004279 && ((options &
4280 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4281 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004282# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004283 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004284# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004285 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004286 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004287 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004288 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004289 if (ta_len == 0)
4290 {
4291 /* Get extra characters when we don't have any.
4292 * Reset the counter and timer. */
4293 noread_cnt = 0;
4294# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4295 gettimeofday(&start_tv, NULL);
4296# endif
4297 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4298 }
4299 if (ta_len > 0 || len > 0)
4300 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301 /*
4302 * For pipes:
4303 * Check for CTRL-C: send interrupt signal to child.
4304 * Check for CTRL-D: EOF, close pipe to child.
4305 */
4306 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4307 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004308# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309 /*
4310 * Send SIGINT to the child's group or all
4311 * processes in our group.
4312 */
4313 if (ta_buf[ta_len] == Ctrl_C
4314 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004315 {
4316# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004317 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004318# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004321 if (wpid > 0)
4322 kill(wpid, SIGINT);
4323 }
4324# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004325 if (pty_master_fd < 0 && toshell_fd >= 0
4326 && ta_buf[ta_len] == Ctrl_D)
4327 {
4328 close(toshell_fd);
4329 toshell_fd = -1;
4330 }
4331 }
4332
4333 /* replace K_BS by <BS> and K_DEL by <DEL> */
4334 for (i = ta_len; i < ta_len + len; ++i)
4335 {
4336 if (ta_buf[i] == CSI && len - i > 2)
4337 {
4338 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4339 if (c == K_DEL || c == K_KDEL || c == K_BS)
4340 {
4341 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4342 (size_t)(len - i - 2));
4343 if (c == K_DEL || c == K_KDEL)
4344 ta_buf[i] = DEL;
4345 else
4346 ta_buf[i] = Ctrl_H;
4347 len -= 2;
4348 }
4349 }
4350 else if (ta_buf[i] == '\r')
4351 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004352# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004353 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00004354 i += (*mb_ptr2len_len)(ta_buf + i,
4355 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004356# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357 }
4358
4359 /*
4360 * For pipes: echo the typed characters.
4361 * For a pty this does not seem to work.
4362 */
4363 if (pty_master_fd < 0)
4364 {
4365 for (i = ta_len; i < ta_len + len; ++i)
4366 {
4367 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4368 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004369# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004370 else if (has_mbyte)
4371 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004372 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004373
4374 msg_outtrans_len(ta_buf + i, l);
4375 i += l - 1;
4376 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004377# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004378 else
4379 msg_outtrans_len(ta_buf + i, 1);
4380 }
4381 windgoto(msg_row, msg_col);
4382 out_flush();
4383 }
4384
4385 ta_len += len;
4386
4387 /*
4388 * Write the characters to the child, unless EOF has
4389 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004390 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004391 * When writing buffer lines, drop the typed
4392 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004393 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004394 if (options & SHELL_WRITE)
4395 ta_len = 0;
4396 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004397 {
4398 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4399 if (len > 0)
4400 {
4401 ta_len -= len;
4402 mch_memmove(ta_buf, ta_buf + len, ta_len);
4403 }
4404 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004405 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004406 }
4407
Bram Moolenaardf177f62005-02-22 08:39:57 +00004408 if (got_int)
4409 {
4410 /* CTRL-C sends a signal to the child, we ignore it
4411 * ourselves */
4412# ifdef HAVE_SETSID
4413 kill(-pid, SIGINT);
4414# else
4415 kill(0, SIGINT);
4416# endif
4417 if (wpid > 0)
4418 kill(wpid, SIGINT);
4419 got_int = FALSE;
4420 }
4421
Bram Moolenaar071d4272004-06-13 20:20:40 +00004422 /*
4423 * Check if the child has any characters to be printed.
4424 * Read them and write them to our window. Repeat this as
4425 * long as there is something to do, avoid the 10ms wait
4426 * for mch_inchar(), or sending typeahead characters to
4427 * the external process.
4428 * TODO: This should handle escape sequences, compatible
4429 * to some terminal (vt52?).
4430 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004431 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004432 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4433 {
4434 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004435# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004436 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004437# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004438 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004439# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004440 );
4441 if (len <= 0) /* end of file or error */
4442 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004443
4444 noread_cnt = 0;
4445 if (options & SHELL_READ)
4446 {
4447 /* Do NUL -> NL translation, append NL separated
4448 * lines to the current buffer. */
4449 for (i = 0; i < len; ++i)
4450 {
4451 if (buffer[i] == NL)
4452 append_ga_line(&ga);
4453 else if (buffer[i] == NUL)
4454 ga_append(&ga, NL);
4455 else
4456 ga_append(&ga, buffer[i]);
4457 }
4458 }
4459# ifdef FEAT_MBYTE
4460 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004461 {
4462 int l;
4463
Bram Moolenaardf177f62005-02-22 08:39:57 +00004464 len += buffer_off;
4465 buffer[len] = NUL;
4466
Bram Moolenaar071d4272004-06-13 20:20:40 +00004467 /* Check if the last character in buffer[] is
4468 * incomplete, keep these bytes for the next
4469 * round. */
4470 for (p = buffer; p < buffer + len; p += l)
4471 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004472 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004473 if (l == 0)
4474 l = 1; /* NUL byte? */
4475 else if (MB_BYTE2LEN(*p) != l)
4476 break;
4477 }
4478 if (p == buffer) /* no complete character */
4479 {
4480 /* avoid getting stuck at an illegal byte */
4481 if (len >= 12)
4482 ++p;
4483 else
4484 {
4485 buffer_off = len;
4486 continue;
4487 }
4488 }
4489 c = *p;
4490 *p = NUL;
4491 msg_puts(buffer);
4492 if (p < buffer + len)
4493 {
4494 *p = c;
4495 buffer_off = (buffer + len) - p;
4496 mch_memmove(buffer, p, buffer_off);
4497 continue;
4498 }
4499 buffer_off = 0;
4500 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004501# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004502 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004503 {
4504 buffer[len] = NUL;
4505 msg_puts(buffer);
4506 }
4507
4508 windgoto(msg_row, msg_col);
4509 cursor_on();
4510 out_flush();
4511 if (got_int)
4512 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004513
4514# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4515 {
4516 struct timeval now_tv;
4517 long msec;
4518
4519 /* Avoid that we keep looping here without
4520 * checking for a CTRL-C for a long time. Don't
4521 * break out too often to avoid losing typeahead. */
4522 gettimeofday(&now_tv, NULL);
4523 msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
4524 + (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
4525 if (msec > 2000)
4526 {
4527 noread_cnt = 5;
4528 break;
4529 }
4530 }
4531# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532 }
4533
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004534 /* If we already detected the child has finished break the
4535 * loop now. */
4536 if (wait_pid == pid)
4537 break;
4538
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539 /*
4540 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004541 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004542 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004543# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004544 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004545# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004546 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004547# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004548 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4549 || (wait_pid == pid && WIFEXITED(status)))
4550 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004551 /* Don't break the loop yet, try reading more
4552 * characters from "fromshell_fd" first. When using
4553 * pipes there might still be something to read and
4554 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004555 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004557 else
4558 wait_pid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559 }
4560finished:
4561 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004562 if (options & SHELL_READ)
4563 {
4564 if (ga.ga_len > 0)
4565 {
4566 append_ga_line(&ga);
4567 /* remember that the NL was missing */
4568 write_no_eol_lnum = curwin->w_cursor.lnum;
4569 }
4570 else
4571 write_no_eol_lnum = 0;
4572 ga_clear(&ga);
4573 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004574
Bram Moolenaar071d4272004-06-13 20:20:40 +00004575 /*
4576 * Give all typeahead that wasn't used back to ui_inchar().
4577 */
4578 if (ta_len)
4579 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004580 State = old_State;
4581 if (toshell_fd >= 0)
4582 close(toshell_fd);
4583 close(fromshell_fd);
4584 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004585
4586 /*
4587 * Wait until our child has exited.
4588 * Ignore wait() returning pids of other children and returning
4589 * because of some signal like SIGWINCH.
4590 * Don't wait if wait_pid was already set above, indicating the
4591 * child already exited.
4592 */
4593 while (wait_pid != pid)
4594 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004595# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004596 /* Ugly hack: when compiled with Python threads are probably
4597 * used, in which case wait() sometimes hangs for no obvious
4598 * reason. Use waitpid() instead and loop (like the GUI). */
4599# ifdef __NeXT__
4600 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4601# else
4602 wait_pid = waitpid(pid, &status, WNOHANG);
4603# endif
4604 if (wait_pid == 0)
4605 {
4606 /* Wait for 1/100 sec before trying again. */
4607 mch_delay(10L, TRUE);
4608 continue;
4609 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004610# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004611 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004612# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004613 if (wait_pid <= 0
4614# ifdef ECHILD
4615 && errno == ECHILD
4616# endif
4617 )
4618 break;
4619 }
4620
Bram Moolenaardf177f62005-02-22 08:39:57 +00004621 /* Make sure the child that writes to the external program is
4622 * dead. */
4623 if (wpid > 0)
4624 kill(wpid, SIGKILL);
4625
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 /*
4627 * Set to raw mode right now, otherwise a CTRL-C after
4628 * catch_signals() will kill Vim.
4629 */
4630 if (tmode == TMODE_RAW)
4631 settmode(TMODE_RAW);
4632 did_settmode = TRUE;
4633 set_signals();
4634
4635 if (WIFEXITED(status))
4636 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004637 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004638 retval = WEXITSTATUS(status);
4639 if (retval && !emsg_silent)
4640 {
4641 if (retval == EXEC_FAILED)
4642 {
4643 MSG_PUTS(_("\nCannot execute shell "));
4644 msg_outtrans(p_sh);
4645 msg_putchar('\n');
4646 }
4647 else if (!(options & SHELL_SILENT))
4648 {
4649 MSG_PUTS(_("\nshell returned "));
4650 msg_outnum((long)retval);
4651 msg_putchar('\n');
4652 }
4653 }
4654 }
4655 else
4656 MSG_PUTS(_("\nCommand terminated\n"));
4657 }
4658 }
4659 vim_free(argv);
4660
4661error:
4662 if (!did_settmode)
4663 if (tmode == TMODE_RAW)
4664 settmode(TMODE_RAW); /* set to raw mode */
4665# ifdef FEAT_TITLE
4666 resettitle();
4667# endif
4668 vim_free(newcmd);
4669
4670 return retval;
4671
4672#endif /* USE_SYSTEM */
4673}
4674
4675/*
4676 * Check for CTRL-C typed by reading all available characters.
4677 * In cooked mode we should get SIGINT, no need to check.
4678 */
4679 void
4680mch_breakcheck()
4681{
4682 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4683 fill_input_buf(FALSE);
4684}
4685
4686/*
4687 * Wait "msec" msec until a character is available from the keyboard or from
4688 * inbuf[]. msec == -1 will block forever.
4689 * When a GUI is being used, this will never get called -- webb
4690 */
4691 static int
4692WaitForChar(msec)
4693 long msec;
4694{
4695#ifdef FEAT_MOUSE_GPM
4696 int gpm_process_wanted;
4697#endif
4698#ifdef FEAT_XCLIPBOARD
4699 int rest;
4700#endif
4701 int avail;
4702
4703 if (input_available()) /* something in inbuf[] */
4704 return 1;
4705
4706#if defined(FEAT_MOUSE_DEC)
4707 /* May need to query the mouse position. */
4708 if (WantQueryMouse)
4709 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004710 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004711 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4712 }
4713#endif
4714
4715 /*
4716 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4717 * events. This is a bit complicated, because they might both be defined.
4718 */
4719#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4720# ifdef FEAT_XCLIPBOARD
4721 rest = 0;
4722 if (do_xterm_trace())
4723 rest = msec;
4724# endif
4725 do
4726 {
4727# ifdef FEAT_XCLIPBOARD
4728 if (rest != 0)
4729 {
4730 msec = XT_TRACE_DELAY;
4731 if (rest >= 0 && rest < XT_TRACE_DELAY)
4732 msec = rest;
4733 if (rest >= 0)
4734 rest -= msec;
4735 }
4736# endif
4737# ifdef FEAT_MOUSE_GPM
4738 gpm_process_wanted = 0;
4739 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4740# else
4741 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4742# endif
4743 if (!avail)
4744 {
4745 if (input_available())
4746 return 1;
4747# ifdef FEAT_XCLIPBOARD
4748 if (rest == 0 || !do_xterm_trace())
4749# endif
4750 break;
4751 }
4752 }
4753 while (FALSE
4754# ifdef FEAT_MOUSE_GPM
4755 || (gpm_process_wanted && mch_gpm_process() == 0)
4756# endif
4757# ifdef FEAT_XCLIPBOARD
4758 || (!avail && rest != 0)
4759# endif
4760 );
4761
4762#else
4763 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4764#endif
4765 return avail;
4766}
4767
4768/*
4769 * Wait "msec" msec until a character is available from file descriptor "fd".
4770 * Time == -1 will block forever.
4771 * When a GUI is being used, this will not be used for input -- webb
4772 * Returns also, when a request from Sniff is waiting -- toni.
4773 * Or when a Linux GPM mouse event is waiting.
4774 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004775#if defined(__BEOS__)
4776 int
4777#else
4778 static int
4779#endif
4780RealWaitForChar(fd, msec, check_for_gpm)
4781 int fd;
4782 long msec;
Bram Moolenaar78a15312009-05-15 19:33:18 +00004783 int *check_for_gpm UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004784{
4785 int ret;
Bram Moolenaar67c53842010-05-22 18:28:27 +02004786#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02004787 int nb_fd = netbeans_filedesc();
Bram Moolenaar67c53842010-05-22 18:28:27 +02004788#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004789#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004790 static int busy = FALSE;
4791
4792 /* May retry getting characters after an event was handled. */
4793# define MAY_LOOP
4794
4795# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4796 /* Remember at what time we started, so that we know how much longer we
4797 * should wait after being interrupted. */
4798# define USE_START_TV
4799 struct timeval start_tv;
4800
4801 if (msec > 0 && (
4802# ifdef FEAT_XCLIPBOARD
4803 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004804# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004805 ||
4806# endif
4807# endif
4808# ifdef USE_XSMP
4809 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004810# ifdef FEAT_MZSCHEME
4811 ||
4812# endif
4813# endif
4814# ifdef FEAT_MZSCHEME
4815 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004816# endif
4817 ))
4818 gettimeofday(&start_tv, NULL);
4819# endif
4820
4821 /* Handle being called recursively. This may happen for the session
4822 * manager stuff, it may save the file, which does a breakcheck. */
4823 if (busy)
4824 return 0;
4825#endif
4826
4827#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00004828 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004829#endif
4830 {
4831#ifdef MAY_LOOP
4832 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004833# ifdef FEAT_MZSCHEME
4834 int mzquantum_used = FALSE;
4835# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004836#endif
4837#ifndef HAVE_SELECT
Bram Moolenaar67c53842010-05-22 18:28:27 +02004838 struct pollfd fds[6];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839 int nfd;
4840# ifdef FEAT_XCLIPBOARD
4841 int xterm_idx = -1;
4842# endif
4843# ifdef FEAT_MOUSE_GPM
4844 int gpm_idx = -1;
4845# endif
4846# ifdef USE_XSMP
4847 int xsmp_idx = -1;
4848# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02004849# ifdef FEAT_NETBEANS_INTG
4850 int nb_idx = -1;
4851# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004852 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004853
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004854# ifdef FEAT_MZSCHEME
4855 mzvim_check_threads();
4856 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4857 {
4858 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4859 mzquantum_used = TRUE;
4860 }
4861# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862 fds[0].fd = fd;
4863 fds[0].events = POLLIN;
4864 nfd = 1;
4865
4866# ifdef FEAT_SNIFF
4867# define SNIFF_IDX 1
4868 if (want_sniff_request)
4869 {
4870 fds[SNIFF_IDX].fd = fd_from_sniff;
4871 fds[SNIFF_IDX].events = POLLIN;
4872 nfd++;
4873 }
4874# endif
4875# ifdef FEAT_XCLIPBOARD
4876 if (xterm_Shell != (Widget)0)
4877 {
4878 xterm_idx = nfd;
4879 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4880 fds[nfd].events = POLLIN;
4881 nfd++;
4882 }
4883# endif
4884# ifdef FEAT_MOUSE_GPM
4885 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4886 {
4887 gpm_idx = nfd;
4888 fds[nfd].fd = gpm_fd;
4889 fds[nfd].events = POLLIN;
4890 nfd++;
4891 }
4892# endif
4893# ifdef USE_XSMP
4894 if (xsmp_icefd != -1)
4895 {
4896 xsmp_idx = nfd;
4897 fds[nfd].fd = xsmp_icefd;
4898 fds[nfd].events = POLLIN;
4899 nfd++;
4900 }
4901# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02004902#ifdef FEAT_NETBEANS_INTG
4903 if (nb_fd != -1)
4904 {
4905 nb_idx = nfd;
4906 fds[nfd].fd = nb_fd;
4907 fds[nfd].events = POLLIN;
4908 nfd++;
4909 }
4910#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004911
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004912 ret = poll(fds, nfd, towait);
4913# ifdef FEAT_MZSCHEME
4914 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00004915 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004916 finished = FALSE;
4917# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918
4919# ifdef FEAT_SNIFF
4920 if (ret < 0)
4921 sniff_disconnect(1);
4922 else if (want_sniff_request)
4923 {
4924 if (fds[SNIFF_IDX].revents & POLLHUP)
4925 sniff_disconnect(1);
4926 if (fds[SNIFF_IDX].revents & POLLIN)
4927 sniff_request_waiting = 1;
4928 }
4929# endif
4930# ifdef FEAT_XCLIPBOARD
4931 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4932 {
4933 xterm_update(); /* Maybe we should hand out clipboard */
4934 if (--ret == 0 && !input_available())
4935 /* Try again */
4936 finished = FALSE;
4937 }
4938# endif
4939# ifdef FEAT_MOUSE_GPM
4940 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4941 {
4942 *check_for_gpm = 1;
4943 }
4944# endif
4945# ifdef USE_XSMP
4946 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4947 {
4948 if (fds[xsmp_idx].revents & POLLIN)
4949 {
4950 busy = TRUE;
4951 xsmp_handle_requests();
4952 busy = FALSE;
4953 }
4954 else if (fds[xsmp_idx].revents & POLLHUP)
4955 {
4956 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004957 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004958 xsmp_close();
4959 }
4960 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004961 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004962 }
4963# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02004964#ifdef FEAT_NETBEANS_INTG
4965 if (ret > 0 && nb_idx != -1 && fds[nb_idx].revents & POLLIN)
4966 {
4967 netbeans_read();
4968 --ret;
4969 }
4970#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004971
4972
4973#else /* HAVE_SELECT */
4974
4975 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004976 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004977 fd_set rfds, efds;
4978 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004979 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004980
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004981# ifdef FEAT_MZSCHEME
4982 mzvim_check_threads();
4983 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4984 {
4985 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4986 mzquantum_used = TRUE;
4987 }
4988# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004989# ifdef __EMX__
4990 /* don't check for incoming chars if not in raw mode, because select()
4991 * always returns TRUE then (in some version of emx.dll) */
4992 if (curr_tmode != TMODE_RAW)
4993 return 0;
4994# endif
4995
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004996 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004997 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004998 tv.tv_sec = towait / 1000;
4999 tv.tv_usec = (towait % 1000) * (1000000/1000);
5000 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005001 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005002 else
5003 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005004
5005 /*
5006 * Select on ready for reading and exceptional condition (end of file).
5007 */
5008 FD_ZERO(&rfds); /* calls bzero() on a sun */
5009 FD_ZERO(&efds);
5010 FD_SET(fd, &rfds);
5011# if !defined(__QNX__) && !defined(__CYGWIN32__)
5012 /* For QNX select() always returns 1 if this is set. Why? */
5013 FD_SET(fd, &efds);
5014# endif
5015 maxfd = fd;
5016
5017# ifdef FEAT_SNIFF
5018 if (want_sniff_request)
5019 {
5020 FD_SET(fd_from_sniff, &rfds);
5021 FD_SET(fd_from_sniff, &efds);
5022 if (maxfd < fd_from_sniff)
5023 maxfd = fd_from_sniff;
5024 }
5025# endif
5026# ifdef FEAT_XCLIPBOARD
5027 if (xterm_Shell != (Widget)0)
5028 {
5029 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
5030 if (maxfd < ConnectionNumber(xterm_dpy))
5031 maxfd = ConnectionNumber(xterm_dpy);
5032 }
5033# endif
5034# ifdef FEAT_MOUSE_GPM
5035 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5036 {
5037 FD_SET(gpm_fd, &rfds);
5038 FD_SET(gpm_fd, &efds);
5039 if (maxfd < gpm_fd)
5040 maxfd = gpm_fd;
5041 }
5042# endif
5043# ifdef USE_XSMP
5044 if (xsmp_icefd != -1)
5045 {
5046 FD_SET(xsmp_icefd, &rfds);
5047 FD_SET(xsmp_icefd, &efds);
5048 if (maxfd < xsmp_icefd)
5049 maxfd = xsmp_icefd;
5050 }
5051# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005052#ifdef FEAT_NETBEANS_INTG
5053 if (nb_fd != -1)
5054 {
5055 FD_SET(nb_fd, &rfds);
5056 if (maxfd < nb_fd)
5057 maxfd = nb_fd;
5058 }
5059#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005060
5061# ifdef OLD_VMS
5062 /* Old VMS as v6.2 and older have broken select(). It waits more than
5063 * required. Should not be used */
5064 ret = 0;
5065# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005066 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
5067# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00005068# ifdef __TANDEM
5069 if (ret == -1 && errno == ENOTSUP)
5070 {
5071 FD_ZERO(&rfds);
5072 FD_ZERO(&efds);
5073 ret = 0;
5074 }
5075#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005076# ifdef FEAT_MZSCHEME
5077 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005078 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005079 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005080# endif
5081
5082# ifdef FEAT_SNIFF
5083 if (ret < 0 )
5084 sniff_disconnect(1);
5085 else if (ret > 0 && want_sniff_request)
5086 {
5087 if (FD_ISSET(fd_from_sniff, &efds))
5088 sniff_disconnect(1);
5089 if (FD_ISSET(fd_from_sniff, &rfds))
5090 sniff_request_waiting = 1;
5091 }
5092# endif
5093# ifdef FEAT_XCLIPBOARD
5094 if (ret > 0 && xterm_Shell != (Widget)0
5095 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
5096 {
5097 xterm_update(); /* Maybe we should hand out clipboard */
5098 /* continue looping when we only got the X event and the input
5099 * buffer is empty */
5100 if (--ret == 0 && !input_available())
5101 {
5102 /* Try again */
5103 finished = FALSE;
5104 }
5105 }
5106# endif
5107# ifdef FEAT_MOUSE_GPM
5108 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
5109 {
5110 if (FD_ISSET(gpm_fd, &efds))
5111 gpm_close();
5112 else if (FD_ISSET(gpm_fd, &rfds))
5113 *check_for_gpm = 1;
5114 }
5115# endif
5116# ifdef USE_XSMP
5117 if (ret > 0 && xsmp_icefd != -1)
5118 {
5119 if (FD_ISSET(xsmp_icefd, &efds))
5120 {
5121 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005122 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005123 xsmp_close();
5124 if (--ret == 0)
5125 finished = FALSE; /* keep going if event was only one */
5126 }
5127 else if (FD_ISSET(xsmp_icefd, &rfds))
5128 {
5129 busy = TRUE;
5130 xsmp_handle_requests();
5131 busy = FALSE;
5132 if (--ret == 0)
5133 finished = FALSE; /* keep going if event was only one */
5134 }
5135 }
5136# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005137#ifdef FEAT_NETBEANS_INTG
5138 if (ret > 0 && nb_fd != -1 && FD_ISSET(nb_fd, &rfds))
5139 {
5140 netbeans_read();
5141 --ret;
5142 }
5143#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005144
5145#endif /* HAVE_SELECT */
5146
5147#ifdef MAY_LOOP
5148 if (finished || msec == 0)
5149 break;
5150
5151 /* We're going to loop around again, find out for how long */
5152 if (msec > 0)
5153 {
5154# ifdef USE_START_TV
5155 struct timeval mtv;
5156
5157 /* Compute remaining wait time. */
5158 gettimeofday(&mtv, NULL);
5159 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
5160 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
5161# else
5162 /* Guess we got interrupted halfway. */
5163 msec = msec / 2;
5164# endif
5165 if (msec <= 0)
5166 break; /* waited long enough */
5167 }
5168#endif
5169 }
5170
5171 return (ret > 0);
5172}
5173
5174#ifndef VMS
5175
5176#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00005177/*
Bram Moolenaar02743632005-07-25 20:42:36 +00005178 * Expand a path into all matching files and/or directories. Handles "*",
5179 * "?", "[a-z]", "**", etc.
5180 * "path" has backslashes before chars that are not to be expanded.
5181 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005182 */
5183 int
5184mch_expandpath(gap, path, flags)
5185 garray_T *gap;
5186 char_u *path;
5187 int flags; /* EW_* flags */
5188{
Bram Moolenaar02743632005-07-25 20:42:36 +00005189 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005190}
5191#endif
5192
5193/*
5194 * mch_expand_wildcards() - this code does wild-card pattern matching using
5195 * the shell
5196 *
5197 * return OK for success, FAIL for error (you may lose some memory) and put
5198 * an error message in *file.
5199 *
5200 * num_pat is number of input patterns
5201 * pat is array of pointers to input patterns
5202 * num_file is pointer to number of matched file names
5203 * file is pointer to array of pointers to matched file names
5204 */
5205
5206#ifndef SEEK_SET
5207# define SEEK_SET 0
5208#endif
5209#ifndef SEEK_END
5210# define SEEK_END 2
5211#endif
5212
Bram Moolenaar5555acc2006-04-07 21:33:12 +00005213#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00005214
Bram Moolenaar071d4272004-06-13 20:20:40 +00005215 int
5216mch_expand_wildcards(num_pat, pat, num_file, file, flags)
5217 int num_pat;
5218 char_u **pat;
5219 int *num_file;
5220 char_u ***file;
5221 int flags; /* EW_* flags */
5222{
5223 int i;
5224 size_t len;
5225 char_u *p;
5226 int dir;
5227#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00005228 /*
5229 * This is the OS/2 implementation.
5230 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005231# define EXPL_ALLOC_INC 16
5232 char_u **expl_files;
5233 size_t files_alloced, files_free;
5234 char_u *buf;
5235 int has_wildcard;
5236
5237 *num_file = 0; /* default: no files found */
5238 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
5239 files_free = EXPL_ALLOC_INC; /* how much space is not used */
5240 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
5241 if (*file == NULL)
5242 return FAIL;
5243
5244 for (; num_pat > 0; num_pat--, pat++)
5245 {
5246 expl_files = NULL;
5247 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
5248 /* expand environment var or home dir */
5249 buf = expand_env_save(*pat);
5250 else
5251 buf = vim_strsave(*pat);
5252 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005253 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005254 if (has_wildcard) /* yes, so expand them */
5255 expl_files = (char_u **)_fnexplode(buf);
5256
5257 /*
5258 * return value of buf if no wildcards left,
5259 * OR if no match AND EW_NOTFOUND is set.
5260 */
5261 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
5262 || (expl_files == NULL && (flags & EW_NOTFOUND)))
5263 { /* simply save the current contents of *buf */
5264 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
5265 if (expl_files != NULL)
5266 {
5267 expl_files[0] = vim_strsave(buf);
5268 expl_files[1] = NULL;
5269 }
5270 }
5271 vim_free(buf);
5272
5273 /*
5274 * Count number of names resulting from expansion,
5275 * At the same time add a backslash to the end of names that happen to
5276 * be directories, and replace slashes with backslashes.
5277 */
5278 if (expl_files)
5279 {
5280 for (i = 0; (p = expl_files[i]) != NULL; i++)
5281 {
5282 dir = mch_isdir(p);
5283 /* If we don't want dirs and this is one, skip it */
5284 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5285 continue;
5286
Bram Moolenaara2031822006-03-07 22:29:51 +00005287 /* Skip files that are not executable if we check for that. */
5288 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
5289 continue;
5290
Bram Moolenaar071d4272004-06-13 20:20:40 +00005291 if (--files_free == 0)
5292 {
5293 /* need more room in table of pointers */
5294 files_alloced += EXPL_ALLOC_INC;
5295 *file = (char_u **)vim_realloc(*file,
5296 sizeof(char_u **) * files_alloced);
5297 if (*file == NULL)
5298 {
5299 EMSG(_(e_outofmem));
5300 *num_file = 0;
5301 return FAIL;
5302 }
5303 files_free = EXPL_ALLOC_INC;
5304 }
5305 slash_adjust(p);
5306 if (dir)
5307 {
5308 /* For a directory we add a '/', unless it's already
5309 * there. */
5310 len = STRLEN(p);
5311 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5312 {
5313 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005314 if (!after_pathsep((*file)[*num_file],
5315 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005316 {
5317 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005318 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005319 }
5320 }
5321 }
5322 else
5323 {
5324 (*file)[*num_file] = vim_strsave(p);
5325 }
5326
5327 /*
5328 * Error message already given by either alloc or vim_strsave.
5329 * Should return FAIL, but returning OK works also.
5330 */
5331 if ((*file)[*num_file] == NULL)
5332 break;
5333 (*num_file)++;
5334 }
5335 _fnexplodefree((char **)expl_files);
5336 }
5337 }
5338 return OK;
5339
5340#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005341 /*
5342 * This is the non-OS/2 implementation (really Unix).
5343 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005344 int j;
5345 char_u *tempname;
5346 char_u *command;
5347 FILE *fd;
5348 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005349#define STYLE_ECHO 0 /* use "echo", the default */
5350#define STYLE_GLOB 1 /* use "glob", for csh */
5351#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5352#define STYLE_PRINT 3 /* use "print -N", for zsh */
5353#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5354 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005355 int shell_style = STYLE_ECHO;
5356 int check_spaces;
5357 static int did_find_nul = FALSE;
5358 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005359 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005360 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005361
5362 *num_file = 0; /* default: no files found */
5363 *file = NULL;
5364
5365 /*
5366 * If there are no wildcards, just copy the names to allocated memory.
5367 * Saves a lot of time, because we don't have to start a new shell.
5368 */
5369 if (!have_wildcard(num_pat, pat))
5370 return save_patterns(num_pat, pat, num_file, file);
5371
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005372# ifdef HAVE_SANDBOX
5373 /* Don't allow any shell command in the sandbox. */
5374 if (sandbox != 0 && check_secure())
5375 return FAIL;
5376# endif
5377
Bram Moolenaar071d4272004-06-13 20:20:40 +00005378 /*
5379 * Don't allow the use of backticks in secure and restricted mode.
5380 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005381 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005382 for (i = 0; i < num_pat; ++i)
5383 if (vim_strchr(pat[i], '`') != NULL
5384 && (check_restricted() || check_secure()))
5385 return FAIL;
5386
5387 /*
5388 * get a name for the temp file
5389 */
5390 if ((tempname = vim_tempname('o')) == NULL)
5391 {
5392 EMSG(_(e_notmp));
5393 return FAIL;
5394 }
5395
5396 /*
5397 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005398 * file.
5399 * STYLE_BT: NL separated
5400 * If expanding `cmd` execute it directly.
5401 * STYLE_GLOB: NUL separated
5402 * If we use *csh, "glob" will work better than "echo".
5403 * STYLE_PRINT: NL or NUL separated
5404 * If we use *zsh, "print -N" will work better than "glob".
5405 * STYLE_VIMGLOB: NL separated
5406 * If we use *sh*, we define "vimglob()".
5407 * STYLE_ECHO: space separated.
5408 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005409 */
5410 if (num_pat == 1 && *pat[0] == '`'
5411 && (len = STRLEN(pat[0])) > 2
5412 && *(pat[0] + len - 1) == '`')
5413 shell_style = STYLE_BT;
5414 else if ((len = STRLEN(p_sh)) >= 3)
5415 {
5416 if (STRCMP(p_sh + len - 3, "csh") == 0)
5417 shell_style = STYLE_GLOB;
5418 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5419 shell_style = STYLE_PRINT;
5420 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005421 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5422 "sh") != NULL)
5423 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005424
Bram Moolenaarc7247912008-01-13 12:54:11 +00005425 /* Compute the length of the command. We need 2 extra bytes: for the
5426 * optional '&' and for the NUL.
5427 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005428 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005429 if (shell_style == STYLE_VIMGLOB)
5430 len += STRLEN(sh_vimglob_func);
5431
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005432 for (i = 0; i < num_pat; ++i)
5433 {
5434 /* Count the length of the patterns in the same way as they are put in
5435 * "command" below. */
5436#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005437 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005438#else
5439 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005440 for (j = 0; pat[i][j] != NUL; ++j)
5441 {
5442 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5443 ++len; /* may add a backslash */
5444 ++len;
5445 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005446#endif
5447 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005448 command = alloc(len);
5449 if (command == NULL)
5450 {
5451 /* out of memory */
5452 vim_free(tempname);
5453 return FAIL;
5454 }
5455
5456 /*
5457 * Build the shell command:
5458 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5459 * recognizes this).
5460 * - Add the shell command to print the expanded names.
5461 * - Add the temp file name.
5462 * - Add the file name patterns.
5463 */
5464 if (shell_style == STYLE_BT)
5465 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005466 /* change `command; command& ` to (command; command ) */
5467 STRCPY(command, "(");
5468 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005469 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005470 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005471 while (p > command && vim_iswhite(*p))
5472 --p;
5473 if (*p == '&') /* remove trailing '&' */
5474 {
5475 ampersent = TRUE;
5476 *p = ' ';
5477 }
5478 STRCAT(command, ">");
5479 }
5480 else
5481 {
5482 if (flags & EW_NOTFOUND)
5483 STRCPY(command, "set nonomatch; ");
5484 else
5485 STRCPY(command, "unset nonomatch; ");
5486 if (shell_style == STYLE_GLOB)
5487 STRCAT(command, "glob >");
5488 else if (shell_style == STYLE_PRINT)
5489 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005490 else if (shell_style == STYLE_VIMGLOB)
5491 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005492 else
5493 STRCAT(command, "echo >");
5494 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005495
Bram Moolenaar071d4272004-06-13 20:20:40 +00005496 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005497
Bram Moolenaar071d4272004-06-13 20:20:40 +00005498 if (shell_style != STYLE_BT)
5499 for (i = 0; i < num_pat; ++i)
5500 {
5501 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005502 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005503 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005504#ifdef USE_SYSTEM
5505 STRCAT(command, " \"");
5506 STRCAT(command, pat[i]);
5507 STRCAT(command, "\"");
5508#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005509 int intick = FALSE;
5510
Bram Moolenaar071d4272004-06-13 20:20:40 +00005511 p = command + STRLEN(command);
5512 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005513 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005514 {
5515 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005516 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005517 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5518 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005519 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005520 * backslash inside backticks, before a special character
5521 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005522 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005523 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5524 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005525 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005526 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005527 }
5528 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005529 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005530 /* Put a backslash before a special character, but not
5531 * when inside ``. */
5532 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005533
5534 /* Copy one character. */
5535 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005536 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005537 *p = NUL;
5538#endif
5539 }
5540 if (flags & EW_SILENT)
5541 show_shell_mess = FALSE;
5542 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00005543 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005544
5545 /*
5546 * Using zsh -G: If a pattern has no matches, it is just deleted from
5547 * the argument list, otherwise zsh gives an error message and doesn't
5548 * expand any other pattern.
5549 */
5550 if (shell_style == STYLE_PRINT)
5551 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5552
5553 /*
5554 * If we use -f then shell variables set in .cshrc won't get expanded.
5555 * vi can do it, so we will too, but it is only necessary if there is a "$"
5556 * in one of the patterns, otherwise we can still use the fast option.
5557 */
5558 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5559 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5560
5561 /*
5562 * execute the shell command
5563 */
5564 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5565
5566 /* When running in the background, give it some time to create the temp
5567 * file, but don't wait for it to finish. */
5568 if (ampersent)
5569 mch_delay(10L, TRUE);
5570
5571 extra_shell_arg = NULL; /* cleanup */
5572 show_shell_mess = TRUE;
5573 vim_free(command);
5574
Bram Moolenaarc7247912008-01-13 12:54:11 +00005575 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005576 {
5577 mch_remove(tempname);
5578 vim_free(tempname);
5579 /*
5580 * With interactive completion, the error message is not printed.
5581 * However with USE_SYSTEM, I don't know how to turn off error messages
5582 * from the shell, so screen may still get messed up -- webb.
5583 */
5584#ifndef USE_SYSTEM
5585 if (!(flags & EW_SILENT))
5586#endif
5587 {
5588 redraw_later_clear(); /* probably messed up screen */
5589 msg_putchar('\n'); /* clear bottom line quickly */
5590 cmdline_row = Rows - 1; /* continue on last line */
5591#ifdef USE_SYSTEM
5592 if (!(flags & EW_SILENT))
5593#endif
5594 {
5595 MSG(_(e_wildexpand));
5596 msg_start(); /* don't overwrite this message */
5597 }
5598 }
5599 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5600 * EW_NOTFOUND is given */
5601 if (shell_style == STYLE_BT)
5602 return FAIL;
5603 goto notfound;
5604 }
5605
5606 /*
5607 * read the names from the file into memory
5608 */
5609 fd = fopen((char *)tempname, READBIN);
5610 if (fd == NULL)
5611 {
5612 /* Something went wrong, perhaps a file name with a special char. */
5613 if (!(flags & EW_SILENT))
5614 {
5615 MSG(_(e_wildexpand));
5616 msg_start(); /* don't overwrite this message */
5617 }
5618 vim_free(tempname);
5619 goto notfound;
5620 }
5621 fseek(fd, 0L, SEEK_END);
5622 len = ftell(fd); /* get size of temp file */
5623 fseek(fd, 0L, SEEK_SET);
5624 buffer = alloc(len + 1);
5625 if (buffer == NULL)
5626 {
5627 /* out of memory */
5628 mch_remove(tempname);
5629 vim_free(tempname);
5630 fclose(fd);
5631 return FAIL;
5632 }
5633 i = fread((char *)buffer, 1, len, fd);
5634 fclose(fd);
5635 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00005636 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005637 {
5638 /* unexpected read error */
5639 EMSG2(_(e_notread), tempname);
5640 vim_free(tempname);
5641 vim_free(buffer);
5642 return FAIL;
5643 }
5644 vim_free(tempname);
5645
Bram Moolenaarc7247912008-01-13 12:54:11 +00005646# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005647 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5648 p = buffer;
5649 for (i = 0; i < len; ++i)
5650 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5651 *p++ = buffer[i];
5652 len = p - buffer;
5653# endif
5654
5655
5656 /* file names are separated with Space */
5657 if (shell_style == STYLE_ECHO)
5658 {
5659 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5660 p = buffer;
5661 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5662 {
5663 while (*p != ' ' && *p != '\n')
5664 ++p;
5665 p = skipwhite(p); /* skip to next entry */
5666 }
5667 }
5668 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005669 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005670 {
5671 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5672 p = buffer;
5673 for (i = 0; *p != NUL; ++i) /* count number of entries */
5674 {
5675 while (*p != '\n' && *p != NUL)
5676 ++p;
5677 if (*p != NUL)
5678 ++p;
5679 p = skipwhite(p); /* skip leading white space */
5680 }
5681 }
5682 /* file names are separated with NUL */
5683 else
5684 {
5685 /*
5686 * Some versions of zsh use spaces instead of NULs to separate
5687 * results. Only do this when there is no NUL before the end of the
5688 * buffer, otherwise we would never be able to use file names with
5689 * embedded spaces when zsh does use NULs.
5690 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5691 * don't check for spaces again.
5692 */
5693 check_spaces = FALSE;
5694 if (shell_style == STYLE_PRINT && !did_find_nul)
5695 {
5696 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaar78a15312009-05-15 19:33:18 +00005697 if (len && (int)STRLEN(buffer) < (int)len - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005698 did_find_nul = TRUE;
5699 else
5700 check_spaces = TRUE;
5701 }
5702
5703 /*
5704 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5705 * already is one, for STYLE_GLOB it needs to be added.
5706 */
5707 if (len && buffer[len - 1] == NUL)
5708 --len;
5709 else
5710 buffer[len] = NUL;
5711 i = 0;
5712 for (p = buffer; p < buffer + len; ++p)
5713 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5714 {
5715 ++i;
5716 *p = NUL;
5717 }
5718 if (len)
5719 ++i; /* count last entry */
5720 }
5721 if (i == 0)
5722 {
5723 /*
5724 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5725 * /bin/sh will happily expand it to nothing rather than returning an
5726 * error; and hey, it's good to check anyway -- webb.
5727 */
5728 vim_free(buffer);
5729 goto notfound;
5730 }
5731 *num_file = i;
5732 *file = (char_u **)alloc(sizeof(char_u *) * i);
5733 if (*file == NULL)
5734 {
5735 /* out of memory */
5736 vim_free(buffer);
5737 return FAIL;
5738 }
5739
5740 /*
5741 * Isolate the individual file names.
5742 */
5743 p = buffer;
5744 for (i = 0; i < *num_file; ++i)
5745 {
5746 (*file)[i] = p;
5747 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005748 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
5749 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005750 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00005751 while (!(shell_style == STYLE_ECHO && *p == ' ')
5752 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005753 ++p;
5754 if (p == buffer + len) /* last entry */
5755 *p = NUL;
5756 else
5757 {
5758 *p++ = NUL;
5759 p = skipwhite(p); /* skip to next entry */
5760 }
5761 }
5762 else /* NUL separates */
5763 {
5764 while (*p && p < buffer + len) /* skip entry */
5765 ++p;
5766 ++p; /* skip NUL */
5767 }
5768 }
5769
5770 /*
5771 * Move the file names to allocated memory.
5772 */
5773 for (j = 0, i = 0; i < *num_file; ++i)
5774 {
5775 /* Require the files to exist. Helps when using /bin/sh */
5776 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5777 continue;
5778
5779 /* check if this entry should be included */
5780 dir = (mch_isdir((*file)[i]));
5781 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5782 continue;
5783
Bram Moolenaara2031822006-03-07 22:29:51 +00005784 /* Skip files that are not executable if we check for that. */
5785 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
5786 continue;
5787
Bram Moolenaar071d4272004-06-13 20:20:40 +00005788 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5789 if (p)
5790 {
5791 STRCPY(p, (*file)[i]);
5792 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00005793 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005794 (*file)[j++] = p;
5795 }
5796 }
5797 vim_free(buffer);
5798 *num_file = j;
5799
5800 if (*num_file == 0) /* rejected all entries */
5801 {
5802 vim_free(*file);
5803 *file = NULL;
5804 goto notfound;
5805 }
5806
5807 return OK;
5808
5809notfound:
5810 if (flags & EW_NOTFOUND)
5811 return save_patterns(num_pat, pat, num_file, file);
5812 return FAIL;
5813
5814#endif /* __EMX__ */
5815}
5816
5817#endif /* VMS */
5818
5819#ifndef __EMX__
5820 static int
5821save_patterns(num_pat, pat, num_file, file)
5822 int num_pat;
5823 char_u **pat;
5824 int *num_file;
5825 char_u ***file;
5826{
5827 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005828 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005829
5830 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5831 if (*file == NULL)
5832 return FAIL;
5833 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005834 {
5835 s = vim_strsave(pat[i]);
5836 if (s != NULL)
5837 /* Be compatible with expand_filename(): halve the number of
5838 * backslashes. */
5839 backslash_halve(s);
5840 (*file)[i] = s;
5841 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005842 *num_file = num_pat;
5843 return OK;
5844}
5845#endif
5846
5847
5848/*
5849 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5850 * expand.
5851 */
5852 int
5853mch_has_exp_wildcard(p)
5854 char_u *p;
5855{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005856 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005857 {
5858#ifndef OS2
5859 if (*p == '\\' && p[1] != NUL)
5860 ++p;
5861 else
5862#endif
5863 if (vim_strchr((char_u *)
5864#ifdef VMS
5865 "*?%"
5866#else
5867# ifdef OS2
5868 "*?"
5869# else
5870 "*?[{'"
5871# endif
5872#endif
5873 , *p) != NULL)
5874 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005875 }
5876 return FALSE;
5877}
5878
5879/*
5880 * Return TRUE if the string "p" contains a wildcard.
5881 * Don't recognize '~' at the end as a wildcard.
5882 */
5883 int
5884mch_has_wildcard(p)
5885 char_u *p;
5886{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005887 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005888 {
5889#ifndef OS2
5890 if (*p == '\\' && p[1] != NUL)
5891 ++p;
5892 else
5893#endif
5894 if (vim_strchr((char_u *)
5895#ifdef VMS
5896 "*?%$"
5897#else
5898# ifdef OS2
5899# ifdef VIM_BACKTICK
5900 "*?$`"
5901# else
5902 "*?$"
5903# endif
5904# else
5905 "*?[{`'$"
5906# endif
5907#endif
5908 , *p) != NULL
5909 || (*p == '~' && p[1] != NUL))
5910 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005911 }
5912 return FALSE;
5913}
5914
5915#ifndef __EMX__
5916 static int
5917have_wildcard(num, file)
5918 int num;
5919 char_u **file;
5920{
5921 int i;
5922
5923 for (i = 0; i < num; i++)
5924 if (mch_has_wildcard(file[i]))
5925 return 1;
5926 return 0;
5927}
5928
5929 static int
5930have_dollars(num, file)
5931 int num;
5932 char_u **file;
5933{
5934 int i;
5935
5936 for (i = 0; i < num; i++)
5937 if (vim_strchr(file[i], '$') != NULL)
5938 return TRUE;
5939 return FALSE;
5940}
5941#endif /* ifndef __EMX__ */
5942
5943#ifndef HAVE_RENAME
5944/*
5945 * Scaled-down version of rename(), which is missing in Xenix.
5946 * This version can only move regular files and will fail if the
5947 * destination exists.
5948 */
5949 int
5950mch_rename(src, dest)
5951 const char *src, *dest;
5952{
5953 struct stat st;
5954
5955 if (stat(dest, &st) >= 0) /* fail if destination exists */
5956 return -1;
5957 if (link(src, dest) != 0) /* link file to new name */
5958 return -1;
5959 if (mch_remove(src) == 0) /* delete link to old name */
5960 return 0;
5961 return -1;
5962}
5963#endif /* !HAVE_RENAME */
5964
5965#ifdef FEAT_MOUSE_GPM
5966/*
5967 * Initializes connection with gpm (if it isn't already opened)
5968 * Return 1 if succeeded (or connection already opened), 0 if failed
5969 */
5970 static int
5971gpm_open()
5972{
5973 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5974
5975 if (!gpm_flag)
5976 {
5977 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5978 gpm_connect.defaultMask = ~GPM_HARD;
5979 /* Default handling for mouse move*/
5980 gpm_connect.minMod = 0; /* Handle any modifier keys */
5981 gpm_connect.maxMod = 0xffff;
5982 if (Gpm_Open(&gpm_connect, 0) > 0)
5983 {
5984 /* gpm library tries to handling TSTP causes
5985 * problems. Anyways, we close connection to Gpm whenever
5986 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005987 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00005988 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00005989# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00005990 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00005991# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005992 return 1; /* succeed */
5993 }
5994 if (gpm_fd == -2)
5995 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5996 return 0;
5997 }
5998 return 1; /* already open */
5999}
6000
6001/*
6002 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00006003 */
6004 static void
6005gpm_close()
6006{
6007 if (gpm_flag && gpm_fd >= 0) /* if Open */
6008 Gpm_Close();
6009}
6010
6011/* Reads gpm event and adds special keys to input buf. Returns length of
6012 * generated key sequence.
6013 * This function is made after gui_send_mouse_event
6014 */
6015 static int
6016mch_gpm_process()
6017{
6018 int button;
6019 static Gpm_Event gpm_event;
6020 char_u string[6];
6021 int_u vim_modifiers;
6022 int row,col;
6023 unsigned char buttons_mask;
6024 unsigned char gpm_modifiers;
6025 static unsigned char old_buttons = 0;
6026
6027 Gpm_GetEvent(&gpm_event);
6028
6029#ifdef FEAT_GUI
6030 /* Don't put events in the input queue now. */
6031 if (hold_gui_events)
6032 return 0;
6033#endif
6034
6035 row = gpm_event.y - 1;
6036 col = gpm_event.x - 1;
6037
6038 string[0] = ESC; /* Our termcode */
6039 string[1] = 'M';
6040 string[2] = 'G';
6041 switch (GPM_BARE_EVENTS(gpm_event.type))
6042 {
6043 case GPM_DRAG:
6044 string[3] = MOUSE_DRAG;
6045 break;
6046 case GPM_DOWN:
6047 buttons_mask = gpm_event.buttons & ~old_buttons;
6048 old_buttons = gpm_event.buttons;
6049 switch (buttons_mask)
6050 {
6051 case GPM_B_LEFT:
6052 button = MOUSE_LEFT;
6053 break;
6054 case GPM_B_MIDDLE:
6055 button = MOUSE_MIDDLE;
6056 break;
6057 case GPM_B_RIGHT:
6058 button = MOUSE_RIGHT;
6059 break;
6060 default:
6061 return 0;
6062 /*Don't know what to do. Can more than one button be
6063 * reported in one event? */
6064 }
6065 string[3] = (char_u)(button | 0x20);
6066 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
6067 break;
6068 case GPM_UP:
6069 string[3] = MOUSE_RELEASE;
6070 old_buttons &= ~gpm_event.buttons;
6071 break;
6072 default:
6073 return 0;
6074 }
6075 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
6076 gpm_modifiers = gpm_event.modifiers;
6077 vim_modifiers = 0x0;
6078 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
6079 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
6080 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
6081 */
6082 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
6083 vim_modifiers |= MOUSE_SHIFT;
6084
6085 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
6086 vim_modifiers |= MOUSE_CTRL;
6087 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
6088 vim_modifiers |= MOUSE_ALT;
6089 string[3] |= vim_modifiers;
6090 string[4] = (char_u)(col + ' ' + 1);
6091 string[5] = (char_u)(row + ' ' + 1);
6092 add_to_input_buf(string, 6);
6093 return 6;
6094}
6095#endif /* FEAT_MOUSE_GPM */
6096
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006097#ifdef FEAT_SYSMOUSE
6098/*
6099 * Initialize connection with sysmouse.
6100 * Let virtual console inform us with SIGUSR2 for pending sysmouse
6101 * output, any sysmouse output than will be processed via sig_sysmouse().
6102 * Return OK if succeeded, FAIL if failed.
6103 */
6104 static int
6105sysmouse_open()
6106{
6107 struct mouse_info mouse;
6108
6109 mouse.operation = MOUSE_MODE;
6110 mouse.u.mode.mode = 0;
6111 mouse.u.mode.signal = SIGUSR2;
6112 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
6113 {
6114 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
6115 mouse.operation = MOUSE_SHOW;
6116 ioctl(1, CONS_MOUSECTL, &mouse);
6117 return OK;
6118 }
6119 return FAIL;
6120}
6121
6122/*
6123 * Stop processing SIGUSR2 signals, and also make sure that
6124 * virtual console do not send us any sysmouse related signal.
6125 */
6126 static void
6127sysmouse_close()
6128{
6129 struct mouse_info mouse;
6130
6131 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
6132 mouse.operation = MOUSE_MODE;
6133 mouse.u.mode.mode = 0;
6134 mouse.u.mode.signal = 0;
6135 ioctl(1, CONS_MOUSECTL, &mouse);
6136}
6137
6138/*
6139 * Gets info from sysmouse and adds special keys to input buf.
6140 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006141 static RETSIGTYPE
6142sig_sysmouse SIGDEFARG(sigarg)
6143{
6144 struct mouse_info mouse;
6145 struct video_info video;
6146 char_u string[6];
6147 int row, col;
6148 int button;
6149 int buttons;
6150 static int oldbuttons = 0;
6151
6152#ifdef FEAT_GUI
6153 /* Don't put events in the input queue now. */
6154 if (hold_gui_events)
6155 return;
6156#endif
6157
6158 mouse.operation = MOUSE_GETINFO;
6159 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
6160 && ioctl(1, FBIO_MODEINFO, &video) != -1
6161 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
6162 && video.vi_cheight > 0 && video.vi_cwidth > 0)
6163 {
6164 row = mouse.u.data.y / video.vi_cheight;
6165 col = mouse.u.data.x / video.vi_cwidth;
6166 buttons = mouse.u.data.buttons;
6167 string[0] = ESC; /* Our termcode */
6168 string[1] = 'M';
6169 string[2] = 'S';
6170 if (oldbuttons == buttons && buttons != 0)
6171 {
6172 button = MOUSE_DRAG;
6173 }
6174 else
6175 {
6176 switch (buttons)
6177 {
6178 case 0:
6179 button = MOUSE_RELEASE;
6180 break;
6181 case 1:
6182 button = MOUSE_LEFT;
6183 break;
6184 case 2:
6185 button = MOUSE_MIDDLE;
6186 break;
6187 case 4:
6188 button = MOUSE_RIGHT;
6189 break;
6190 default:
6191 return;
6192 }
6193 oldbuttons = buttons;
6194 }
6195 string[3] = (char_u)(button);
6196 string[4] = (char_u)(col + ' ' + 1);
6197 string[5] = (char_u)(row + ' ' + 1);
6198 add_to_input_buf(string, 6);
6199 }
6200 return;
6201}
6202#endif /* FEAT_SYSMOUSE */
6203
Bram Moolenaar071d4272004-06-13 20:20:40 +00006204#if defined(FEAT_LIBCALL) || defined(PROTO)
6205typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
6206typedef char_u * (*INTPROCSTR)__ARGS((int));
6207typedef int (*STRPROCINT)__ARGS((char_u *));
6208typedef int (*INTPROCINT)__ARGS((int));
6209
6210/*
6211 * Call a DLL routine which takes either a string or int param
6212 * and returns an allocated string.
6213 */
6214 int
6215mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
6216 char_u *libname;
6217 char_u *funcname;
6218 char_u *argstring; /* NULL when using a argint */
6219 int argint;
6220 char_u **string_result;/* NULL when using number_result */
6221 int *number_result;
6222{
6223# if defined(USE_DLOPEN)
6224 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006225 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006226# else
6227 shl_t hinstLib;
6228# endif
6229 STRPROCSTR ProcAdd;
6230 INTPROCSTR ProcAddI;
6231 char_u *retval_str = NULL;
6232 int retval_int = 0;
6233 int success = FALSE;
6234
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006235 /*
6236 * Get a handle to the DLL module.
6237 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006238# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006239 /* First clear any error, it's not cleared by the dlopen() call. */
6240 (void)dlerror();
6241
Bram Moolenaar071d4272004-06-13 20:20:40 +00006242 hinstLib = dlopen((char *)libname, RTLD_LAZY
6243# ifdef RTLD_LOCAL
6244 | RTLD_LOCAL
6245# endif
6246 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006247 if (hinstLib == NULL)
6248 {
6249 /* "dlerr" must be used before dlclose() */
6250 dlerr = (char *)dlerror();
6251 if (dlerr != NULL)
6252 EMSG2(_("dlerror = \"%s\""), dlerr);
6253 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006254# else
6255 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
6256# endif
6257
6258 /* If the handle is valid, try to get the function address. */
6259 if (hinstLib != NULL)
6260 {
6261# ifdef HAVE_SETJMP_H
6262 /*
6263 * Catch a crash when calling the library function. For example when
6264 * using a number where a string pointer is expected.
6265 */
6266 mch_startjmp();
6267 if (SETJMP(lc_jump_env) != 0)
6268 {
6269 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006270# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006271 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006272# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006273 mch_didjmp();
6274 }
6275 else
6276# endif
6277 {
6278 retval_str = NULL;
6279 retval_int = 0;
6280
6281 if (argstring != NULL)
6282 {
6283# if defined(USE_DLOPEN)
6284 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006285 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006286# else
6287 if (shl_findsym(&hinstLib, (const char *)funcname,
6288 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
6289 ProcAdd = NULL;
6290# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006291 if ((success = (ProcAdd != NULL
6292# if defined(USE_DLOPEN)
6293 && dlerr == NULL
6294# endif
6295 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006296 {
6297 if (string_result == NULL)
6298 retval_int = ((STRPROCINT)ProcAdd)(argstring);
6299 else
6300 retval_str = (ProcAdd)(argstring);
6301 }
6302 }
6303 else
6304 {
6305# if defined(USE_DLOPEN)
6306 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006307 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006308# else
6309 if (shl_findsym(&hinstLib, (const char *)funcname,
6310 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
6311 ProcAddI = NULL;
6312# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006313 if ((success = (ProcAddI != NULL
6314# if defined(USE_DLOPEN)
6315 && dlerr == NULL
6316# endif
6317 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006318 {
6319 if (string_result == NULL)
6320 retval_int = ((INTPROCINT)ProcAddI)(argint);
6321 else
6322 retval_str = (ProcAddI)(argint);
6323 }
6324 }
6325
6326 /* Save the string before we free the library. */
6327 /* Assume that a "1" or "-1" result is an illegal pointer. */
6328 if (string_result == NULL)
6329 *number_result = retval_int;
6330 else if (retval_str != NULL
6331 && retval_str != (char_u *)1
6332 && retval_str != (char_u *)-1)
6333 *string_result = vim_strsave(retval_str);
6334 }
6335
6336# ifdef HAVE_SETJMP_H
6337 mch_endjmp();
6338# ifdef SIGHASARG
6339 if (lc_signal != 0)
6340 {
6341 int i;
6342
6343 /* try to find the name of this signal */
6344 for (i = 0; signal_info[i].sig != -1; i++)
6345 if (lc_signal == signal_info[i].sig)
6346 break;
6347 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6348 }
6349# endif
6350# endif
6351
Bram Moolenaar071d4272004-06-13 20:20:40 +00006352# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006353 /* "dlerr" must be used before dlclose() */
6354 if (dlerr != NULL)
6355 EMSG2(_("dlerror = \"%s\""), dlerr);
6356
6357 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006358 (void)dlclose(hinstLib);
6359# else
6360 (void)shl_unload(hinstLib);
6361# endif
6362 }
6363
6364 if (!success)
6365 {
6366 EMSG2(_(e_libcall), funcname);
6367 return FAIL;
6368 }
6369
6370 return OK;
6371}
6372#endif
6373
6374#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6375static int xterm_trace = -1; /* default: disabled */
6376static int xterm_button;
6377
6378/*
6379 * Setup a dummy window for X selections in a terminal.
6380 */
6381 void
6382setup_term_clip()
6383{
6384 int z = 0;
6385 char *strp = "";
6386 Widget AppShell;
6387
6388 if (!x_connect_to_server())
6389 return;
6390
6391 open_app_context();
6392 if (app_context != NULL && xterm_Shell == (Widget)0)
6393 {
6394 int (*oldhandler)();
6395#if defined(HAVE_SETJMP_H)
6396 int (*oldIOhandler)();
6397#endif
6398# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6399 struct timeval start_tv;
6400
6401 if (p_verbose > 0)
6402 gettimeofday(&start_tv, NULL);
6403# endif
6404
6405 /* Ignore X errors while opening the display */
6406 oldhandler = XSetErrorHandler(x_error_check);
6407
6408#if defined(HAVE_SETJMP_H)
6409 /* Ignore X IO errors while opening the display */
6410 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6411 mch_startjmp();
6412 if (SETJMP(lc_jump_env) != 0)
6413 {
6414 mch_didjmp();
6415 xterm_dpy = NULL;
6416 }
6417 else
6418#endif
6419 {
6420 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6421 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6422#if defined(HAVE_SETJMP_H)
6423 mch_endjmp();
6424#endif
6425 }
6426
6427#if defined(HAVE_SETJMP_H)
6428 /* Now handle X IO errors normally. */
6429 (void)XSetIOErrorHandler(oldIOhandler);
6430#endif
6431 /* Now handle X errors normally. */
6432 (void)XSetErrorHandler(oldhandler);
6433
6434 if (xterm_dpy == NULL)
6435 {
6436 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006437 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006438 return;
6439 }
6440
6441 /* Catch terminating error of the X server connection. */
6442 (void)XSetIOErrorHandler(x_IOerror_handler);
6443
6444# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6445 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006446 {
6447 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006448 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006449 verbose_leave();
6450 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006451# endif
6452
6453 /* Create a Shell to make converters work. */
6454 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6455 applicationShellWidgetClass, xterm_dpy,
6456 NULL);
6457 if (AppShell == (Widget)0)
6458 return;
6459 xterm_Shell = XtVaCreatePopupShell("VIM",
6460 topLevelShellWidgetClass, AppShell,
6461 XtNmappedWhenManaged, 0,
6462 XtNwidth, 1,
6463 XtNheight, 1,
6464 NULL);
6465 if (xterm_Shell == (Widget)0)
6466 return;
6467
6468 x11_setup_atoms(xterm_dpy);
6469 if (x11_display == NULL)
6470 x11_display = xterm_dpy;
6471
6472 XtRealizeWidget(xterm_Shell);
6473 XSync(xterm_dpy, False);
6474 xterm_update();
6475 }
6476 if (xterm_Shell != (Widget)0)
6477 {
6478 clip_init(TRUE);
6479 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6480 x11_window = (Window)atol(strp);
6481 /* Check if $WINDOWID is valid. */
6482 if (test_x11_window(xterm_dpy) == FAIL)
6483 x11_window = 0;
6484 if (x11_window != 0)
6485 xterm_trace = 0;
6486 }
6487}
6488
6489 void
6490start_xterm_trace(button)
6491 int button;
6492{
6493 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6494 return;
6495 xterm_trace = 1;
6496 xterm_button = button;
6497 do_xterm_trace();
6498}
6499
6500
6501 void
6502stop_xterm_trace()
6503{
6504 if (xterm_trace < 0)
6505 return;
6506 xterm_trace = 0;
6507}
6508
6509/*
6510 * Query the xterm pointer and generate mouse termcodes if necessary
6511 * return TRUE if dragging is active, else FALSE
6512 */
6513 static int
6514do_xterm_trace()
6515{
6516 Window root, child;
6517 int root_x, root_y;
6518 int win_x, win_y;
6519 int row, col;
6520 int_u mask_return;
6521 char_u buf[50];
6522 char_u *strp;
6523 long got_hints;
6524 static char_u *mouse_code;
6525 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6526 static int prev_row = 0, prev_col = 0;
6527 static XSizeHints xterm_hints;
6528
6529 if (xterm_trace <= 0)
6530 return FALSE;
6531
6532 if (xterm_trace == 1)
6533 {
6534 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006535 * have changed recently. */
6536 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6537 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006538 || xterm_hints.width_inc <= 1
6539 || xterm_hints.height_inc <= 1)
6540 {
6541 xterm_trace = -1; /* Not enough data -- disable tracing */
6542 return FALSE;
6543 }
6544
6545 /* Rely on the same mouse code for the duration of this */
6546 mouse_code = find_termcode(mouse_name);
6547 prev_row = mouse_row;
6548 prev_row = mouse_col;
6549 xterm_trace = 2;
6550
6551 /* Find the offset of the chars, there might be a scrollbar on the
6552 * left of the window and/or a menu on the top (eterm etc.) */
6553 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6554 &win_x, &win_y, &mask_return);
6555 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6556 - (xterm_hints.height_inc / 2);
6557 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6558 xterm_hints.y = 2;
6559 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6560 - (xterm_hints.width_inc / 2);
6561 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6562 xterm_hints.x = 2;
6563 return TRUE;
6564 }
6565 if (mouse_code == NULL)
6566 {
6567 xterm_trace = 0;
6568 return FALSE;
6569 }
6570
6571 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6572 &win_x, &win_y, &mask_return);
6573
6574 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6575 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6576 if (row == prev_row && col == prev_col)
6577 return TRUE;
6578
6579 STRCPY(buf, mouse_code);
6580 strp = buf + STRLEN(buf);
6581 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6582 *strp++ = (char_u)(col + ' ' + 1);
6583 *strp++ = (char_u)(row + ' ' + 1);
6584 *strp = 0;
6585 add_to_input_buf(buf, STRLEN(buf));
6586
6587 prev_row = row;
6588 prev_col = col;
6589 return TRUE;
6590}
6591
6592# if defined(FEAT_GUI) || defined(PROTO)
6593/*
6594 * Destroy the display, window and app_context. Required for GTK.
6595 */
6596 void
6597clear_xterm_clip()
6598{
6599 if (xterm_Shell != (Widget)0)
6600 {
6601 XtDestroyWidget(xterm_Shell);
6602 xterm_Shell = (Widget)0;
6603 }
6604 if (xterm_dpy != NULL)
6605 {
Bram Moolenaare8208012008-06-20 09:59:25 +00006606# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006607 /* Lesstif and Solaris crash here, lose some memory */
6608 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00006609# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006610 if (x11_display == xterm_dpy)
6611 x11_display = NULL;
6612 xterm_dpy = NULL;
6613 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006614# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006615 if (app_context != (XtAppContext)NULL)
6616 {
6617 /* Lesstif and Solaris crash here, lose some memory */
6618 XtDestroyApplicationContext(app_context);
6619 app_context = (XtAppContext)NULL;
6620 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006621# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006622}
6623# endif
6624
6625/*
6626 * Catch up with any queued X events. This may put keyboard input into the
6627 * input buffer, call resize call-backs, trigger timers etc. If there is
6628 * nothing in the X event queue (& no timers pending), then we return
6629 * immediately.
6630 */
6631 static void
6632xterm_update()
6633{
6634 XEvent event;
6635
6636 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6637 {
6638 XtAppNextEvent(app_context, &event);
6639#ifdef FEAT_CLIENTSERVER
6640 {
6641 XPropertyEvent *e = (XPropertyEvent *)&event;
6642
6643 if (e->type == PropertyNotify && e->window == commWindow
6644 && e->atom == commProperty && e->state == PropertyNewValue)
6645 serverEventProc(xterm_dpy, &event);
6646 }
6647#endif
6648 XtDispatchEvent(&event);
6649 }
6650}
6651
6652 int
6653clip_xterm_own_selection(cbd)
6654 VimClipboard *cbd;
6655{
6656 if (xterm_Shell != (Widget)0)
6657 return clip_x11_own_selection(xterm_Shell, cbd);
6658 return FAIL;
6659}
6660
6661 void
6662clip_xterm_lose_selection(cbd)
6663 VimClipboard *cbd;
6664{
6665 if (xterm_Shell != (Widget)0)
6666 clip_x11_lose_selection(xterm_Shell, cbd);
6667}
6668
6669 void
6670clip_xterm_request_selection(cbd)
6671 VimClipboard *cbd;
6672{
6673 if (xterm_Shell != (Widget)0)
6674 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6675}
6676
6677 void
6678clip_xterm_set_selection(cbd)
6679 VimClipboard *cbd;
6680{
6681 clip_x11_set_selection(cbd);
6682}
6683#endif
6684
6685
6686#if defined(USE_XSMP) || defined(PROTO)
6687/*
6688 * Code for X Session Management Protocol.
6689 */
6690static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6691static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6692static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6693static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6694static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6695
6696
6697# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6698static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6699
6700/*
6701 * This is our chance to ask the user if they want to save,
6702 * or abort the logout
6703 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006704 static void
6705xsmp_handle_interaction(smc_conn, client_data)
6706 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006707 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006708{
6709 cmdmod_T save_cmdmod;
6710 int cancel_shutdown = False;
6711
6712 save_cmdmod = cmdmod;
6713 cmdmod.confirm = TRUE;
6714 if (check_changed_any(FALSE))
6715 /* Mustn't logout */
6716 cancel_shutdown = True;
6717 cmdmod = save_cmdmod;
6718 setcursor(); /* position cursor */
6719 out_flush();
6720
6721 /* Done interaction */
6722 SmcInteractDone(smc_conn, cancel_shutdown);
6723
6724 /* Finish off
6725 * Only end save-yourself here if we're not cancelling shutdown;
6726 * we'll get a cancelled callback later in which we'll end it.
6727 * Hopefully get around glitchy SMs (like GNOME-1)
6728 */
6729 if (!cancel_shutdown)
6730 {
6731 xsmp.save_yourself = False;
6732 SmcSaveYourselfDone(smc_conn, True);
6733 }
6734}
6735# endif
6736
6737/*
6738 * Callback that starts save-yourself.
6739 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006740 static void
6741xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6742 shutdown, interact_style, fast)
6743 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006744 SmPointer client_data UNUSED;
6745 int save_type UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006746 Bool shutdown;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006747 int interact_style UNUSED;
6748 Bool fast UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006749{
6750 /* Handle already being in saveyourself */
6751 if (xsmp.save_yourself)
6752 SmcSaveYourselfDone(smc_conn, True);
6753 xsmp.save_yourself = True;
6754 xsmp.shutdown = shutdown;
6755
6756 /* First up, preserve all files */
6757 out_flush();
6758 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6759
6760 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006761 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006762
6763# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6764 /* Now see if we can ask about unsaved files */
6765 if (shutdown && !fast && gui.in_use)
6766 /* Need to interact with user, but need SM's permission */
6767 SmcInteractRequest(smc_conn, SmDialogError,
6768 xsmp_handle_interaction, client_data);
6769 else
6770# endif
6771 {
6772 /* Can stop the cycle here */
6773 SmcSaveYourselfDone(smc_conn, True);
6774 xsmp.save_yourself = False;
6775 }
6776}
6777
6778
6779/*
6780 * Callback to warn us of imminent death.
6781 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006782 static void
6783xsmp_die(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006784 SmcConn smc_conn UNUSED;
6785 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006786{
6787 xsmp_close();
6788
6789 /* quit quickly leaving swapfiles for modified buffers behind */
6790 getout_preserve_modified(0);
6791}
6792
6793
6794/*
6795 * Callback to tell us that save-yourself has completed.
6796 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006797 static void
6798xsmp_save_complete(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006799 SmcConn smc_conn UNUSED;
6800 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006801{
6802 xsmp.save_yourself = False;
6803}
6804
6805
6806/*
6807 * Callback to tell us that an instigated shutdown was cancelled
6808 * (maybe even by us)
6809 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006810 static void
6811xsmp_shutdown_cancelled(smc_conn, client_data)
6812 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006813 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006814{
6815 if (xsmp.save_yourself)
6816 SmcSaveYourselfDone(smc_conn, True);
6817 xsmp.save_yourself = False;
6818 xsmp.shutdown = False;
6819}
6820
6821
6822/*
6823 * Callback to tell us that a new ICE connection has been established.
6824 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006825 static void
6826xsmp_ice_connection(iceConn, clientData, opening, watchData)
6827 IceConn iceConn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006828 IcePointer clientData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006829 Bool opening;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006830 IcePointer *watchData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006831{
6832 /* Intercept creation of ICE connection fd */
6833 if (opening)
6834 {
6835 xsmp_icefd = IceConnectionNumber(iceConn);
6836 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6837 }
6838}
6839
6840
6841/* Handle any ICE processing that's required; return FAIL if SM lost */
6842 int
6843xsmp_handle_requests()
6844{
6845 Bool rep;
6846
6847 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6848 == IceProcessMessagesIOError)
6849 {
6850 /* Lost ICE */
6851 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006852 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006853 xsmp_close();
6854 return FAIL;
6855 }
6856 else
6857 return OK;
6858}
6859
6860static int dummy;
6861
6862/* Set up X Session Management Protocol */
6863 void
6864xsmp_init(void)
6865{
6866 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006867 SmcCallbacks smcallbacks;
6868#if 0
6869 SmPropValue smname;
6870 SmProp smnameprop;
6871 SmProp *smprops[1];
6872#endif
6873
6874 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006875 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006876
6877 xsmp.save_yourself = xsmp.shutdown = False;
6878
6879 /* Set up SM callbacks - must have all, even if they're not used */
6880 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6881 smcallbacks.save_yourself.client_data = NULL;
6882 smcallbacks.die.callback = xsmp_die;
6883 smcallbacks.die.client_data = NULL;
6884 smcallbacks.save_complete.callback = xsmp_save_complete;
6885 smcallbacks.save_complete.client_data = NULL;
6886 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6887 smcallbacks.shutdown_cancelled.client_data = NULL;
6888
6889 /* Set up a watch on ICE connection creations. The "dummy" argument is
6890 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6891 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6892 {
6893 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006894 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006895 return;
6896 }
6897
6898 /* Create an SM connection */
6899 xsmp.smcconn = SmcOpenConnection(
6900 NULL,
6901 NULL,
6902 SmProtoMajor,
6903 SmProtoMinor,
6904 SmcSaveYourselfProcMask | SmcDieProcMask
6905 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6906 &smcallbacks,
6907 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00006908 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00006909 sizeof(errorstring),
6910 errorstring);
6911 if (xsmp.smcconn == NULL)
6912 {
6913 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00006914
Bram Moolenaar071d4272004-06-13 20:20:40 +00006915 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006916 {
6917 vim_snprintf(errorreport, sizeof(errorreport),
6918 _("XSMP SmcOpenConnection failed: %s"), errorstring);
6919 verb_msg((char_u *)errorreport);
6920 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006921 return;
6922 }
6923 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6924
6925#if 0
6926 /* ID ourselves */
6927 smname.value = "vim";
6928 smname.length = 3;
6929 smnameprop.name = "SmProgram";
6930 smnameprop.type = "SmARRAY8";
6931 smnameprop.num_vals = 1;
6932 smnameprop.vals = &smname;
6933
6934 smprops[0] = &smnameprop;
6935 SmcSetProperties(xsmp.smcconn, 1, smprops);
6936#endif
6937}
6938
6939
6940/* Shut down XSMP comms. */
6941 void
6942xsmp_close()
6943{
6944 if (xsmp_icefd != -1)
6945 {
6946 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00006947 if (xsmp.clientid != NULL)
6948 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00006949 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006950 xsmp_icefd = -1;
6951 }
6952}
6953#endif /* USE_XSMP */
6954
6955
6956#ifdef EBCDIC
6957/* Translate character to its CTRL- value */
6958char CtrlTable[] =
6959{
6960/* 00 - 5E */
6961 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6962 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6963 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6964 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6965 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6966 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6967/* ^ */ 0x1E,
6968/* - */ 0x1F,
6969/* 61 - 6C */
6970 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6971/* _ */ 0x1F,
6972/* 6E - 80 */
6973 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6974/* a */ 0x01,
6975/* b */ 0x02,
6976/* c */ 0x03,
6977/* d */ 0x37,
6978/* e */ 0x2D,
6979/* f */ 0x2E,
6980/* g */ 0x2F,
6981/* h */ 0x16,
6982/* i */ 0x05,
6983/* 8A - 90 */
6984 0, 0, 0, 0, 0, 0, 0,
6985/* j */ 0x15,
6986/* k */ 0x0B,
6987/* l */ 0x0C,
6988/* m */ 0x0D,
6989/* n */ 0x0E,
6990/* o */ 0x0F,
6991/* p */ 0x10,
6992/* q */ 0x11,
6993/* r */ 0x12,
6994/* 9A - A1 */
6995 0, 0, 0, 0, 0, 0, 0, 0,
6996/* s */ 0x13,
6997/* t */ 0x3C,
6998/* u */ 0x3D,
6999/* v */ 0x32,
7000/* w */ 0x26,
7001/* x */ 0x18,
7002/* y */ 0x19,
7003/* z */ 0x3F,
7004/* AA - AC */
7005 0, 0, 0,
7006/* [ */ 0x27,
7007/* AE - BC */
7008 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7009/* ] */ 0x1D,
7010/* BE - C0 */ 0, 0, 0,
7011/* A */ 0x01,
7012/* B */ 0x02,
7013/* C */ 0x03,
7014/* D */ 0x37,
7015/* E */ 0x2D,
7016/* F */ 0x2E,
7017/* G */ 0x2F,
7018/* H */ 0x16,
7019/* I */ 0x05,
7020/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
7021/* J */ 0x15,
7022/* K */ 0x0B,
7023/* L */ 0x0C,
7024/* M */ 0x0D,
7025/* N */ 0x0E,
7026/* O */ 0x0F,
7027/* P */ 0x10,
7028/* Q */ 0x11,
7029/* R */ 0x12,
7030/* DA - DF */ 0, 0, 0, 0, 0, 0,
7031/* \ */ 0x1C,
7032/* E1 */ 0,
7033/* S */ 0x13,
7034/* T */ 0x3C,
7035/* U */ 0x3D,
7036/* V */ 0x32,
7037/* W */ 0x26,
7038/* X */ 0x18,
7039/* Y */ 0x19,
7040/* Z */ 0x3F,
7041/* EA - FF*/ 0, 0, 0, 0, 0, 0,
7042 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7043};
7044
7045char MetaCharTable[]=
7046{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7047 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
7048 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
7049 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
7050 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
7051};
7052
7053
7054/* TODO: Use characters NOT numbers!!! */
7055char CtrlCharTable[]=
7056{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7057 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
7058 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
7059 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
7060 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
7061};
7062
7063
7064#endif