blob: 5059ab152c510a254815be6fcdf11236d117f3ef [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. */
371 if (usingNetbeans)
372 netbeans_parse_messages();
373#endif
374
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375 /* Check if window changed size while we were busy, perhaps the ":set
376 * columns=99" command was used. */
377 while (do_resize)
378 handle_resize();
379
380 if (wtime >= 0)
381 {
382 while (WaitForChar(wtime) == 0) /* no character available */
383 {
384 if (!do_resize) /* return if not interrupted by resize */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000385 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000386 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200387#ifdef FEAT_NETBEANS_INTG
388 /* Process the queued netbeans messages. */
389 if (usingNetbeans)
390 netbeans_parse_messages();
391#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392 }
393 }
394 else /* wtime == -1 */
395 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000396 /*
397 * If there is no character available within 'updatetime' seconds
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000398 * flush all the swap files to disk.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000399 * Also done when interrupted by SIGWINCH.
400 */
401 if (WaitForChar(p_ut) == 0)
402 {
403#ifdef FEAT_AUTOCMD
Bram Moolenaard35f9712005-12-18 22:02:33 +0000404 if (trigger_cursorhold() && maxlen >= 3
405 && !typebuf_changed(tb_change_cnt))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406 {
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000407 buf[0] = K_SPECIAL;
408 buf[1] = KS_EXTRA;
409 buf[2] = (int)KE_CURSORHOLD;
410 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000411 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412#endif
Bram Moolenaard4098f52005-06-27 22:37:13 +0000413 before_blocking();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000414 }
415 }
416
417 for (;;) /* repeat until we got a character */
418 {
419 while (do_resize) /* window changed size */
420 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200421
422#ifdef FEAT_NETBEANS_INTG
423 /* Process the queued netbeans messages. */
424 if (usingNetbeans)
425 netbeans_parse_messages();
426#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427 /*
428 * we want to be interrupted by the winch signal
Bram Moolenaar67c53842010-05-22 18:28:27 +0200429 * or by an event on the monitored file descriptors
Bram Moolenaar071d4272004-06-13 20:20:40 +0000430 */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200431 if (WaitForChar(-1L) == 0)
432 {
433 if (do_resize) /* interrupted by SIGWINCH signal */
434 handle_resize();
435 return 0;
436 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437
438 /* If input was put directly in typeahead buffer bail out here. */
439 if (typebuf_changed(tb_change_cnt))
440 return 0;
441
442 /*
443 * For some terminals we only get one character at a time.
444 * We want the get all available characters, so we could keep on
445 * trying until none is available
446 * For some other terminals this is quite slow, that's why we don't do
447 * it.
448 */
449 len = read_from_input_buf(buf, (long)maxlen);
450 if (len > 0)
451 {
452#ifdef OS2
453 int i;
454
455 for (i = 0; i < len; i++)
456 if (buf[i] == 0)
457 buf[i] = K_NUL;
458#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000459 return len;
460 }
461 }
462}
463
464 static void
465handle_resize()
466{
467 do_resize = FALSE;
468 shell_resized();
469}
470
471/*
472 * return non-zero if a character is available
473 */
474 int
475mch_char_avail()
476{
477 return WaitForChar(0L);
478}
479
480#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
481# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000482# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000483# endif
484# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
485# include <sys/sysctl.h>
486# endif
487# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
488# include <sys/sysinfo.h>
489# endif
490
491/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000492 * Return total amount of memory available in Kbyte.
493 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000494 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000495 long_u
496mch_total_mem(special)
Bram Moolenaar78a15312009-05-15 19:33:18 +0000497 int special UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498{
499# ifdef __EMX__
Bram Moolenaar914572a2007-05-01 11:37:47 +0000500 return ulimit(3, 0L) >> 10; /* always 32MB? */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000501# else
502 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000503 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504
505# ifdef HAVE_SYSCTL
506 int mib[2], physmem;
507 size_t len;
508
509 /* BSD way of getting the amount of RAM available. */
510 mib[0] = CTL_HW;
511 mib[1] = HW_USERMEM;
512 len = sizeof(physmem);
513 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
514 mem = (long_u)physmem;
515# endif
516
517# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
518 if (mem == 0)
519 {
520 struct sysinfo sinfo;
521
522 /* Linux way of getting amount of RAM available */
523 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000524 {
525# ifdef HAVE_SYSINFO_MEM_UNIT
526 /* avoid overflow as much as possible */
527 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
528 {
529 sinfo.mem_unit = sinfo.mem_unit >> 1;
530 --shiftright;
531 }
532 mem = sinfo.totalram * sinfo.mem_unit;
533# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534 mem = sinfo.totalram;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000535# endif
536 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000537 }
538# endif
539
540# ifdef HAVE_SYSCONF
541 if (mem == 0)
542 {
543 long pagesize, pagecount;
544
545 /* Solaris way of getting amount of RAM available */
546 pagesize = sysconf(_SC_PAGESIZE);
547 pagecount = sysconf(_SC_PHYS_PAGES);
548 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000549 {
550 /* avoid overflow as much as possible */
551 while (shiftright > 0 && (pagesize & 1) == 0)
552 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000553 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000554 --shiftright;
555 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000556 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000557 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558 }
559# endif
560
561 /* Return the minimum of the physical memory and the user limit, because
562 * using more than the user limit may cause Vim to be terminated. */
563# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
564 {
565 struct rlimit rlp;
566
567 if (getrlimit(RLIMIT_DATA, &rlp) == 0
568 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
569# ifdef RLIM_INFINITY
570 && rlp.rlim_cur != RLIM_INFINITY
571# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000572 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000573 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000574 {
575 mem = (long_u)rlp.rlim_cur;
576 shiftright = 10;
577 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578 }
579# endif
580
581 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000582 return mem >> shiftright;
583 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584# endif
585}
586#endif
587
588 void
589mch_delay(msec, ignoreinput)
590 long msec;
591 int ignoreinput;
592{
593 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000594#ifdef FEAT_MZSCHEME
595 long total = msec; /* remember original value */
596#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597
598 if (ignoreinput)
599 {
600 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000601 * here. But we don't want QUIT to kill us (CTRL-\ used in a
602 * shell may produce SIGQUIT). */
603 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000604 old_tmode = curr_tmode;
605 if (curr_tmode == TMODE_RAW)
606 settmode(TMODE_SLEEP);
607
608 /*
609 * Everybody sleeps in a different way...
610 * Prefer nanosleep(), some versions of usleep() can only sleep up to
611 * one second.
612 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000613#ifdef FEAT_MZSCHEME
614 do
615 {
616 /* if total is large enough, wait by portions in p_mzq */
617 if (total > p_mzq)
618 msec = p_mzq;
619 else
620 msec = total;
621 total -= msec;
622#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000623#ifdef HAVE_NANOSLEEP
624 {
625 struct timespec ts;
626
627 ts.tv_sec = msec / 1000;
628 ts.tv_nsec = (msec % 1000) * 1000000;
629 (void)nanosleep(&ts, NULL);
630 }
631#else
632# ifdef HAVE_USLEEP
633 while (msec >= 1000)
634 {
635 usleep((unsigned int)(999 * 1000));
636 msec -= 999;
637 }
638 usleep((unsigned int)(msec * 1000));
639# else
640# ifndef HAVE_SELECT
641 poll(NULL, 0, (int)msec);
642# else
643# ifdef __EMX__
644 _sleep2(msec);
645# else
646 {
647 struct timeval tv;
648
649 tv.tv_sec = msec / 1000;
650 tv.tv_usec = (msec % 1000) * 1000;
651 /*
652 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
653 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
654 */
655 select(0, NULL, NULL, NULL, &tv);
656 }
657# endif /* __EMX__ */
658# endif /* HAVE_SELECT */
659# endif /* HAVE_NANOSLEEP */
660#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000661#ifdef FEAT_MZSCHEME
662 }
663 while (total > 0);
664#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665
666 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000667 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 }
669 else
670 WaitForChar(msec);
671}
672
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000673#if 0 /* disabled, no longer needed now that regmatch() is not recursive */
674# if defined(HAVE_GETRLIMIT)
675# define HAVE_STACK_LIMIT
676# endif
677#endif
678
679#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
681# define HAVE_CHECK_STACK_GROWTH
682/*
683 * Support for checking for an almost-out-of-stack-space situation.
684 */
685
686/*
687 * Return a pointer to an item on the stack. Used to find out if the stack
688 * grows up or down.
689 */
690static void check_stack_growth __ARGS((char *p));
691static int stack_grows_downwards;
692
693/*
694 * Find out if the stack grows upwards or downwards.
695 * "p" points to a variable on the stack of the caller.
696 */
697 static void
698check_stack_growth(p)
699 char *p;
700{
701 int i;
702
703 stack_grows_downwards = (p > (char *)&i);
704}
705#endif
706
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000707#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000708static char *stack_limit = NULL;
709
710#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
711# include <pthread.h>
712# include <pthread_np.h>
713#endif
714
715/*
716 * Find out until how var the stack can grow without getting into trouble.
717 * Called when starting up and when switching to the signal stack in
718 * deathtrap().
719 */
720 static void
721get_stack_limit()
722{
723 struct rlimit rlp;
724 int i;
725 long lim;
726
727 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
728 * limit doesn't fit in a long (rlim_cur might be "long long"). */
729 if (getrlimit(RLIMIT_STACK, &rlp) == 0
730 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
731# ifdef RLIM_INFINITY
732 && rlp.rlim_cur != RLIM_INFINITY
733# endif
734 )
735 {
736 lim = (long)rlp.rlim_cur;
737#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
738 {
739 pthread_attr_t attr;
740 size_t size;
741
742 /* On FreeBSD the initial thread always has a fixed stack size, no
743 * matter what the limits are set to. Normally it's 1 Mbyte. */
744 pthread_attr_init(&attr);
745 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
746 {
747 pthread_attr_getstacksize(&attr, &size);
748 if (lim > (long)size)
749 lim = (long)size;
750 }
751 pthread_attr_destroy(&attr);
752 }
753#endif
754 if (stack_grows_downwards)
755 {
756 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
757 if (stack_limit >= (char *)&i)
758 /* overflow, set to 1/16 of current stack position */
759 stack_limit = (char *)((long)&i / 16L);
760 }
761 else
762 {
763 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
764 if (stack_limit <= (char *)&i)
765 stack_limit = NULL; /* overflow */
766 }
767 }
768}
769
770/*
771 * Return FAIL when running out of stack space.
772 * "p" must point to any variable local to the caller that's on the stack.
773 */
774 int
775mch_stackcheck(p)
776 char *p;
777{
778 if (stack_limit != NULL)
779 {
780 if (stack_grows_downwards)
781 {
782 if (p < stack_limit)
783 return FAIL;
784 }
785 else if (p > stack_limit)
786 return FAIL;
787 }
788 return OK;
789}
790#endif
791
792#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
793/*
794 * Support for using the signal stack.
795 * This helps when we run out of stack space, which causes a SIGSEGV. The
796 * signal handler then must run on another stack, since the normal stack is
797 * completely full.
798 */
799
800#ifndef SIGSTKSZ
801# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
802#endif
803
804# ifdef HAVE_SIGALTSTACK
805static stack_t sigstk; /* for sigaltstack() */
806# else
807static struct sigstack sigstk; /* for sigstack() */
808# endif
809
810static void init_signal_stack __ARGS((void));
811static char *signal_stack;
812
813 static void
814init_signal_stack()
815{
816 if (signal_stack != NULL)
817 {
818# ifdef HAVE_SIGALTSTACK
Bram Moolenaar1a3d0862007-08-30 09:47:38 +0000819# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
820 || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
822 * "struct sigaltstack" needs to be declared. */
823 extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
824# endif
825
826# ifdef HAVE_SS_BASE
827 sigstk.ss_base = signal_stack;
828# else
829 sigstk.ss_sp = signal_stack;
830# endif
831 sigstk.ss_size = SIGSTKSZ;
832 sigstk.ss_flags = 0;
833 (void)sigaltstack(&sigstk, NULL);
834# else
835 sigstk.ss_sp = signal_stack;
836 if (stack_grows_downwards)
837 sigstk.ss_sp += SIGSTKSZ - 1;
838 sigstk.ss_onstack = 0;
839 (void)sigstack(&sigstk, NULL);
840# endif
841 }
842}
843#endif
844
845/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000846 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847 * will barf when the second argument to signal() is ``wrong''.
848 * Let me try it with a few tricky defines from my own osdef.h (jw).
849 */
850#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000851 static RETSIGTYPE
852sig_winch SIGDEFARG(sigarg)
853{
854 /* this is not required on all systems, but it doesn't hurt anybody */
855 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
856 do_resize = TRUE;
857 SIGRETURN;
858}
859#endif
860
861#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 static RETSIGTYPE
863catch_sigint SIGDEFARG(sigarg)
864{
865 /* this is not required on all systems, but it doesn't hurt anybody */
866 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
867 got_int = TRUE;
868 SIGRETURN;
869}
870#endif
871
872#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000873 static RETSIGTYPE
874catch_sigpwr SIGDEFARG(sigarg)
875{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000876 /* this is not required on all systems, but it doesn't hurt anybody */
877 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000878 /*
879 * I'm not sure we get the SIGPWR signal when the system is really going
880 * down or when the batteries are almost empty. Just preserve the swap
881 * files and don't exit, that can't do any harm.
882 */
883 ml_sync_all(FALSE, FALSE);
884 SIGRETURN;
885}
886#endif
887
888#ifdef SET_SIG_ALARM
889/*
890 * signal function for alarm().
891 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000892 static RETSIGTYPE
893sig_alarm SIGDEFARG(sigarg)
894{
895 /* doesn't do anything, just to break a system call */
896 sig_alarm_called = TRUE;
897 SIGRETURN;
898}
899#endif
900
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000901#if (defined(HAVE_SETJMP_H) \
902 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
903 || defined(FEAT_LIBCALL))) \
904 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905/*
906 * A simplistic version of setjmp() that only allows one level of using.
907 * Don't call twice before calling mch_endjmp()!.
908 * Usage:
909 * mch_startjmp();
910 * if (SETJMP(lc_jump_env) != 0)
911 * {
912 * mch_didjmp();
913 * EMSG("crash!");
914 * }
915 * else
916 * {
917 * do_the_work;
918 * mch_endjmp();
919 * }
920 * Note: Can't move SETJMP() here, because a function calling setjmp() must
921 * not return before the saved environment is used.
922 * Returns OK for normal return, FAIL when the protected code caused a
923 * problem and LONGJMP() was used.
924 */
925 void
926mch_startjmp()
927{
928#ifdef SIGHASARG
929 lc_signal = 0;
930#endif
931 lc_active = TRUE;
932}
933
934 void
935mch_endjmp()
936{
937 lc_active = FALSE;
938}
939
940 void
941mch_didjmp()
942{
943# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
944 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
945 * otherwise catching the signal only works once. */
946 init_signal_stack();
947# endif
948}
949#endif
950
951/*
952 * This function handles deadly signals.
953 * It tries to preserve any swap file and exit properly.
954 * (partly from Elvis).
955 */
956 static RETSIGTYPE
957deathtrap SIGDEFARG(sigarg)
958{
959 static int entered = 0; /* count the number of times we got here.
960 Note: when memory has been corrupted
961 this may get an arbitrary value! */
962#ifdef SIGHASARG
963 int i;
964#endif
965
966#if defined(HAVE_SETJMP_H)
967 /*
968 * Catch a crash in protected code.
969 * Restores the environment saved in lc_jump_env, which looks like
970 * SETJMP() returns 1.
971 */
972 if (lc_active)
973 {
974# if defined(SIGHASARG)
975 lc_signal = sigarg;
976# endif
977 lc_active = FALSE; /* don't jump again */
978 LONGJMP(lc_jump_env, 1);
979 /* NOTREACHED */
980 }
981#endif
982
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000983#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000984# ifdef SIGQUIT
985 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
986 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
987 * pressing CTRL-\, but we don't want Vim to exit then. */
988 if (in_mch_delay && sigarg == SIGQUIT)
989 SIGRETURN;
990# endif
991
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000992 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
993 * here. This avoids that a non-reentrant function is interrupted, e.g.,
994 * free(). Calling free() again may then cause a crash. */
995 if (entered == 0
996 && (0
997# ifdef SIGHUP
998 || sigarg == SIGHUP
999# endif
1000# ifdef SIGQUIT
1001 || sigarg == SIGQUIT
1002# endif
1003# ifdef SIGTERM
1004 || sigarg == SIGTERM
1005# endif
1006# ifdef SIGPWR
1007 || sigarg == SIGPWR
1008# endif
1009# ifdef SIGUSR1
1010 || sigarg == SIGUSR1
1011# endif
1012# ifdef SIGUSR2
1013 || sigarg == SIGUSR2
1014# endif
1015 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001016 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001017 SIGRETURN;
1018#endif
1019
Bram Moolenaar071d4272004-06-13 20:20:40 +00001020 /* Remember how often we have been called. */
1021 ++entered;
1022
1023#ifdef FEAT_EVAL
1024 /* Set the v:dying variable. */
1025 set_vim_var_nr(VV_DYING, (long)entered);
1026#endif
1027
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001028#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029 /* Since we are now using the signal stack, need to reset the stack
1030 * limit. Otherwise using a regexp will fail. */
1031 get_stack_limit();
1032#endif
1033
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001034#if 0
1035 /* This is for opening gdb the moment Vim crashes.
1036 * You need to manually adjust the file name and Vim executable name.
1037 * Suggested by SungHyun Nam. */
1038 {
1039# define VI_GDB_FILE "/tmp/vimgdb"
1040# define VIM_NAME "/usr/bin/vim"
1041 FILE *fp = fopen(VI_GDB_FILE, "w");
1042 if (fp)
1043 {
1044 fprintf(fp,
1045 "file %s\n"
1046 "attach %d\n"
1047 "set height 1000\n"
1048 "bt full\n"
1049 , VIM_NAME, getpid());
1050 fclose(fp);
1051 system("xterm -e gdb -x "VI_GDB_FILE);
1052 unlink(VI_GDB_FILE);
1053 }
1054 }
1055#endif
1056
Bram Moolenaar071d4272004-06-13 20:20:40 +00001057#ifdef SIGHASARG
1058 /* try to find the name of this signal */
1059 for (i = 0; signal_info[i].sig != -1; i++)
1060 if (sigarg == signal_info[i].sig)
1061 break;
1062 deadly_signal = sigarg;
1063#endif
1064
1065 full_screen = FALSE; /* don't write message to the GUI, it might be
1066 * part of the problem... */
1067 /*
1068 * If something goes wrong after entering here, we may get here again.
1069 * When this happens, give a message and try to exit nicely (resetting the
1070 * terminal mode, etc.)
1071 * When this happens twice, just exit, don't even try to give a message,
1072 * stack may be corrupt or something weird.
1073 * When this still happens again (or memory was corrupted in such a way
1074 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1075 */
1076 if (entered >= 3)
1077 {
1078 reset_signals(); /* don't catch any signals anymore */
1079 may_core_dump();
1080 if (entered >= 4)
1081 _exit(8);
1082 exit(7);
1083 }
1084 if (entered == 2)
1085 {
1086 OUT_STR(_("Vim: Double signal, exiting\n"));
1087 out_flush();
1088 getout(1);
1089 }
1090
1091#ifdef SIGHASARG
1092 sprintf((char *)IObuff, _("Vim: Caught deadly signal %s\n"),
1093 signal_info[i].name);
1094#else
1095 sprintf((char *)IObuff, _("Vim: Caught deadly signal\n"));
1096#endif
1097 preserve_exit(); /* preserve files and exit */
1098
Bram Moolenaar009b2592004-10-24 19:18:58 +00001099#ifdef NBDEBUG
1100 reset_signals();
1101 may_core_dump();
1102 abort();
1103#endif
1104
Bram Moolenaar071d4272004-06-13 20:20:40 +00001105 SIGRETURN;
1106}
1107
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001108#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109/*
1110 * On Solaris with multi-threading, suspending might not work immediately.
1111 * Catch the SIGCONT signal, which will be used as an indication whether the
1112 * suspending has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001113 *
1114 * On Linux, signal is not always handled immediately either.
1115 * See https://bugs.launchpad.net/bugs/291373
1116 *
1117 * volatile because it is used in in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001119static volatile int sigcont_received;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001120static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1121
1122/*
1123 * signal handler for SIGCONT
1124 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001125 static RETSIGTYPE
1126sigcont_handler SIGDEFARG(sigarg)
1127{
1128 sigcont_received = TRUE;
1129 SIGRETURN;
1130}
1131#endif
1132
1133/*
1134 * If the machine has job control, use it to suspend the program,
1135 * otherwise fake it by starting a new shell.
1136 */
1137 void
1138mch_suspend()
1139{
1140 /* BeOS does have SIGTSTP, but it doesn't work. */
1141#if defined(SIGTSTP) && !defined(__BEOS__)
1142 out_flush(); /* needed to make cursor visible on some systems */
1143 settmode(TMODE_COOK);
1144 out_flush(); /* needed to disable mouse on some systems */
1145
1146# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1147 /* Since we are going to sleep, we can't respond to requests for the X
1148 * selections. Lose them, otherwise other applications will hang. But
1149 * first copy the text to cut buffer 0. */
1150 if (clip_star.owned || clip_plus.owned)
1151 {
1152 x11_export_final_selection();
1153 if (clip_star.owned)
1154 clip_lose_selection(&clip_star);
1155 if (clip_plus.owned)
1156 clip_lose_selection(&clip_plus);
1157 if (x11_display != NULL)
1158 XFlush(x11_display);
1159 }
1160# endif
1161
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001162# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163 sigcont_received = FALSE;
1164# endif
1165 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001166# if defined(_REENTRANT) && defined(SIGCONT)
1167 /*
1168 * Wait for the SIGCONT signal to be handled. It generally happens
1169 * immediately, but somehow not all the time. Do not call pause()
1170 * because there would be race condition which would hang Vim if
1171 * signal happened in between the test of sigcont_received and the
1172 * call to pause(). If signal is not yet received, call sleep(0)
1173 * to just yield CPU. Signal should then be received. If somehow
1174 * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
1175 * further if signal is not received after 1+2+3+4 ms (not expected
1176 * to happen).
1177 */
1178 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001179 long wait_time;
1180 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001181 /* Loop is not entered most of the time */
Bram Moolenaar262735e2009-07-14 10:20:22 +00001182 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001183 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001184# endif
1185
1186# ifdef FEAT_TITLE
1187 /*
1188 * Set oldtitle to NULL, so the current title is obtained again.
1189 */
1190 vim_free(oldtitle);
1191 oldtitle = NULL;
1192# endif
1193 settmode(TMODE_RAW);
1194 need_check_timestamps = TRUE;
1195 did_check_timestamps = FALSE;
1196#else
1197 suspend_shell();
1198#endif
1199}
1200
1201 void
1202mch_init()
1203{
1204 Columns = 80;
1205 Rows = 24;
1206
1207 out_flush();
1208 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001209
Bram Moolenaar56718732006-03-15 22:53:57 +00001210#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001211 mac_conv_init();
1212#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001213}
1214
1215 static void
1216set_signals()
1217{
1218#if defined(SIGWINCH)
1219 /*
1220 * WINDOW CHANGE signal is handled with sig_winch().
1221 */
1222 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1223#endif
1224
1225 /*
1226 * We want the STOP signal to work, to make mch_suspend() work.
1227 * For "rvim" the STOP signal is ignored.
1228 */
1229#ifdef SIGTSTP
1230 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1231#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001232#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233 signal(SIGCONT, sigcont_handler);
1234#endif
1235
1236 /*
1237 * We want to ignore breaking of PIPEs.
1238 */
1239#ifdef SIGPIPE
1240 signal(SIGPIPE, SIG_IGN);
1241#endif
1242
Bram Moolenaar071d4272004-06-13 20:20:40 +00001243#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001244 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001245#endif
1246
1247 /*
1248 * Ignore alarm signals (Perl's alarm() generates it).
1249 */
1250#ifdef SIGALRM
1251 signal(SIGALRM, SIG_IGN);
1252#endif
1253
1254 /*
1255 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1256 * work will be lost.
1257 */
1258#ifdef SIGPWR
1259 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1260#endif
1261
1262 /*
1263 * Arrange for other signals to gracefully shutdown Vim.
1264 */
1265 catch_signals(deathtrap, SIG_ERR);
1266
1267#if defined(FEAT_GUI) && defined(SIGHUP)
1268 /*
1269 * When the GUI is running, ignore the hangup signal.
1270 */
1271 if (gui.in_use)
1272 signal(SIGHUP, SIG_IGN);
1273#endif
1274}
1275
Bram Moolenaardf177f62005-02-22 08:39:57 +00001276#if defined(SIGINT) || defined(PROTO)
1277/*
1278 * Catch CTRL-C (only works while in Cooked mode).
1279 */
1280 static void
1281catch_int_signal()
1282{
1283 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1284}
1285#endif
1286
Bram Moolenaar071d4272004-06-13 20:20:40 +00001287 void
1288reset_signals()
1289{
1290 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001291#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001292 /* SIGCONT isn't in the list, because its default action is ignore */
1293 signal(SIGCONT, SIG_DFL);
1294#endif
1295}
1296
1297 static void
1298catch_signals(func_deadly, func_other)
1299 RETSIGTYPE (*func_deadly)();
1300 RETSIGTYPE (*func_other)();
1301{
1302 int i;
1303
1304 for (i = 0; signal_info[i].sig != -1; i++)
1305 if (signal_info[i].deadly)
1306 {
1307#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1308 struct sigaction sa;
1309
1310 /* Setup to use the alternate stack for the signal function. */
1311 sa.sa_handler = func_deadly;
1312 sigemptyset(&sa.sa_mask);
1313# if defined(__linux__) && defined(_REENTRANT)
1314 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1315 * thread handling in combination with using the alternate stack:
1316 * pthread library functions try to use the stack pointer to
1317 * identify the current thread, causing a SEGV signal, which
1318 * recursively calls deathtrap() and hangs. */
1319 sa.sa_flags = 0;
1320# else
1321 sa.sa_flags = SA_ONSTACK;
1322# endif
1323 sigaction(signal_info[i].sig, &sa, NULL);
1324#else
1325# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1326 struct sigvec sv;
1327
1328 /* Setup to use the alternate stack for the signal function. */
1329 sv.sv_handler = func_deadly;
1330 sv.sv_mask = 0;
1331 sv.sv_flags = SV_ONSTACK;
1332 sigvec(signal_info[i].sig, &sv, NULL);
1333# else
1334 signal(signal_info[i].sig, func_deadly);
1335# endif
1336#endif
1337 }
1338 else if (func_other != SIG_ERR)
1339 signal(signal_info[i].sig, func_other);
1340}
1341
1342/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001343 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001344 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1345 * return TRUE
1346 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1347 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001348 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001349 * Returns TRUE when Vim should exit.
1350 */
1351 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001352vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001353 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001354{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001355 static int got_signal = 0;
1356 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001357
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001358 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001359 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001360 case SIGNAL_BLOCK: blocked = TRUE;
1361 break;
1362
1363 case SIGNAL_UNBLOCK: blocked = FALSE;
1364 if (got_signal != 0)
1365 {
1366 kill(getpid(), got_signal);
1367 got_signal = 0;
1368 }
1369 break;
1370
1371 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001372 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001373 got_signal = sig;
1374#ifdef SIGPWR
1375 if (sig != SIGPWR)
1376#endif
1377 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001378 break;
1379 }
1380 return FALSE;
1381}
1382
1383/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001384 * Check_win checks whether we have an interactive stdout.
1385 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001386 int
1387mch_check_win(argc, argv)
Bram Moolenaar78a15312009-05-15 19:33:18 +00001388 int argc UNUSED;
1389 char **argv UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001390{
1391#ifdef OS2
1392 /*
1393 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1394 * name, mostly it's just "vim" and found in the path, which is unusable.
1395 */
1396 if (mch_isFullName(argv[0]))
1397 exe_name = vim_strsave((char_u *)argv[0]);
1398#endif
1399 if (isatty(1))
1400 return OK;
1401 return FAIL;
1402}
1403
1404/*
1405 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1406 */
1407 int
1408mch_input_isatty()
1409{
1410 if (isatty(read_cmd_fd))
1411 return TRUE;
1412 return FALSE;
1413}
1414
1415#ifdef FEAT_X11
1416
1417# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1418 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1419
1420static void xopen_message __ARGS((struct timeval *tvp));
1421
1422/*
1423 * Give a message about the elapsed time for opening the X window.
1424 */
1425 static void
1426xopen_message(tvp)
1427 struct timeval *tvp; /* must contain start time */
1428{
1429 struct timeval end_tv;
1430
1431 /* Compute elapsed time. */
1432 gettimeofday(&end_tv, NULL);
1433 smsg((char_u *)_("Opening the X display took %ld msec"),
1434 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001435 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001436}
1437# endif
1438#endif
1439
1440#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1441/*
1442 * A few functions shared by X11 title and clipboard code.
1443 */
1444static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1445static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1446static int x_connect_to_server __ARGS((void));
1447static int test_x11_window __ARGS((Display *dpy));
1448
1449static int got_x_error = FALSE;
1450
1451/*
1452 * X Error handler, otherwise X just exits! (very rude) -- webb
1453 */
1454 static int
1455x_error_handler(dpy, error_event)
1456 Display *dpy;
1457 XErrorEvent *error_event;
1458{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001459 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001460 STRCAT(IObuff, _("\nVim: Got X error\n"));
1461
1462 /* We cannot print a message and continue, because no X calls are allowed
1463 * here (causes my system to hang). Silently continuing might be an
1464 * alternative... */
1465 preserve_exit(); /* preserve files and exit */
1466
1467 return 0; /* NOTREACHED */
1468}
1469
1470/*
1471 * Another X Error handler, just used to check for errors.
1472 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001473 static int
1474x_error_check(dpy, error_event)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001475 Display *dpy UNUSED;
1476 XErrorEvent *error_event UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001477{
1478 got_x_error = TRUE;
1479 return 0;
1480}
1481
1482#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1483# if defined(HAVE_SETJMP_H)
1484/*
1485 * An X IO Error handler, used to catch error while opening the display.
1486 */
1487static int x_IOerror_check __ARGS((Display *dpy));
1488
Bram Moolenaar071d4272004-06-13 20:20:40 +00001489 static int
1490x_IOerror_check(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001491 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001492{
1493 /* This function should not return, it causes exit(). Longjump instead. */
1494 LONGJMP(lc_jump_env, 1);
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001495# ifdef VMS
1496 return 0; /* avoid the compiler complains about missing return value */
1497# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001498}
1499# endif
1500
1501/*
1502 * An X IO Error handler, used to catch terminal errors.
1503 */
1504static int x_IOerror_handler __ARGS((Display *dpy));
1505
Bram Moolenaar071d4272004-06-13 20:20:40 +00001506 static int
1507x_IOerror_handler(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001508 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001509{
1510 xterm_dpy = NULL;
1511 x11_window = 0;
1512 x11_display = NULL;
1513 xterm_Shell = (Widget)0;
1514
1515 /* This function should not return, it causes exit(). Longjump instead. */
1516 LONGJMP(x_jump_env, 1);
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001517# ifdef VMS
1518 return 0; /* avoid the compiler complains about missing return value */
1519# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001520}
1521#endif
1522
1523/*
1524 * Return TRUE when connection to the X server is desired.
1525 */
1526 static int
1527x_connect_to_server()
1528{
1529 regmatch_T regmatch;
1530
1531#if defined(FEAT_CLIENTSERVER)
1532 if (x_force_connect)
1533 return TRUE;
1534#endif
1535 if (x_no_connect)
1536 return FALSE;
1537
1538 /* Check for a match with "exclude:" from 'clipboard'. */
1539 if (clip_exclude_prog != NULL)
1540 {
1541 regmatch.rm_ic = FALSE; /* Don't ignore case */
1542 regmatch.regprog = clip_exclude_prog;
1543 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1544 return FALSE;
1545 }
1546 return TRUE;
1547}
1548
1549/*
1550 * Test if "dpy" and x11_window are valid by getting the window title.
1551 * I don't actually want it yet, so there may be a simpler call to use, but
1552 * this will cause the error handler x_error_check() to be called if anything
1553 * is wrong, such as the window pointer being invalid (as can happen when the
1554 * user changes his DISPLAY, but not his WINDOWID) -- webb
1555 */
1556 static int
1557test_x11_window(dpy)
1558 Display *dpy;
1559{
1560 int (*old_handler)();
1561 XTextProperty text_prop;
1562
1563 old_handler = XSetErrorHandler(x_error_check);
1564 got_x_error = FALSE;
1565 if (XGetWMName(dpy, x11_window, &text_prop))
1566 XFree((void *)text_prop.value);
1567 XSync(dpy, False);
1568 (void)XSetErrorHandler(old_handler);
1569
1570 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001571 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001572
1573 return (got_x_error ? FAIL : OK);
1574}
1575#endif
1576
1577#ifdef FEAT_TITLE
1578
1579#ifdef FEAT_X11
1580
1581static int get_x11_thing __ARGS((int get_title, int test_only));
1582
1583/*
1584 * try to get x11 window and display
1585 *
1586 * return FAIL for failure, OK otherwise
1587 */
1588 static int
1589get_x11_windis()
1590{
1591 char *winid;
1592 static int result = -1;
1593#define XD_NONE 0 /* x11_display not set here */
1594#define XD_HERE 1 /* x11_display opened here */
1595#define XD_GUI 2 /* x11_display used from gui.dpy */
1596#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1597 static int x11_display_from = XD_NONE;
1598 static int did_set_error_handler = FALSE;
1599
1600 if (!did_set_error_handler)
1601 {
1602 /* X just exits if it finds an error otherwise! */
1603 (void)XSetErrorHandler(x_error_handler);
1604 did_set_error_handler = TRUE;
1605 }
1606
Bram Moolenaar9372a112005-12-06 19:59:18 +00001607#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001608 if (gui.in_use)
1609 {
1610 /*
1611 * If the X11 display was opened here before, for the window where Vim
1612 * was started, close that one now to avoid a memory leak.
1613 */
1614 if (x11_display_from == XD_HERE && x11_display != NULL)
1615 {
1616 XCloseDisplay(x11_display);
1617 x11_display_from = XD_NONE;
1618 }
1619 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1620 {
1621 x11_display_from = XD_GUI;
1622 return OK;
1623 }
1624 x11_display = NULL;
1625 return FAIL;
1626 }
1627 else if (x11_display_from == XD_GUI)
1628 {
1629 /* GUI must have stopped somehow, clear x11_display */
1630 x11_window = 0;
1631 x11_display = NULL;
1632 x11_display_from = XD_NONE;
1633 }
1634#endif
1635
1636 /* When started with the "-X" argument, don't try connecting. */
1637 if (!x_connect_to_server())
1638 return FAIL;
1639
1640 /*
1641 * If WINDOWID not set, should try another method to find out
1642 * what the current window number is. The only code I know for
1643 * this is very complicated.
1644 * We assume that zero is invalid for WINDOWID.
1645 */
1646 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1647 x11_window = (Window)atol(winid);
1648
1649#ifdef FEAT_XCLIPBOARD
1650 if (xterm_dpy != NULL && x11_window != 0)
1651 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001652 /* We may have checked it already, but Gnome terminal can move us to
1653 * another window, so we need to check every time. */
1654 if (x11_display_from != XD_XTERM)
1655 {
1656 /*
1657 * If the X11 display was opened here before, for the window where
1658 * Vim was started, close that one now to avoid a memory leak.
1659 */
1660 if (x11_display_from == XD_HERE && x11_display != NULL)
1661 XCloseDisplay(x11_display);
1662 x11_display = xterm_dpy;
1663 x11_display_from = XD_XTERM;
1664 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001665 if (test_x11_window(x11_display) == FAIL)
1666 {
1667 /* probably bad $WINDOWID */
1668 x11_window = 0;
1669 x11_display = NULL;
1670 x11_display_from = XD_NONE;
1671 return FAIL;
1672 }
1673 return OK;
1674 }
1675#endif
1676
1677 if (x11_window == 0 || x11_display == NULL)
1678 result = -1;
1679
1680 if (result != -1) /* Have already been here and set this */
1681 return result; /* Don't do all these X calls again */
1682
1683 if (x11_window != 0 && x11_display == NULL)
1684 {
1685#ifdef SET_SIG_ALARM
1686 RETSIGTYPE (*sig_save)();
1687#endif
1688#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1689 struct timeval start_tv;
1690
1691 if (p_verbose > 0)
1692 gettimeofday(&start_tv, NULL);
1693#endif
1694
1695#ifdef SET_SIG_ALARM
1696 /*
1697 * Opening the Display may hang if the DISPLAY setting is wrong, or
1698 * the network connection is bad. Set an alarm timer to get out.
1699 */
1700 sig_alarm_called = FALSE;
1701 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1702 (RETSIGTYPE (*)())sig_alarm);
1703 alarm(2);
1704#endif
1705 x11_display = XOpenDisplay(NULL);
1706
1707#ifdef SET_SIG_ALARM
1708 alarm(0);
1709 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1710 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001711 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001712#endif
1713 if (x11_display != NULL)
1714 {
1715# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1716 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001717 {
1718 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001719 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001720 verbose_leave();
1721 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001722# endif
1723 if (test_x11_window(x11_display) == FAIL)
1724 {
1725 /* Maybe window id is bad */
1726 x11_window = 0;
1727 XCloseDisplay(x11_display);
1728 x11_display = NULL;
1729 }
1730 else
1731 x11_display_from = XD_HERE;
1732 }
1733 }
1734 if (x11_window == 0 || x11_display == NULL)
1735 return (result = FAIL);
1736 return (result = OK);
1737}
1738
1739/*
1740 * Determine original x11 Window Title
1741 */
1742 static int
1743get_x11_title(test_only)
1744 int test_only;
1745{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001746 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001747}
1748
1749/*
1750 * Determine original x11 Window icon
1751 */
1752 static int
1753get_x11_icon(test_only)
1754 int test_only;
1755{
1756 int retval = FALSE;
1757
1758 retval = get_x11_thing(FALSE, test_only);
1759
1760 /* could not get old icon, use terminal name */
1761 if (oldicon == NULL && !test_only)
1762 {
1763 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001764 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001765 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001766 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001767 }
1768
1769 return retval;
1770}
1771
1772 static int
1773get_x11_thing(get_title, test_only)
1774 int get_title; /* get title string */
1775 int test_only;
1776{
1777 XTextProperty text_prop;
1778 int retval = FALSE;
1779 Status status;
1780
1781 if (get_x11_windis() == OK)
1782 {
1783 /* Get window/icon name if any */
1784 if (get_title)
1785 status = XGetWMName(x11_display, x11_window, &text_prop);
1786 else
1787 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1788
1789 /*
1790 * If terminal is xterm, then x11_window may be a child window of the
1791 * outer xterm window that actually contains the window/icon name, so
1792 * keep traversing up the tree until a window with a title/icon is
1793 * found.
1794 */
1795 /* Previously this was only done for xterm and alikes. I don't see a
1796 * reason why it would fail for other terminal emulators.
1797 * if (term_is_xterm) */
1798 {
1799 Window root;
1800 Window parent;
1801 Window win = x11_window;
1802 Window *children;
1803 unsigned int num_children;
1804
1805 while (!status || text_prop.value == NULL)
1806 {
1807 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1808 &num_children))
1809 break;
1810 if (children)
1811 XFree((void *)children);
1812 if (parent == root || parent == 0)
1813 break;
1814
1815 win = parent;
1816 if (get_title)
1817 status = XGetWMName(x11_display, win, &text_prop);
1818 else
1819 status = XGetWMIconName(x11_display, win, &text_prop);
1820 }
1821 }
1822 if (status && text_prop.value != NULL)
1823 {
1824 retval = TRUE;
1825 if (!test_only)
1826 {
1827#ifdef FEAT_XFONTSET
1828 if (text_prop.encoding == XA_STRING)
1829 {
1830#endif
1831 if (get_title)
1832 oldtitle = vim_strsave((char_u *)text_prop.value);
1833 else
1834 oldicon = vim_strsave((char_u *)text_prop.value);
1835#ifdef FEAT_XFONTSET
1836 }
1837 else
1838 {
1839 char **cl;
1840 Status transform_status;
1841 int n = 0;
1842
1843 transform_status = XmbTextPropertyToTextList(x11_display,
1844 &text_prop,
1845 &cl, &n);
1846 if (transform_status >= Success && n > 0 && cl[0])
1847 {
1848 if (get_title)
1849 oldtitle = vim_strsave((char_u *) cl[0]);
1850 else
1851 oldicon = vim_strsave((char_u *) cl[0]);
1852 XFreeStringList(cl);
1853 }
1854 else
1855 {
1856 if (get_title)
1857 oldtitle = vim_strsave((char_u *)text_prop.value);
1858 else
1859 oldicon = vim_strsave((char_u *)text_prop.value);
1860 }
1861 }
1862#endif
1863 }
1864 XFree((void *)text_prop.value);
1865 }
1866 }
1867 return retval;
1868}
1869
1870/* Are Xutf8 functions available? Avoid error from old compilers. */
1871#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1872# if X_HAVE_UTF8_STRING
1873# define USE_UTF8_STRING
1874# endif
1875#endif
1876
1877/*
1878 * Set x11 Window Title
1879 *
1880 * get_x11_windis() must be called before this and have returned OK
1881 */
1882 static void
1883set_x11_title(title)
1884 char_u *title;
1885{
1886 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1887 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1888 * supported everywhere and STRING doesn't work for multi-byte titles.
1889 */
1890#ifdef USE_UTF8_STRING
1891 if (enc_utf8)
1892 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1893 NULL, NULL, 0, NULL, NULL, NULL);
1894 else
1895#endif
1896 {
1897#if XtSpecificationRelease >= 4
1898# ifdef FEAT_XFONTSET
1899 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1900 NULL, NULL, 0, NULL, NULL, NULL);
1901# else
1902 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001903 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001904
1905 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001906 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001907 XSetWMProperties(x11_display, x11_window, &text_prop,
1908 NULL, NULL, 0, NULL, NULL, NULL);
1909# endif
1910#else
1911 XStoreName(x11_display, x11_window, (char *)title);
1912#endif
1913 }
1914 XFlush(x11_display);
1915}
1916
1917/*
1918 * Set x11 Window icon
1919 *
1920 * get_x11_windis() must be called before this and have returned OK
1921 */
1922 static void
1923set_x11_icon(icon)
1924 char_u *icon;
1925{
1926 /* See above for comments about using X*SetWMProperties(). */
1927#ifdef USE_UTF8_STRING
1928 if (enc_utf8)
1929 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1930 NULL, 0, NULL, NULL, NULL);
1931 else
1932#endif
1933 {
1934#if XtSpecificationRelease >= 4
1935# ifdef FEAT_XFONTSET
1936 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1937 NULL, 0, NULL, NULL, NULL);
1938# else
1939 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001940 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001942 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001943 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
1944 NULL, 0, NULL, NULL, NULL);
1945# endif
1946#else
1947 XSetIconName(x11_display, x11_window, (char *)icon);
1948#endif
1949 }
1950 XFlush(x11_display);
1951}
1952
1953#else /* FEAT_X11 */
1954
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955 static int
1956get_x11_title(test_only)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001957 int test_only UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001958{
1959 return FALSE;
1960}
1961
1962 static int
1963get_x11_icon(test_only)
1964 int test_only;
1965{
1966 if (!test_only)
1967 {
1968 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001969 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001970 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001971 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001972 }
1973 return FALSE;
1974}
1975
1976#endif /* FEAT_X11 */
1977
1978 int
1979mch_can_restore_title()
1980{
1981 return get_x11_title(TRUE);
1982}
1983
1984 int
1985mch_can_restore_icon()
1986{
1987 return get_x11_icon(TRUE);
1988}
1989
1990/*
1991 * Set the window title and icon.
1992 */
1993 void
1994mch_settitle(title, icon)
1995 char_u *title;
1996 char_u *icon;
1997{
1998 int type = 0;
1999 static int recursive = 0;
2000
2001 if (T_NAME == NULL) /* no terminal name (yet) */
2002 return;
2003 if (title == NULL && icon == NULL) /* nothing to do */
2004 return;
2005
2006 /* When one of the X11 functions causes a deadly signal, we get here again
2007 * recursively. Avoid hanging then (something is probably locked). */
2008 if (recursive)
2009 return;
2010 ++recursive;
2011
2012 /*
2013 * if the window ID and the display is known, we may use X11 calls
2014 */
2015#ifdef FEAT_X11
2016 if (get_x11_windis() == OK)
2017 type = 1;
2018#else
2019# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2020 if (gui.in_use)
2021 type = 1;
2022# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023#endif
2024
2025 /*
2026 * Note: if "t_TS" is set, title is set with escape sequence rather
2027 * than x11 calls, because the x11 calls don't always work
2028 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002029 if ((type || *T_TS != NUL) && title != NULL)
2030 {
2031 if (oldtitle == NULL
2032#ifdef FEAT_GUI
2033 && !gui.in_use
2034#endif
2035 ) /* first call but not in GUI, save title */
2036 (void)get_x11_title(FALSE);
2037
2038 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2039 term_settitle(title);
2040#ifdef FEAT_X11
2041 else
2042# ifdef FEAT_GUI_GTK
2043 if (!gui.in_use) /* don't do this if GTK+ is running */
2044# endif
2045 set_x11_title(title); /* x11 */
2046#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002047#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002048 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2049 else
2050 gui_mch_settitle(title, icon);
2051#endif
2052 did_set_title = TRUE;
2053 }
2054
2055 if ((type || *T_CIS != NUL) && icon != NULL)
2056 {
2057 if (oldicon == NULL
2058#ifdef FEAT_GUI
2059 && !gui.in_use
2060#endif
2061 ) /* first call, save icon */
2062 get_x11_icon(FALSE);
2063
2064 if (*T_CIS != NUL)
2065 {
2066 out_str(T_CIS); /* set icon start */
2067 out_str_nf(icon);
2068 out_str(T_CIE); /* set icon end */
2069 out_flush();
2070 }
2071#ifdef FEAT_X11
2072 else
2073# ifdef FEAT_GUI_GTK
2074 if (!gui.in_use) /* don't do this if GTK+ is running */
2075# endif
2076 set_x11_icon(icon); /* x11 */
2077#endif
2078 did_set_icon = TRUE;
2079 }
2080 --recursive;
2081}
2082
2083/*
2084 * Restore the window/icon title.
2085 * "which" is one of:
2086 * 1 only restore title
2087 * 2 only restore icon
2088 * 3 restore title and icon
2089 */
2090 void
2091mch_restore_title(which)
2092 int which;
2093{
2094 /* only restore the title or icon when it has been set */
2095 mch_settitle(((which & 1) && did_set_title) ?
2096 (oldtitle ? oldtitle : p_titleold) : NULL,
2097 ((which & 2) && did_set_icon) ? oldicon : NULL);
2098}
2099
2100#endif /* FEAT_TITLE */
2101
2102/*
2103 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002104 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002105 */
2106 int
2107vim_is_xterm(name)
2108 char_u *name;
2109{
2110 if (name == NULL)
2111 return FALSE;
2112 return (STRNICMP(name, "xterm", 5) == 0
2113 || STRNICMP(name, "nxterm", 6) == 0
2114 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002115 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002116 || STRNICMP(name, "rxvt", 4) == 0
2117 || STRCMP(name, "builtin_xterm") == 0);
2118}
2119
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002120#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2121/*
2122 * Return TRUE if "name" appears to be that of a terminal
2123 * known to support the xterm-style mouse protocol.
2124 * Relies on term_is_xterm having been set to its correct value.
2125 */
2126 int
2127use_xterm_like_mouse(name)
2128 char_u *name;
2129{
2130 return (name != NULL
2131 && (term_is_xterm || STRNICMP(name, "screen", 6) == 0));
2132}
2133#endif
2134
Bram Moolenaar071d4272004-06-13 20:20:40 +00002135#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2136/*
2137 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2138 * Return 1 for "xterm".
2139 * Return 2 for "xterm2".
2140 */
2141 int
2142use_xterm_mouse()
2143{
2144 if (ttym_flags == TTYM_XTERM2)
2145 return 2;
2146 if (ttym_flags == TTYM_XTERM)
2147 return 1;
2148 return 0;
2149}
2150#endif
2151
2152 int
2153vim_is_iris(name)
2154 char_u *name;
2155{
2156 if (name == NULL)
2157 return FALSE;
2158 return (STRNICMP(name, "iris-ansi", 9) == 0
2159 || STRCMP(name, "builtin_iris-ansi") == 0);
2160}
2161
2162 int
2163vim_is_vt300(name)
2164 char_u *name;
2165{
2166 if (name == NULL)
2167 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002168 /* catch VT100 - VT5xx */
2169 return ((STRNICMP(name, "vt", 2) == 0
2170 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002171 || STRCMP(name, "builtin_vt320") == 0);
2172}
2173
2174/*
2175 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2176 * This should include all windowed terminal emulators.
2177 */
2178 int
2179vim_is_fastterm(name)
2180 char_u *name;
2181{
2182 if (name == NULL)
2183 return FALSE;
2184 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2185 return TRUE;
2186 return ( STRNICMP(name, "hpterm", 6) == 0
2187 || STRNICMP(name, "sun-cmd", 7) == 0
2188 || STRNICMP(name, "screen", 6) == 0
2189 || STRNICMP(name, "dtterm", 6) == 0);
2190}
2191
2192/*
2193 * Insert user name in s[len].
2194 * Return OK if a name found.
2195 */
2196 int
2197mch_get_user_name(s, len)
2198 char_u *s;
2199 int len;
2200{
2201#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002202 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002203 return OK;
2204#else
2205 return mch_get_uname(getuid(), s, len);
2206#endif
2207}
2208
2209/*
2210 * Insert user name for "uid" in s[len].
2211 * Return OK if a name found.
2212 */
2213 int
2214mch_get_uname(uid, s, len)
2215 uid_t uid;
2216 char_u *s;
2217 int len;
2218{
2219#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2220 struct passwd *pw;
2221
2222 if ((pw = getpwuid(uid)) != NULL
2223 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2224 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002225 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002226 return OK;
2227 }
2228#endif
2229 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2230 return FAIL; /* a number is not a name */
2231}
2232
2233/*
2234 * Insert host name is s[len].
2235 */
2236
2237#ifdef HAVE_SYS_UTSNAME_H
2238 void
2239mch_get_host_name(s, len)
2240 char_u *s;
2241 int len;
2242{
2243 struct utsname vutsname;
2244
2245 if (uname(&vutsname) < 0)
2246 *s = NUL;
2247 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002248 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249}
2250#else /* HAVE_SYS_UTSNAME_H */
2251
2252# ifdef HAVE_SYS_SYSTEMINFO_H
2253# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2254# endif
2255
2256 void
2257mch_get_host_name(s, len)
2258 char_u *s;
2259 int len;
2260{
2261# ifdef VAXC
2262 vaxc$gethostname((char *)s, len);
2263# else
2264 gethostname((char *)s, len);
2265# endif
2266 s[len - 1] = NUL; /* make sure it's terminated */
2267}
2268#endif /* HAVE_SYS_UTSNAME_H */
2269
2270/*
2271 * return process ID
2272 */
2273 long
2274mch_get_pid()
2275{
2276 return (long)getpid();
2277}
2278
2279#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2280static char *strerror __ARGS((int));
2281
2282 static char *
2283strerror(err)
2284 int err;
2285{
2286 extern int sys_nerr;
2287 extern char *sys_errlist[];
2288 static char er[20];
2289
2290 if (err > 0 && err < sys_nerr)
2291 return (sys_errlist[err]);
2292 sprintf(er, "Error %d", err);
2293 return er;
2294}
2295#endif
2296
2297/*
2298 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2299 * Return OK for success, FAIL for failure.
2300 */
2301 int
2302mch_dirname(buf, len)
2303 char_u *buf;
2304 int len;
2305{
2306#if defined(USE_GETCWD)
2307 if (getcwd((char *)buf, len) == NULL)
2308 {
2309 STRCPY(buf, strerror(errno));
2310 return FAIL;
2311 }
2312 return OK;
2313#else
2314 return (getwd((char *)buf) != NULL ? OK : FAIL);
2315#endif
2316}
2317
2318#if defined(OS2) || defined(PROTO)
2319/*
2320 * Replace all slashes by backslashes.
2321 * When 'shellslash' set do it the other way around.
2322 */
2323 void
2324slash_adjust(p)
2325 char_u *p;
2326{
2327 while (*p)
2328 {
2329 if (*p == psepcN)
2330 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002331 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332 }
2333}
2334#endif
2335
2336/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002337 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002338 *
2339 * return FAIL for failure, OK for success
2340 */
2341 int
2342mch_FullName(fname, buf, len, force)
2343 char_u *fname, *buf;
2344 int len;
2345 int force; /* also expand when already absolute path */
2346{
2347 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002348#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002349 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002350#endif
2351#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352 int fd = -1;
2353 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002354#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002355 char_u olddir[MAXPATHL];
2356 char_u *p;
2357 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002358#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002359 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2360 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002361#endif
2362
Bram Moolenaar38323e42007-03-06 19:22:53 +00002363#ifdef VMS
2364 fname = vms_fixfilename(fname);
2365#endif
2366
Bram Moolenaara2442432007-04-26 14:26:37 +00002367#ifdef __CYGWIN__
2368 /*
2369 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2370 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002371# if CYGWIN_VERSION_DLL_MAJOR >= 1007
2372 cygwin_conv_path(CCP_WIN_A_TO_POSIX, fname, posix_fname, MAXPATHL);
2373# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002374 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002375# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002376 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002377#endif
2378
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379 /* expand it if forced or not an absolute path */
2380 if (force || !mch_isFullName(fname))
2381 {
2382 /*
2383 * If the file name has a path, change to that directory for a moment,
2384 * and then do the getwd() (and get back to where we were).
2385 * This will get the correct path name with "../" things.
2386 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002387#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 only_drive = 0;
2389 if (((p = vim_strrchr(fname, '/')) != NULL)
2390 || ((p = vim_strrchr(fname, '\\')) != NULL)
2391 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002392#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002394#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002395 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002396#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002397 /*
2398 * Use fchdir() if possible, it's said to be faster and more
2399 * reliable. But on SunOS 4 it might not work. Check this by
2400 * doing a fchdir() right now.
2401 */
2402 if (!dont_fchdir)
2403 {
2404 fd = open(".", O_RDONLY | O_EXTRA, 0);
2405 if (fd >= 0 && fchdir(fd) < 0)
2406 {
2407 close(fd);
2408 fd = -1;
2409 dont_fchdir = TRUE; /* don't try again */
2410 }
2411 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002412#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002413
2414 /* Only change directory when we are sure we can return to where
2415 * we are now. After doing "su" chdir(".") might not work. */
2416 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002417#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002418 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002419#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002420 (mch_dirname(olddir, MAXPATHL) == FAIL
2421 || mch_chdir((char *)olddir) != 0))
2422 {
2423 p = NULL; /* can't get current dir: don't chdir */
2424 retval = FAIL;
2425 }
2426 else
2427 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002428#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002429 /*
2430 * compensate for case where ':' from "D:" was the only
2431 * path separator detected in the file name; the _next_
2432 * character has to be removed, and then restored later.
2433 */
2434 if (only_drive)
2435 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002436#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002437 /* The directory is copied into buf[], to be able to remove
2438 * the file name without changing it (could be a string in
2439 * read-only memory) */
2440 if (p - fname >= len)
2441 retval = FAIL;
2442 else
2443 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002444 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002445 if (mch_chdir((char *)buf))
2446 retval = FAIL;
2447 else
2448 fname = p + 1;
2449 *buf = NUL;
2450 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002451#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002452 if (only_drive)
2453 {
2454 p--;
2455 if (retval != FAIL)
2456 fname--;
2457 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002458#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002459 }
2460 }
2461 if (mch_dirname(buf, len) == FAIL)
2462 {
2463 retval = FAIL;
2464 *buf = NUL;
2465 }
2466 if (p != NULL)
2467 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002468#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002469 if (fd >= 0)
2470 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002471 if (p_verbose >= 5)
2472 {
2473 verbose_enter();
2474 MSG("fchdir() to previous dir");
2475 verbose_leave();
2476 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 l = fchdir(fd);
2478 close(fd);
2479 }
2480 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002481#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 l = mch_chdir((char *)olddir);
2483 if (l != 0)
2484 EMSG(_(e_prev_dir));
2485 }
2486
2487 l = STRLEN(buf);
2488 if (l >= len)
2489 retval = FAIL;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002490#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002491 else
2492 {
2493 if (l > 0 && buf[l - 1] != '/' && *fname != NUL
2494 && STRCMP(fname, ".") != 0)
2495 STRCAT(buf, "/");
2496 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002497#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002498 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002499
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002501 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002502 return FAIL;
2503
2504 /* Do not append ".", "/dir/." is equal to "/dir". */
2505 if (STRCMP(fname, ".") != 0)
2506 STRCAT(buf, fname);
2507
2508 return OK;
2509}
2510
2511/*
2512 * Return TRUE if "fname" does not depend on the current directory.
2513 */
2514 int
2515mch_isFullName(fname)
2516 char_u *fname;
2517{
2518#ifdef __EMX__
2519 return _fnisabs(fname);
2520#else
2521# ifdef VMS
2522 return ( fname[0] == '/' || fname[0] == '.' ||
2523 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2524 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2525 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2526# else
2527 return (*fname == '/' || *fname == '~');
2528# endif
2529#endif
2530}
2531
Bram Moolenaar24552be2005-12-10 20:17:30 +00002532#if defined(USE_FNAME_CASE) || defined(PROTO)
2533/*
2534 * Set the case of the file name, if it already exists. This will cause the
2535 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002536 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002537 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002538 void
2539fname_case(name, len)
2540 char_u *name;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002541 int len UNUSED; /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002542{
2543 struct stat st;
2544 char_u *slash, *tail;
2545 DIR *dirp;
2546 struct dirent *dp;
2547
2548 if (lstat((char *)name, &st) >= 0)
2549 {
2550 /* Open the directory where the file is located. */
2551 slash = vim_strrchr(name, '/');
2552 if (slash == NULL)
2553 {
2554 dirp = opendir(".");
2555 tail = name;
2556 }
2557 else
2558 {
2559 *slash = NUL;
2560 dirp = opendir((char *)name);
2561 *slash = '/';
2562 tail = slash + 1;
2563 }
2564
2565 if (dirp != NULL)
2566 {
2567 while ((dp = readdir(dirp)) != NULL)
2568 {
2569 /* Only accept names that differ in case and are the same byte
2570 * length. TODO: accept different length name. */
2571 if (STRICMP(tail, dp->d_name) == 0
2572 && STRLEN(tail) == STRLEN(dp->d_name))
2573 {
2574 char_u newname[MAXPATHL + 1];
2575 struct stat st2;
2576
2577 /* Verify the inode is equal. */
2578 vim_strncpy(newname, name, MAXPATHL);
2579 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2580 MAXPATHL - (tail - name));
2581 if (lstat((char *)newname, &st2) >= 0
2582 && st.st_ino == st2.st_ino
2583 && st.st_dev == st2.st_dev)
2584 {
2585 STRCPY(tail, dp->d_name);
2586 break;
2587 }
2588 }
2589 }
2590
2591 closedir(dirp);
2592 }
2593 }
2594}
2595#endif
2596
Bram Moolenaar071d4272004-06-13 20:20:40 +00002597/*
2598 * Get file permissions for 'name'.
2599 * Returns -1 when it doesn't exist.
2600 */
2601 long
2602mch_getperm(name)
2603 char_u *name;
2604{
2605 struct stat statb;
2606
2607 /* Keep the #ifdef outside of stat(), it may be a macro. */
2608#ifdef VMS
2609 if (stat((char *)vms_fixfilename(name), &statb))
2610#else
2611 if (stat((char *)name, &statb))
2612#endif
2613 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002614#ifdef __INTERIX
2615 /* The top bit makes the value negative, which means the file doesn't
2616 * exist. Remove the bit, we don't use it. */
2617 return statb.st_mode & ~S_ADDACE;
2618#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002619 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002620#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002621}
2622
2623/*
2624 * set file permission for 'name' to 'perm'
2625 *
2626 * return FAIL for failure, OK otherwise
2627 */
2628 int
2629mch_setperm(name, perm)
2630 char_u *name;
2631 long perm;
2632{
2633 return (chmod((char *)
2634#ifdef VMS
2635 vms_fixfilename(name),
2636#else
2637 name,
2638#endif
2639 (mode_t)perm) == 0 ? OK : FAIL);
2640}
2641
2642#if defined(HAVE_ACL) || defined(PROTO)
2643# ifdef HAVE_SYS_ACL_H
2644# include <sys/acl.h>
2645# endif
2646# ifdef HAVE_SYS_ACCESS_H
2647# include <sys/access.h>
2648# endif
2649
2650# ifdef HAVE_SOLARIS_ACL
2651typedef struct vim_acl_solaris_T {
2652 int acl_cnt;
2653 aclent_t *acl_entry;
2654} vim_acl_solaris_T;
2655# endif
2656
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002657#if defined(HAVE_SELINUX) || defined(PROTO)
2658/*
2659 * Copy security info from "from_file" to "to_file".
2660 */
2661 void
2662mch_copy_sec(from_file, to_file)
2663 char_u *from_file;
2664 char_u *to_file;
2665{
2666 if (from_file == NULL)
2667 return;
2668
2669 if (selinux_enabled == -1)
2670 selinux_enabled = is_selinux_enabled();
2671
2672 if (selinux_enabled > 0)
2673 {
2674 security_context_t from_context = NULL;
2675 security_context_t to_context = NULL;
2676
2677 if (getfilecon((char *)from_file, &from_context) < 0)
2678 {
2679 /* If the filesystem doesn't support extended attributes,
2680 the original had no special security context and the
2681 target cannot have one either. */
2682 if (errno == EOPNOTSUPP)
2683 return;
2684
2685 MSG_PUTS(_("\nCould not get security context for "));
2686 msg_outtrans(from_file);
2687 msg_putchar('\n');
2688 return;
2689 }
2690 if (getfilecon((char *)to_file, &to_context) < 0)
2691 {
2692 MSG_PUTS(_("\nCould not get security context for "));
2693 msg_outtrans(to_file);
2694 msg_putchar('\n');
2695 freecon (from_context);
2696 return ;
2697 }
2698 if (strcmp(from_context, to_context) != 0)
2699 {
2700 if (setfilecon((char *)to_file, from_context) < 0)
2701 {
2702 MSG_PUTS(_("\nCould not set security context for "));
2703 msg_outtrans(to_file);
2704 msg_putchar('\n');
2705 }
2706 }
2707 freecon(to_context);
2708 freecon(from_context);
2709 }
2710}
2711#endif /* HAVE_SELINUX */
2712
Bram Moolenaar071d4272004-06-13 20:20:40 +00002713/*
2714 * Return a pointer to the ACL of file "fname" in allocated memory.
2715 * Return NULL if the ACL is not available for whatever reason.
2716 */
2717 vim_acl_T
2718mch_get_acl(fname)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002719 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002720{
2721 vim_acl_T ret = NULL;
2722#ifdef HAVE_POSIX_ACL
2723 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2724#else
2725#ifdef HAVE_SOLARIS_ACL
2726 vim_acl_solaris_T *aclent;
2727
2728 aclent = malloc(sizeof(vim_acl_solaris_T));
2729 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2730 {
2731 free(aclent);
2732 return NULL;
2733 }
2734 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2735 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2736 {
2737 free(aclent->acl_entry);
2738 free(aclent);
2739 return NULL;
2740 }
2741 ret = (vim_acl_T)aclent;
2742#else
2743#if defined(HAVE_AIX_ACL)
2744 int aclsize;
2745 struct acl *aclent;
2746
2747 aclsize = sizeof(struct acl);
2748 aclent = malloc(aclsize);
2749 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2750 {
2751 if (errno == ENOSPC)
2752 {
2753 aclsize = aclent->acl_len;
2754 aclent = realloc(aclent, aclsize);
2755 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2756 {
2757 free(aclent);
2758 return NULL;
2759 }
2760 }
2761 else
2762 {
2763 free(aclent);
2764 return NULL;
2765 }
2766 }
2767 ret = (vim_acl_T)aclent;
2768#endif /* HAVE_AIX_ACL */
2769#endif /* HAVE_SOLARIS_ACL */
2770#endif /* HAVE_POSIX_ACL */
2771 return ret;
2772}
2773
2774/*
2775 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2776 */
2777 void
2778mch_set_acl(fname, aclent)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002779 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002780 vim_acl_T aclent;
2781{
2782 if (aclent == NULL)
2783 return;
2784#ifdef HAVE_POSIX_ACL
2785 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2786#else
2787#ifdef HAVE_SOLARIS_ACL
2788 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2789 ((vim_acl_solaris_T *)aclent)->acl_entry);
2790#else
2791#ifdef HAVE_AIX_ACL
2792 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2793#endif /* HAVE_AIX_ACL */
2794#endif /* HAVE_SOLARIS_ACL */
2795#endif /* HAVE_POSIX_ACL */
2796}
2797
2798 void
2799mch_free_acl(aclent)
2800 vim_acl_T aclent;
2801{
2802 if (aclent == NULL)
2803 return;
2804#ifdef HAVE_POSIX_ACL
2805 acl_free((acl_t)aclent);
2806#else
2807#ifdef HAVE_SOLARIS_ACL
2808 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2809 free(aclent);
2810#else
2811#ifdef HAVE_AIX_ACL
2812 free(aclent);
2813#endif /* HAVE_AIX_ACL */
2814#endif /* HAVE_SOLARIS_ACL */
2815#endif /* HAVE_POSIX_ACL */
2816}
2817#endif
2818
2819/*
2820 * Set hidden flag for "name".
2821 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002822 void
2823mch_hide(name)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002824 char_u *name UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002825{
2826 /* can't hide a file */
2827}
2828
2829/*
2830 * return TRUE if "name" is a directory
2831 * return FALSE if "name" is not a directory
2832 * return FALSE for error
2833 */
2834 int
2835mch_isdir(name)
2836 char_u *name;
2837{
2838 struct stat statb;
2839
2840 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2841 return FALSE;
2842 if (stat((char *)name, &statb))
2843 return FALSE;
2844#ifdef _POSIX_SOURCE
2845 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2846#else
2847 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2848#endif
2849}
2850
Bram Moolenaar071d4272004-06-13 20:20:40 +00002851static int executable_file __ARGS((char_u *name));
2852
2853/*
2854 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2855 */
2856 static int
2857executable_file(name)
2858 char_u *name;
2859{
2860 struct stat st;
2861
2862 if (stat((char *)name, &st))
2863 return 0;
2864 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2865}
2866
2867/*
2868 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2869 * Return -1 if unknown.
2870 */
2871 int
2872mch_can_exe(name)
2873 char_u *name;
2874{
2875 char_u *buf;
2876 char_u *p, *e;
2877 int retval;
2878
2879 /* If it's an absolute or relative path don't need to use $PATH. */
2880 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2881 || (name[1] == '.' && name[2] == '/'))))
2882 return executable_file(name);
2883
2884 p = (char_u *)getenv("PATH");
2885 if (p == NULL || *p == NUL)
2886 return -1;
2887 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2888 if (buf == NULL)
2889 return -1;
2890
2891 /*
2892 * Walk through all entries in $PATH to check if "name" exists there and
2893 * is an executable file.
2894 */
2895 for (;;)
2896 {
2897 e = (char_u *)strchr((char *)p, ':');
2898 if (e == NULL)
2899 e = p + STRLEN(p);
2900 if (e - p <= 1) /* empty entry means current dir */
2901 STRCPY(buf, "./");
2902 else
2903 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002904 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002905 add_pathsep(buf);
2906 }
2907 STRCAT(buf, name);
2908 retval = executable_file(buf);
2909 if (retval == 1)
2910 break;
2911
2912 if (*e != ':')
2913 break;
2914 p = e + 1;
2915 }
2916
2917 vim_free(buf);
2918 return retval;
2919}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002920
2921/*
2922 * Check what "name" is:
2923 * NODE_NORMAL: file or directory (or doesn't exist)
2924 * NODE_WRITABLE: writable device, socket, fifo, etc.
2925 * NODE_OTHER: non-writable things
2926 */
2927 int
2928mch_nodetype(name)
2929 char_u *name;
2930{
2931 struct stat st;
2932
2933 if (stat((char *)name, &st))
2934 return NODE_NORMAL;
2935 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2936 return NODE_NORMAL;
2937#ifndef OS2
2938 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2939 return NODE_OTHER;
2940#endif
2941 /* Everything else is writable? */
2942 return NODE_WRITABLE;
2943}
2944
2945 void
2946mch_early_init()
2947{
2948#ifdef HAVE_CHECK_STACK_GROWTH
2949 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950
Bram Moolenaar071d4272004-06-13 20:20:40 +00002951 check_stack_growth((char *)&i);
2952
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002953# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954 get_stack_limit();
2955# endif
2956
2957#endif
2958
2959 /*
2960 * Setup an alternative stack for signals. Helps to catch signals when
2961 * running out of stack space.
2962 * Use of sigaltstack() is preferred, it's more portable.
2963 * Ignore any errors.
2964 */
2965#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00002966 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967 init_signal_stack();
2968#endif
2969}
2970
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002971#if defined(EXITFREE) || defined(PROTO)
2972 void
2973mch_free_mem()
2974{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002975# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2976 if (clip_star.owned)
2977 clip_lose_selection(&clip_star);
2978 if (clip_plus.owned)
2979 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002980# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00002981# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002982 if (xterm_Shell != (Widget)0)
2983 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00002984# ifndef LESSTIF_VERSION
2985 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002986 if (xterm_dpy != NULL)
2987 XtCloseDisplay(xterm_dpy);
2988 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00002989 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002990 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00002991# ifdef FEAT_X11
2992 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
2993# endif
2994 }
2995# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002996# endif
Bram Moolenaara8785102008-11-12 13:10:15 +00002997 /* Don't close the display for GTK 1, it is done in exit(). */
2998# if defined(FEAT_X11) && (!defined(FEAT_GUI_GTK) || defined(HAVE_GTK2))
Bram Moolenaare8208012008-06-20 09:59:25 +00002999 if (x11_display != NULL
3000# ifdef FEAT_XCLIPBOARD
3001 && x11_display != xterm_dpy
3002# endif
3003 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003004 XCloseDisplay(x11_display);
3005# endif
3006# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
3007 vim_free(signal_stack);
3008 signal_stack = NULL;
3009# endif
3010# ifdef FEAT_TITLE
3011 vim_free(oldtitle);
3012 vim_free(oldicon);
3013# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003014}
3015#endif
3016
Bram Moolenaar071d4272004-06-13 20:20:40 +00003017static void exit_scroll __ARGS((void));
3018
3019/*
3020 * Output a newline when exiting.
3021 * Make sure the newline goes to the same stream as the text.
3022 */
3023 static void
3024exit_scroll()
3025{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003026 if (silent_mode)
3027 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003028 if (newline_on_exit || msg_didout)
3029 {
3030 if (msg_use_printf())
3031 {
3032 if (info_message)
3033 mch_msg("\n");
3034 else
3035 mch_errmsg("\r\n");
3036 }
3037 else
3038 out_char('\n');
3039 }
3040 else
3041 {
3042 restore_cterm_colors(); /* get original colors back */
3043 msg_clr_eos_force(); /* clear the rest of the display */
3044 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3045 }
3046}
3047
3048 void
3049mch_exit(r)
3050 int r;
3051{
3052 exiting = TRUE;
3053
3054#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3055 x11_export_final_selection();
3056#endif
3057
3058#ifdef FEAT_GUI
3059 if (!gui.in_use)
3060#endif
3061 {
3062 settmode(TMODE_COOK);
3063#ifdef FEAT_TITLE
3064 mch_restore_title(3); /* restore xterm title and icon name */
3065#endif
3066 /*
3067 * When t_ti is not empty but it doesn't cause swapping terminal
3068 * pages, need to output a newline when msg_didout is set. But when
3069 * t_ti does swap pages it should not go to the shell page. Do this
3070 * before stoptermcap().
3071 */
3072 if (swapping_screen() && !newline_on_exit)
3073 exit_scroll();
3074
3075 /* Stop termcap: May need to check for T_CRV response, which
3076 * requires RAW mode. */
3077 stoptermcap();
3078
3079 /*
3080 * A newline is only required after a message in the alternate screen.
3081 * This is set to TRUE by wait_return().
3082 */
3083 if (!swapping_screen() || newline_on_exit)
3084 exit_scroll();
3085
3086 /* Cursor may have been switched off without calling starttermcap()
3087 * when doing "vim -u vimrc" and vimrc contains ":q". */
3088 if (full_screen)
3089 cursor_on();
3090 }
3091 out_flush();
3092 ml_close_all(TRUE); /* remove all memfiles */
3093 may_core_dump();
3094#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003095 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003096 gui_exit(r);
3097#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003098
Bram Moolenaar56718732006-03-15 22:53:57 +00003099#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003100 mac_conv_cleanup();
3101#endif
3102
Bram Moolenaar071d4272004-06-13 20:20:40 +00003103#ifdef __QNX__
3104 /* A core dump won't be created if the signal handler
3105 * doesn't return, so we can't call exit() */
3106 if (deadly_signal != 0)
3107 return;
3108#endif
3109
Bram Moolenaar009b2592004-10-24 19:18:58 +00003110#ifdef FEAT_NETBEANS_INTG
3111 if (usingNetbeans)
3112 netbeans_send_disconnect();
3113#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003114
3115#ifdef EXITFREE
3116 free_all_mem();
3117#endif
3118
Bram Moolenaar071d4272004-06-13 20:20:40 +00003119 exit(r);
3120}
3121
3122 static void
3123may_core_dump()
3124{
3125 if (deadly_signal != 0)
3126 {
3127 signal(deadly_signal, SIG_DFL);
3128 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3129 }
3130}
3131
3132#ifndef VMS
3133
3134 void
3135mch_settmode(tmode)
3136 int tmode;
3137{
3138 static int first = TRUE;
3139
3140 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3141#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3142 /*
3143 * for "new" tty systems
3144 */
3145# ifdef HAVE_TERMIOS_H
3146 static struct termios told;
3147 struct termios tnew;
3148# else
3149 static struct termio told;
3150 struct termio tnew;
3151# endif
3152
3153 if (first)
3154 {
3155 first = FALSE;
3156# if defined(HAVE_TERMIOS_H)
3157 tcgetattr(read_cmd_fd, &told);
3158# else
3159 ioctl(read_cmd_fd, TCGETA, &told);
3160# endif
3161 }
3162
3163 tnew = told;
3164 if (tmode == TMODE_RAW)
3165 {
3166 /*
3167 * ~ICRNL enables typing ^V^M
3168 */
3169 tnew.c_iflag &= ~ICRNL;
3170 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3171# if defined(IEXTEN) && !defined(__MINT__)
3172 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3173 /* but it breaks function keys on MINT */
3174# endif
3175 );
3176# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3177 tnew.c_oflag &= ~ONLCR;
3178# endif
3179 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3180 tnew.c_cc[VTIME] = 0; /* don't wait */
3181 }
3182 else if (tmode == TMODE_SLEEP)
3183 tnew.c_lflag &= ~(ECHO);
3184
3185# if defined(HAVE_TERMIOS_H)
3186 {
3187 int n = 10;
3188
3189 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3190 * few times. */
3191 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3192 && errno == EINTR && n > 0)
3193 --n;
3194 }
3195# else
3196 ioctl(read_cmd_fd, TCSETA, &tnew);
3197# endif
3198
3199#else
3200
3201 /*
3202 * for "old" tty systems
3203 */
3204# ifndef TIOCSETN
3205# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3206# endif
3207 static struct sgttyb ttybold;
3208 struct sgttyb ttybnew;
3209
3210 if (first)
3211 {
3212 first = FALSE;
3213 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3214 }
3215
3216 ttybnew = ttybold;
3217 if (tmode == TMODE_RAW)
3218 {
3219 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3220 ttybnew.sg_flags |= RAW;
3221 }
3222 else if (tmode == TMODE_SLEEP)
3223 ttybnew.sg_flags &= ~(ECHO);
3224 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3225#endif
3226 curr_tmode = tmode;
3227}
3228
3229/*
3230 * Try to get the code for "t_kb" from the stty setting
3231 *
3232 * Even if termcap claims a backspace key, the user's setting *should*
3233 * prevail. stty knows more about reality than termcap does, and if
3234 * somebody's usual erase key is DEL (which, for most BSD users, it will
3235 * be), they're going to get really annoyed if their erase key starts
3236 * doing forward deletes for no reason. (Eric Fischer)
3237 */
3238 void
3239get_stty()
3240{
3241 char_u buf[2];
3242 char_u *p;
3243
3244 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3245#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3246 /* for "new" tty systems */
3247# ifdef HAVE_TERMIOS_H
3248 struct termios keys;
3249# else
3250 struct termio keys;
3251# endif
3252
3253# if defined(HAVE_TERMIOS_H)
3254 if (tcgetattr(read_cmd_fd, &keys) != -1)
3255# else
3256 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3257# endif
3258 {
3259 buf[0] = keys.c_cc[VERASE];
3260 intr_char = keys.c_cc[VINTR];
3261#else
3262 /* for "old" tty systems */
3263 struct sgttyb keys;
3264
3265 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3266 {
3267 buf[0] = keys.sg_erase;
3268 intr_char = keys.sg_kill;
3269#endif
3270 buf[1] = NUL;
3271 add_termcode((char_u *)"kb", buf, FALSE);
3272
3273 /*
3274 * If <BS> and <DEL> are now the same, redefine <DEL>.
3275 */
3276 p = find_termcode((char_u *)"kD");
3277 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3278 do_fixdel(NULL);
3279 }
3280#if 0
3281 } /* to keep cindent happy */
3282#endif
3283}
3284
3285#endif /* VMS */
3286
3287#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3288/*
3289 * Set mouse clicks on or off.
3290 */
3291 void
3292mch_setmouse(on)
3293 int on;
3294{
3295 static int ison = FALSE;
3296 int xterm_mouse_vers;
3297
3298 if (on == ison) /* return quickly if nothing to do */
3299 return;
3300
3301 xterm_mouse_vers = use_xterm_mouse();
3302 if (xterm_mouse_vers > 0)
3303 {
3304 if (on) /* enable mouse events, use mouse tracking if available */
3305 out_str_nf((char_u *)
3306 (xterm_mouse_vers > 1
3307 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3308 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3309 else /* disable mouse events, could probably always send the same */
3310 out_str_nf((char_u *)
3311 (xterm_mouse_vers > 1
3312 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3313 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3314 ison = on;
3315 }
3316
3317# ifdef FEAT_MOUSE_DEC
3318 else if (ttym_flags == TTYM_DEC)
3319 {
3320 if (on) /* enable mouse events */
3321 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3322 else /* disable mouse events */
3323 out_str_nf((char_u *)"\033['z");
3324 ison = on;
3325 }
3326# endif
3327
3328# ifdef FEAT_MOUSE_GPM
3329 else
3330 {
3331 if (on)
3332 {
3333 if (gpm_open())
3334 ison = TRUE;
3335 }
3336 else
3337 {
3338 gpm_close();
3339 ison = FALSE;
3340 }
3341 }
3342# endif
3343
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003344# ifdef FEAT_SYSMOUSE
3345 else
3346 {
3347 if (on)
3348 {
3349 if (sysmouse_open() == OK)
3350 ison = TRUE;
3351 }
3352 else
3353 {
3354 sysmouse_close();
3355 ison = FALSE;
3356 }
3357 }
3358# endif
3359
Bram Moolenaar071d4272004-06-13 20:20:40 +00003360# ifdef FEAT_MOUSE_JSB
3361 else
3362 {
3363 if (on)
3364 {
3365 /* D - Enable Mouse up/down messages
3366 * L - Enable Left Button Reporting
3367 * M - Enable Middle Button Reporting
3368 * R - Enable Right Button Reporting
3369 * K - Enable SHIFT and CTRL key Reporting
3370 * + - Enable Advanced messaging of mouse moves and up/down messages
3371 * Q - Quiet No Ack
3372 * # - Numeric value of mouse pointer required
3373 * 0 = Multiview 2000 cursor, used as standard
3374 * 1 = Windows Arrow
3375 * 2 = Windows I Beam
3376 * 3 = Windows Hour Glass
3377 * 4 = Windows Cross Hair
3378 * 5 = Windows UP Arrow
3379 */
3380#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3381 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3382 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3383#else
3384 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3385 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3386#endif
3387 ison = TRUE;
3388 }
3389 else
3390 {
3391 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3392 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3393 ison = FALSE;
3394 }
3395 }
3396# endif
3397# ifdef FEAT_MOUSE_PTERM
3398 else
3399 {
3400 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3401 if (on)
3402 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3403 else
3404 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3405 ison = on;
3406 }
3407# endif
3408}
3409
3410/*
3411 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3412 */
3413 void
3414check_mouse_termcode()
3415{
3416# ifdef FEAT_MOUSE_XTERM
3417 if (use_xterm_mouse()
3418# ifdef FEAT_GUI
3419 && !gui.in_use
3420# endif
3421 )
3422 {
3423 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003424 ? IF_EB("\233M", CSI_STR "M")
3425 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003426 if (*p_mouse != NUL)
3427 {
3428 /* force mouse off and maybe on to send possibly new mouse
3429 * activation sequence to the xterm, with(out) drag tracing. */
3430 mch_setmouse(FALSE);
3431 setmouse();
3432 }
3433 }
3434 else
3435 del_mouse_termcode(KS_MOUSE);
3436# endif
3437
3438# ifdef FEAT_MOUSE_GPM
3439 if (!use_xterm_mouse()
3440# ifdef FEAT_GUI
3441 && !gui.in_use
3442# endif
3443 )
3444 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3445# endif
3446
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003447# ifdef FEAT_SYSMOUSE
3448 if (!use_xterm_mouse()
3449# ifdef FEAT_GUI
3450 && !gui.in_use
3451# endif
3452 )
3453 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3454# endif
3455
Bram Moolenaar071d4272004-06-13 20:20:40 +00003456# ifdef FEAT_MOUSE_JSB
3457 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3458 if (!use_xterm_mouse()
3459# ifdef FEAT_GUI
3460 && !gui.in_use
3461# endif
3462 )
3463 set_mouse_termcode(KS_JSBTERM_MOUSE,
3464 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3465 else
3466 del_mouse_termcode(KS_JSBTERM_MOUSE);
3467# endif
3468
3469# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003470 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471 * define it in the GUI or when using an xterm. */
3472 if (!use_xterm_mouse()
3473# ifdef FEAT_GUI
3474 && !gui.in_use
3475# endif
3476 )
3477 set_mouse_termcode(KS_NETTERM_MOUSE,
3478 (char_u *)IF_EB("\033}", ESC_STR "}"));
3479 else
3480 del_mouse_termcode(KS_NETTERM_MOUSE);
3481# endif
3482
3483# ifdef FEAT_MOUSE_DEC
3484 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3485 if (!use_xterm_mouse()
3486# ifdef FEAT_GUI
3487 && !gui.in_use
3488# endif
3489 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003490 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3491 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003492 else
3493 del_mouse_termcode(KS_DEC_MOUSE);
3494# endif
3495# ifdef FEAT_MOUSE_PTERM
3496 /* same as the dec mouse */
3497 if (!use_xterm_mouse()
3498# ifdef FEAT_GUI
3499 && !gui.in_use
3500# endif
3501 )
3502 set_mouse_termcode(KS_PTERM_MOUSE,
3503 (char_u *) IF_EB("\033[", ESC_STR "["));
3504 else
3505 del_mouse_termcode(KS_PTERM_MOUSE);
3506# endif
3507}
3508#endif
3509
3510/*
3511 * set screen mode, always fails.
3512 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003513 int
3514mch_screenmode(arg)
Bram Moolenaar78a15312009-05-15 19:33:18 +00003515 char_u *arg UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003516{
3517 EMSG(_(e_screenmode));
3518 return FAIL;
3519}
3520
3521#ifndef VMS
3522
3523/*
3524 * Try to get the current window size:
3525 * 1. with an ioctl(), most accurate method
3526 * 2. from the environment variables LINES and COLUMNS
3527 * 3. from the termcap
3528 * 4. keep using the old values
3529 * Return OK when size could be determined, FAIL otherwise.
3530 */
3531 int
3532mch_get_shellsize()
3533{
3534 long rows = 0;
3535 long columns = 0;
3536 char_u *p;
3537
3538 /*
3539 * For OS/2 use _scrsize().
3540 */
3541# ifdef __EMX__
3542 {
3543 int s[2];
3544
3545 _scrsize(s);
3546 columns = s[0];
3547 rows = s[1];
3548 }
3549# endif
3550
3551 /*
3552 * 1. try using an ioctl. It is the most accurate method.
3553 *
3554 * Try using TIOCGWINSZ first, some systems that have it also define
3555 * TIOCGSIZE but don't have a struct ttysize.
3556 */
3557# ifdef TIOCGWINSZ
3558 {
3559 struct winsize ws;
3560 int fd = 1;
3561
3562 /* When stdout is not a tty, use stdin for the ioctl(). */
3563 if (!isatty(fd) && isatty(read_cmd_fd))
3564 fd = read_cmd_fd;
3565 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3566 {
3567 columns = ws.ws_col;
3568 rows = ws.ws_row;
3569 }
3570 }
3571# else /* TIOCGWINSZ */
3572# ifdef TIOCGSIZE
3573 {
3574 struct ttysize ts;
3575 int fd = 1;
3576
3577 /* When stdout is not a tty, use stdin for the ioctl(). */
3578 if (!isatty(fd) && isatty(read_cmd_fd))
3579 fd = read_cmd_fd;
3580 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3581 {
3582 columns = ts.ts_cols;
3583 rows = ts.ts_lines;
3584 }
3585 }
3586# endif /* TIOCGSIZE */
3587# endif /* TIOCGWINSZ */
3588
3589 /*
3590 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003591 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3592 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003593 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003594 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003595 {
3596 if ((p = (char_u *)getenv("LINES")))
3597 rows = atoi((char *)p);
3598 if ((p = (char_u *)getenv("COLUMNS")))
3599 columns = atoi((char *)p);
3600 }
3601
3602#ifdef HAVE_TGETENT
3603 /*
3604 * 3. try reading "co" and "li" entries from termcap
3605 */
3606 if (columns == 0 || rows == 0)
3607 getlinecol(&columns, &rows);
3608#endif
3609
3610 /*
3611 * 4. If everything fails, use the old values
3612 */
3613 if (columns <= 0 || rows <= 0)
3614 return FAIL;
3615
3616 Rows = rows;
3617 Columns = columns;
3618 return OK;
3619}
3620
3621/*
3622 * Try to set the window size to Rows and Columns.
3623 */
3624 void
3625mch_set_shellsize()
3626{
3627 if (*T_CWS)
3628 {
3629 /*
3630 * NOTE: if you get an error here that term_set_winsize() is
3631 * undefined, check the output of configure. It could probably not
3632 * find a ncurses, termcap or termlib library.
3633 */
3634 term_set_winsize((int)Rows, (int)Columns);
3635 out_flush();
3636 screen_start(); /* don't know where cursor is now */
3637 }
3638}
3639
3640#endif /* VMS */
3641
3642/*
3643 * Rows and/or Columns has changed.
3644 */
3645 void
3646mch_new_shellsize()
3647{
3648 /* Nothing to do. */
3649}
3650
Bram Moolenaardf177f62005-02-22 08:39:57 +00003651#ifndef USE_SYSTEM
3652static void append_ga_line __ARGS((garray_T *gap));
3653
3654/*
3655 * Append the text in "gap" below the cursor line and clear "gap".
3656 */
3657 static void
3658append_ga_line(gap)
3659 garray_T *gap;
3660{
3661 /* Remove trailing CR. */
3662 if (gap->ga_len > 0
3663 && !curbuf->b_p_bin
3664 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3665 --gap->ga_len;
3666 ga_append(gap, NUL);
3667 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3668 gap->ga_len = 0;
3669}
3670#endif
3671
Bram Moolenaar071d4272004-06-13 20:20:40 +00003672 int
3673mch_call_shell(cmd, options)
3674 char_u *cmd;
3675 int options; /* SHELL_*, see vim.h */
3676{
3677#ifdef VMS
3678 char *ifn = NULL;
3679 char *ofn = NULL;
3680#endif
3681 int tmode = cur_tmode;
3682#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3683 int x;
3684# ifndef __EMX__
3685 char_u *newcmd; /* only needed for unix */
3686# else
3687 /*
3688 * Set the preferred shell in the EMXSHELL environment variable (but
3689 * only if it is different from what is already in the environment).
3690 * Emx then takes care of whether to use "/c" or "-c" in an
3691 * intelligent way. Simply pass the whole thing to emx's system() call.
3692 * Emx also starts an interactive shell if system() is passed an empty
3693 * string.
3694 */
3695 char_u *p, *old;
3696
3697 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3698 {
3699 /* should check HAVE_SETENV, but I know we don't have it. */
3700 p = alloc(10 + strlen(p_sh));
3701 if (p)
3702 {
3703 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3704 putenv((char *)p); /* don't free the pointer! */
3705 }
3706 }
3707# endif
3708
3709 out_flush();
3710
3711 if (options & SHELL_COOKED)
3712 settmode(TMODE_COOK); /* set to normal mode */
3713
3714# ifdef __EMX__
3715 if (cmd == NULL)
3716 x = system(""); /* this starts an interactive shell in emx */
3717 else
3718 x = system((char *)cmd);
3719 /* system() returns -1 when error occurs in starting shell */
3720 if (x == -1 && !emsg_silent)
3721 {
3722 MSG_PUTS(_("\nCannot execute shell "));
3723 msg_outtrans(p_sh);
3724 msg_putchar('\n');
3725 }
3726# else /* not __EMX__ */
3727 if (cmd == NULL)
3728 x = system((char *)p_sh);
3729 else
3730 {
3731# ifdef VMS
3732 if (ofn = strchr((char *)cmd, '>'))
3733 *ofn++ = '\0';
3734 if (ifn = strchr((char *)cmd, '<'))
3735 {
3736 char *p;
3737
3738 *ifn++ = '\0';
3739 p = strchr(ifn,' '); /* chop off any trailing spaces */
3740 if (p)
3741 *p = '\0';
3742 }
3743 if (ofn)
3744 x = vms_sys((char *)cmd, ofn, ifn);
3745 else
3746 x = system((char *)cmd);
3747# else
3748 newcmd = lalloc(STRLEN(p_sh)
3749 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3750 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3751 if (newcmd == NULL)
3752 x = 0;
3753 else
3754 {
3755 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3756 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3757 (char *)p_shcf,
3758 (char *)cmd);
3759 x = system((char *)newcmd);
3760 vim_free(newcmd);
3761 }
3762# endif
3763 }
3764# ifdef VMS
3765 x = vms_sys_status(x);
3766# endif
3767 if (emsg_silent)
3768 ;
3769 else if (x == 127)
3770 MSG_PUTS(_("\nCannot execute shell sh\n"));
3771# endif /* __EMX__ */
3772 else if (x && !(options & SHELL_SILENT))
3773 {
3774 MSG_PUTS(_("\nshell returned "));
3775 msg_outnum((long)x);
3776 msg_putchar('\n');
3777 }
3778
3779 if (tmode == TMODE_RAW)
3780 settmode(TMODE_RAW); /* set to raw mode */
3781# ifdef FEAT_TITLE
3782 resettitle();
3783# endif
3784 return x;
3785
3786#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3787
Bram Moolenaardf177f62005-02-22 08:39:57 +00003788# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3789 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790
3791 char_u *newcmd = NULL;
3792 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003793 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794 pid_t wait_pid = 0;
3795# ifdef HAVE_UNION_WAIT
3796 union wait status;
3797# else
3798 int status = -1;
3799# endif
3800 int retval = -1;
3801 char **argv = NULL;
3802 int argc;
3803 int i;
3804 char_u *p;
3805 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003806 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003807# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 int pty_slave_fd = -1;
3809 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003810# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003811 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812 int fd_fromshell[2];
3813 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003814# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003815 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003816# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003817 static char envbuf_Rows[20];
3818 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003820 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003821
3822 out_flush();
3823 if (options & SHELL_COOKED)
3824 settmode(TMODE_COOK); /* set to normal mode */
3825
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826 newcmd = vim_strsave(p_sh);
3827 if (newcmd == NULL) /* out of memory */
3828 goto error;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003829
3830 /*
3831 * Do this loop twice:
3832 * 1: find number of arguments
3833 * 2: separate them and build argv[]
3834 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 for (i = 0; i < 2; ++i)
3836 {
3837 p = newcmd;
3838 inquote = FALSE;
3839 argc = 0;
3840 for (;;)
3841 {
3842 if (i == 1)
3843 argv[argc] = (char *)p;
3844 ++argc;
3845 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3846 {
3847 if (*p == '"')
3848 inquote = !inquote;
3849 ++p;
3850 }
3851 if (*p == NUL)
3852 break;
3853 if (i == 1)
3854 *p++ = NUL;
3855 p = skipwhite(p);
3856 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003857 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003858 {
3859 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3860 if (argv == NULL) /* out of memory */
3861 goto error;
3862 }
3863 }
3864 if (cmd != NULL)
3865 {
3866 if (extra_shell_arg != NULL)
3867 argv[argc++] = (char *)extra_shell_arg;
3868 argv[argc++] = (char *)p_shcf;
3869 argv[argc++] = (char *)cmd;
3870 }
3871 argv[argc] = NULL;
3872
Bram Moolenaar071d4272004-06-13 20:20:40 +00003873 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003874 * For the GUI, when writing the output into the buffer and when reading
3875 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3876 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003877 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003878 if ((options & (SHELL_READ|SHELL_WRITE))
3879# ifdef FEAT_GUI
3880 || (gui.in_use && show_shell_mess)
3881# endif
3882 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003883 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003884# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 /*
3886 * Try to open a master pty.
3887 * If this works, open the slave pty.
3888 * If the slave can't be opened, close the master pty.
3889 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003890 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003891 {
3892 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3893 if (pty_master_fd >= 0 && ((pty_slave_fd =
3894 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3895 {
3896 close(pty_master_fd);
3897 pty_master_fd = -1;
3898 }
3899 }
3900 /*
3901 * If not opening a pty or it didn't work, try using pipes.
3902 */
3903 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003904# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905 {
3906 pipe_error = (pipe(fd_toshell) < 0);
3907 if (!pipe_error) /* pipe create OK */
3908 {
3909 pipe_error = (pipe(fd_fromshell) < 0);
3910 if (pipe_error) /* pipe create failed */
3911 {
3912 close(fd_toshell[0]);
3913 close(fd_toshell[1]);
3914 }
3915 }
3916 if (pipe_error)
3917 {
3918 MSG_PUTS(_("\nCannot create pipes\n"));
3919 out_flush();
3920 }
3921 }
3922 }
3923
3924 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003925 {
3926# ifdef __BEOS__
3927 beos_cleanup_read_thread();
3928# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003929
Bram Moolenaar071d4272004-06-13 20:20:40 +00003930 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3931 {
3932 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003933 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003934# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003935 || (gui.in_use && show_shell_mess)
3936# endif
3937 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003938 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003939# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003940 if (pty_master_fd >= 0) /* close the pseudo tty */
3941 {
3942 close(pty_master_fd);
3943 close(pty_slave_fd);
3944 }
3945 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003946# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003947 {
3948 close(fd_toshell[0]);
3949 close(fd_toshell[1]);
3950 close(fd_fromshell[0]);
3951 close(fd_fromshell[1]);
3952 }
3953 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003954 }
3955 else if (pid == 0) /* child */
3956 {
3957 reset_signals(); /* handle signals normally */
3958
3959 if (!show_shell_mess || (options & SHELL_EXPAND))
3960 {
3961 int fd;
3962
3963 /*
3964 * Don't want to show any message from the shell. Can't just
3965 * close stdout and stderr though, because some systems will
3966 * break if you try to write to them after that, so we must
3967 * use dup() to replace them with something else -- webb
3968 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3969 * waiting for input.
3970 */
3971 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3972 fclose(stdin);
3973 fclose(stdout);
3974 fclose(stderr);
3975
3976 /*
3977 * If any of these open()'s and dup()'s fail, we just continue
3978 * anyway. It's not fatal, and on most systems it will make
3979 * no difference at all. On a few it will cause the execvp()
3980 * to exit with a non-zero status even when the completion
3981 * could be done, which is nothing too serious. If the open()
3982 * or dup() failed we'd just do the same thing ourselves
3983 * anyway -- webb
3984 */
3985 if (fd >= 0)
3986 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00003987 ignored = dup(fd); /* To replace stdin (fd 0) */
3988 ignored = dup(fd); /* To replace stdout (fd 1) */
3989 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003990
3991 /* Don't need this now that we've duplicated it */
3992 close(fd);
3993 }
3994 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003995 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003996# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003997 || gui.in_use
3998# endif
3999 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004000 {
4001
Bram Moolenaardf177f62005-02-22 08:39:57 +00004002# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004003 /* Create our own process group, so that the child and all its
4004 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004005 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004006 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004007 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004008 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004009# if defined(SIGHUP)
4010 /* When doing "!xterm&" and 'shell' is bash: the shell
4011 * will exit and send SIGHUP to all processes in its
4012 * group, killing the just started process. Ignore SIGHUP
4013 * to avoid that. (suggested by Simon Schubert)
4014 */
4015 signal(SIGHUP, SIG_IGN);
4016# endif
4017 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004018# endif
4019# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004020 if (pty_slave_fd >= 0)
4021 {
4022 /* push stream discipline modules */
4023 if (options & SHELL_COOKED)
4024 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004025# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004026 /* Try to become controlling tty (probably doesn't work,
4027 * unless run by root) */
4028 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004029# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004030 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004031# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004032 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004033# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004034 setenv("TERM", "dumb", 1);
4035 sprintf((char *)envbuf, "%ld", Rows);
4036 setenv("ROWS", (char *)envbuf, 1);
4037 sprintf((char *)envbuf, "%ld", Rows);
4038 setenv("LINES", (char *)envbuf, 1);
4039 sprintf((char *)envbuf, "%ld", Columns);
4040 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004041# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004042 /*
4043 * Putenv does not copy the string, it has to remain valid.
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004044 * Use a static array to avoid losing allocated memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004045 */
4046 putenv("TERM=dumb");
4047 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
4048 putenv(envbuf_Rows);
4049 sprintf(envbuf_Rows, "LINES=%ld", Rows);
4050 putenv(envbuf_Rows);
4051 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
4052 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004053# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054
Bram Moolenaara5792f52005-11-23 21:25:05 +00004055 /*
4056 * stderr is only redirected when using the GUI, so that a
4057 * program like gpg can still access the terminal to get a
4058 * passphrase using stderr.
4059 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004060# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004061 if (pty_master_fd >= 0)
4062 {
4063 close(pty_master_fd); /* close master side of pty */
4064
4065 /* set up stdin/stdout/stderr for the child */
4066 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004067 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004068 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004069 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004070 if (gui.in_use)
4071 {
4072 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004073 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004074 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004075
4076 close(pty_slave_fd); /* has been dupped, close it now */
4077 }
4078 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004079# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004080 {
4081 /* set up stdin for the child */
4082 close(fd_toshell[1]);
4083 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004084 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085 close(fd_toshell[0]);
4086
4087 /* set up stdout for the child */
4088 close(fd_fromshell[0]);
4089 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004090 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004091 close(fd_fromshell[1]);
4092
Bram Moolenaara5792f52005-11-23 21:25:05 +00004093# ifdef FEAT_GUI
4094 if (gui.in_use)
4095 {
4096 /* set up stderr for the child */
4097 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004098 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004099 }
4100# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101 }
4102 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004103
Bram Moolenaar071d4272004-06-13 20:20:40 +00004104 /*
4105 * There is no type cast for the argv, because the type may be
4106 * different on different machines. This may cause a warning
4107 * message with strict compilers, don't worry about it.
4108 * Call _exit() instead of exit() to avoid closing the connection
4109 * to the X server (esp. with GTK, which uses atexit()).
4110 */
4111 execvp(argv[0], argv);
4112 _exit(EXEC_FAILED); /* exec failed, return failure code */
4113 }
4114 else /* parent */
4115 {
4116 /*
4117 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004118 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119 */
4120 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004121 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122
4123 /*
4124 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004125 * This is also used to pipe stdin/stdout to/from the external
4126 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004127 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004128 if ((options & (SHELL_READ|SHELL_WRITE))
4129# ifdef FEAT_GUI
4130 || (gui.in_use && show_shell_mess)
4131# endif
4132 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004133 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004134# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004136# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004137 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004138# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004139 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4140 int ta_len = 0; /* valid bytes in ta_buf[] */
4141 int len;
4142 int p_more_save;
4143 int old_State;
4144 int c;
4145 int toshell_fd;
4146 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004147 garray_T ga;
4148 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004149# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4150 struct timeval start_tv;
4151# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004152
Bram Moolenaardf177f62005-02-22 08:39:57 +00004153# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004154 if (pty_master_fd >= 0)
4155 {
4156 close(pty_slave_fd); /* close slave side of pty */
4157 fromshell_fd = pty_master_fd;
4158 toshell_fd = dup(pty_master_fd);
4159 }
4160 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004161# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162 {
4163 close(fd_toshell[0]);
4164 close(fd_fromshell[1]);
4165 toshell_fd = fd_toshell[1];
4166 fromshell_fd = fd_fromshell[0];
4167 }
4168
4169 /*
4170 * Write to the child if there are typed characters.
4171 * Read from the child if there are characters available.
4172 * Repeat the reading a few times if more characters are
4173 * available. Need to check for typed keys now and then, but
4174 * not too often (delays when no chars are available).
4175 * This loop is quit if no characters can be read from the pty
4176 * (WaitForChar detected special condition), or there are no
4177 * characters available and the child has exited.
4178 * Only check if the child has exited when there is no more
4179 * output. The child may exit before all the output has
4180 * been printed.
4181 *
4182 * Currently this busy loops!
4183 * This can probably dead-lock when the write blocks!
4184 */
4185 p_more_save = p_more;
4186 p_more = FALSE;
4187 old_State = State;
4188 State = EXTERNCMD; /* don't redraw at window resize */
4189
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004190 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004191 {
4192 /* Fork a process that will write the lines to the
4193 * external program. */
4194 if ((wpid = fork()) == -1)
4195 {
4196 MSG_PUTS(_("\nCannot fork\n"));
4197 }
4198 else if (wpid == 0)
4199 {
4200 linenr_T lnum = curbuf->b_op_start.lnum;
4201 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004202 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004203 char_u *s;
4204 size_t l;
4205
4206 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004207 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004208 for (;;)
4209 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004210 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004211 if (l == 0)
4212 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004213 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004214 /* NL -> NUL translation */
4215 len = write(toshell_fd, "", (size_t)1);
4216 else
4217 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004218 s = vim_strchr(lp + written, NL);
4219 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004220 s == NULL ? l
4221 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004222 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004223 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004224 {
4225 /* Finished a line, add a NL, unless this line
4226 * should not have one. */
4227 if (lnum != curbuf->b_op_end.lnum
4228 || !curbuf->b_p_bin
4229 || (lnum != write_no_eol_lnum
4230 && (lnum !=
4231 curbuf->b_ml.ml_line_count
4232 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004233 ignored = write(toshell_fd, "\n",
4234 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004235 ++lnum;
4236 if (lnum > curbuf->b_op_end.lnum)
4237 {
4238 /* finished all the lines, close pipe */
4239 close(toshell_fd);
4240 toshell_fd = -1;
4241 break;
4242 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004243 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004244 written = 0;
4245 }
4246 else if (len > 0)
4247 written += len;
4248 }
4249 _exit(0);
4250 }
4251 else
4252 {
4253 close(toshell_fd);
4254 toshell_fd = -1;
4255 }
4256 }
4257
4258 if (options & SHELL_READ)
4259 ga_init2(&ga, 1, BUFLEN);
4260
4261 noread_cnt = 0;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004262# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4263 gettimeofday(&start_tv, NULL);
4264# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004265 for (;;)
4266 {
4267 /*
4268 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004269 * if there are any.
4270 * Don't do this if we are expanding wild cards (would eat
4271 * typeahead).
4272 * Don't do this when filtering and terminal is in cooked
4273 * mode, the shell command will handle the I/O. Avoids
4274 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004275 * Don't get characters when the child has already
4276 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004277 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004278 * while (noread_cnt > 4), avoids that ":r !ls" eats
4279 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004280 */
4281 len = 0;
4282 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004283 && ((options &
4284 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4285 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004286# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004287 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004288# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004289 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004290 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004291 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004293 if (ta_len == 0)
4294 {
4295 /* Get extra characters when we don't have any.
4296 * Reset the counter and timer. */
4297 noread_cnt = 0;
4298# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4299 gettimeofday(&start_tv, NULL);
4300# endif
4301 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4302 }
4303 if (ta_len > 0 || len > 0)
4304 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004305 /*
4306 * For pipes:
4307 * Check for CTRL-C: send interrupt signal to child.
4308 * Check for CTRL-D: EOF, close pipe to child.
4309 */
4310 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4311 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004312# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004313 /*
4314 * Send SIGINT to the child's group or all
4315 * processes in our group.
4316 */
4317 if (ta_buf[ta_len] == Ctrl_C
4318 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004319 {
4320# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004322# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004324# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004325 if (wpid > 0)
4326 kill(wpid, SIGINT);
4327 }
4328# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004329 if (pty_master_fd < 0 && toshell_fd >= 0
4330 && ta_buf[ta_len] == Ctrl_D)
4331 {
4332 close(toshell_fd);
4333 toshell_fd = -1;
4334 }
4335 }
4336
4337 /* replace K_BS by <BS> and K_DEL by <DEL> */
4338 for (i = ta_len; i < ta_len + len; ++i)
4339 {
4340 if (ta_buf[i] == CSI && len - i > 2)
4341 {
4342 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4343 if (c == K_DEL || c == K_KDEL || c == K_BS)
4344 {
4345 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4346 (size_t)(len - i - 2));
4347 if (c == K_DEL || c == K_KDEL)
4348 ta_buf[i] = DEL;
4349 else
4350 ta_buf[i] = Ctrl_H;
4351 len -= 2;
4352 }
4353 }
4354 else if (ta_buf[i] == '\r')
4355 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004356# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00004358 i += (*mb_ptr2len_len)(ta_buf + i,
4359 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004360# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004361 }
4362
4363 /*
4364 * For pipes: echo the typed characters.
4365 * For a pty this does not seem to work.
4366 */
4367 if (pty_master_fd < 0)
4368 {
4369 for (i = ta_len; i < ta_len + len; ++i)
4370 {
4371 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4372 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004373# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374 else if (has_mbyte)
4375 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004376 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004377
4378 msg_outtrans_len(ta_buf + i, l);
4379 i += l - 1;
4380 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004381# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382 else
4383 msg_outtrans_len(ta_buf + i, 1);
4384 }
4385 windgoto(msg_row, msg_col);
4386 out_flush();
4387 }
4388
4389 ta_len += len;
4390
4391 /*
4392 * Write the characters to the child, unless EOF has
4393 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004394 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004395 * When writing buffer lines, drop the typed
4396 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004397 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004398 if (options & SHELL_WRITE)
4399 ta_len = 0;
4400 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004401 {
4402 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4403 if (len > 0)
4404 {
4405 ta_len -= len;
4406 mch_memmove(ta_buf, ta_buf + len, ta_len);
4407 }
4408 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004409 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004410 }
4411
Bram Moolenaardf177f62005-02-22 08:39:57 +00004412 if (got_int)
4413 {
4414 /* CTRL-C sends a signal to the child, we ignore it
4415 * ourselves */
4416# ifdef HAVE_SETSID
4417 kill(-pid, SIGINT);
4418# else
4419 kill(0, SIGINT);
4420# endif
4421 if (wpid > 0)
4422 kill(wpid, SIGINT);
4423 got_int = FALSE;
4424 }
4425
Bram Moolenaar071d4272004-06-13 20:20:40 +00004426 /*
4427 * Check if the child has any characters to be printed.
4428 * Read them and write them to our window. Repeat this as
4429 * long as there is something to do, avoid the 10ms wait
4430 * for mch_inchar(), or sending typeahead characters to
4431 * the external process.
4432 * TODO: This should handle escape sequences, compatible
4433 * to some terminal (vt52?).
4434 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004435 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004436 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4437 {
4438 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004439# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004440 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004441# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004442 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004443# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004444 );
4445 if (len <= 0) /* end of file or error */
4446 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004447
4448 noread_cnt = 0;
4449 if (options & SHELL_READ)
4450 {
4451 /* Do NUL -> NL translation, append NL separated
4452 * lines to the current buffer. */
4453 for (i = 0; i < len; ++i)
4454 {
4455 if (buffer[i] == NL)
4456 append_ga_line(&ga);
4457 else if (buffer[i] == NUL)
4458 ga_append(&ga, NL);
4459 else
4460 ga_append(&ga, buffer[i]);
4461 }
4462 }
4463# ifdef FEAT_MBYTE
4464 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004465 {
4466 int l;
4467
Bram Moolenaardf177f62005-02-22 08:39:57 +00004468 len += buffer_off;
4469 buffer[len] = NUL;
4470
Bram Moolenaar071d4272004-06-13 20:20:40 +00004471 /* Check if the last character in buffer[] is
4472 * incomplete, keep these bytes for the next
4473 * round. */
4474 for (p = buffer; p < buffer + len; p += l)
4475 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004476 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004477 if (l == 0)
4478 l = 1; /* NUL byte? */
4479 else if (MB_BYTE2LEN(*p) != l)
4480 break;
4481 }
4482 if (p == buffer) /* no complete character */
4483 {
4484 /* avoid getting stuck at an illegal byte */
4485 if (len >= 12)
4486 ++p;
4487 else
4488 {
4489 buffer_off = len;
4490 continue;
4491 }
4492 }
4493 c = *p;
4494 *p = NUL;
4495 msg_puts(buffer);
4496 if (p < buffer + len)
4497 {
4498 *p = c;
4499 buffer_off = (buffer + len) - p;
4500 mch_memmove(buffer, p, buffer_off);
4501 continue;
4502 }
4503 buffer_off = 0;
4504 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004505# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004506 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507 {
4508 buffer[len] = NUL;
4509 msg_puts(buffer);
4510 }
4511
4512 windgoto(msg_row, msg_col);
4513 cursor_on();
4514 out_flush();
4515 if (got_int)
4516 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004517
4518# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4519 {
4520 struct timeval now_tv;
4521 long msec;
4522
4523 /* Avoid that we keep looping here without
4524 * checking for a CTRL-C for a long time. Don't
4525 * break out too often to avoid losing typeahead. */
4526 gettimeofday(&now_tv, NULL);
4527 msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
4528 + (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
4529 if (msec > 2000)
4530 {
4531 noread_cnt = 5;
4532 break;
4533 }
4534 }
4535# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004536 }
4537
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004538 /* If we already detected the child has finished break the
4539 * loop now. */
4540 if (wait_pid == pid)
4541 break;
4542
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543 /*
4544 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004545 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004546 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004547# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004548 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004549# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004550 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004551# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004552 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4553 || (wait_pid == pid && WIFEXITED(status)))
4554 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004555 /* Don't break the loop yet, try reading more
4556 * characters from "fromshell_fd" first. When using
4557 * pipes there might still be something to read and
4558 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004561 else
4562 wait_pid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004563 }
4564finished:
4565 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004566 if (options & SHELL_READ)
4567 {
4568 if (ga.ga_len > 0)
4569 {
4570 append_ga_line(&ga);
4571 /* remember that the NL was missing */
4572 write_no_eol_lnum = curwin->w_cursor.lnum;
4573 }
4574 else
4575 write_no_eol_lnum = 0;
4576 ga_clear(&ga);
4577 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004578
Bram Moolenaar071d4272004-06-13 20:20:40 +00004579 /*
4580 * Give all typeahead that wasn't used back to ui_inchar().
4581 */
4582 if (ta_len)
4583 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004584 State = old_State;
4585 if (toshell_fd >= 0)
4586 close(toshell_fd);
4587 close(fromshell_fd);
4588 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004589
4590 /*
4591 * Wait until our child has exited.
4592 * Ignore wait() returning pids of other children and returning
4593 * because of some signal like SIGWINCH.
4594 * Don't wait if wait_pid was already set above, indicating the
4595 * child already exited.
4596 */
4597 while (wait_pid != pid)
4598 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004599# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600 /* Ugly hack: when compiled with Python threads are probably
4601 * used, in which case wait() sometimes hangs for no obvious
4602 * reason. Use waitpid() instead and loop (like the GUI). */
4603# ifdef __NeXT__
4604 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4605# else
4606 wait_pid = waitpid(pid, &status, WNOHANG);
4607# endif
4608 if (wait_pid == 0)
4609 {
4610 /* Wait for 1/100 sec before trying again. */
4611 mch_delay(10L, TRUE);
4612 continue;
4613 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004614# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004615 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004616# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 if (wait_pid <= 0
4618# ifdef ECHILD
4619 && errno == ECHILD
4620# endif
4621 )
4622 break;
4623 }
4624
Bram Moolenaardf177f62005-02-22 08:39:57 +00004625 /* Make sure the child that writes to the external program is
4626 * dead. */
4627 if (wpid > 0)
4628 kill(wpid, SIGKILL);
4629
Bram Moolenaar071d4272004-06-13 20:20:40 +00004630 /*
4631 * Set to raw mode right now, otherwise a CTRL-C after
4632 * catch_signals() will kill Vim.
4633 */
4634 if (tmode == TMODE_RAW)
4635 settmode(TMODE_RAW);
4636 did_settmode = TRUE;
4637 set_signals();
4638
4639 if (WIFEXITED(status))
4640 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004641 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642 retval = WEXITSTATUS(status);
4643 if (retval && !emsg_silent)
4644 {
4645 if (retval == EXEC_FAILED)
4646 {
4647 MSG_PUTS(_("\nCannot execute shell "));
4648 msg_outtrans(p_sh);
4649 msg_putchar('\n');
4650 }
4651 else if (!(options & SHELL_SILENT))
4652 {
4653 MSG_PUTS(_("\nshell returned "));
4654 msg_outnum((long)retval);
4655 msg_putchar('\n');
4656 }
4657 }
4658 }
4659 else
4660 MSG_PUTS(_("\nCommand terminated\n"));
4661 }
4662 }
4663 vim_free(argv);
4664
4665error:
4666 if (!did_settmode)
4667 if (tmode == TMODE_RAW)
4668 settmode(TMODE_RAW); /* set to raw mode */
4669# ifdef FEAT_TITLE
4670 resettitle();
4671# endif
4672 vim_free(newcmd);
4673
4674 return retval;
4675
4676#endif /* USE_SYSTEM */
4677}
4678
4679/*
4680 * Check for CTRL-C typed by reading all available characters.
4681 * In cooked mode we should get SIGINT, no need to check.
4682 */
4683 void
4684mch_breakcheck()
4685{
4686 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4687 fill_input_buf(FALSE);
4688}
4689
4690/*
4691 * Wait "msec" msec until a character is available from the keyboard or from
4692 * inbuf[]. msec == -1 will block forever.
4693 * When a GUI is being used, this will never get called -- webb
4694 */
4695 static int
4696WaitForChar(msec)
4697 long msec;
4698{
4699#ifdef FEAT_MOUSE_GPM
4700 int gpm_process_wanted;
4701#endif
4702#ifdef FEAT_XCLIPBOARD
4703 int rest;
4704#endif
4705 int avail;
4706
4707 if (input_available()) /* something in inbuf[] */
4708 return 1;
4709
4710#if defined(FEAT_MOUSE_DEC)
4711 /* May need to query the mouse position. */
4712 if (WantQueryMouse)
4713 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004714 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004715 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4716 }
4717#endif
4718
4719 /*
4720 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4721 * events. This is a bit complicated, because they might both be defined.
4722 */
4723#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4724# ifdef FEAT_XCLIPBOARD
4725 rest = 0;
4726 if (do_xterm_trace())
4727 rest = msec;
4728# endif
4729 do
4730 {
4731# ifdef FEAT_XCLIPBOARD
4732 if (rest != 0)
4733 {
4734 msec = XT_TRACE_DELAY;
4735 if (rest >= 0 && rest < XT_TRACE_DELAY)
4736 msec = rest;
4737 if (rest >= 0)
4738 rest -= msec;
4739 }
4740# endif
4741# ifdef FEAT_MOUSE_GPM
4742 gpm_process_wanted = 0;
4743 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4744# else
4745 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4746# endif
4747 if (!avail)
4748 {
4749 if (input_available())
4750 return 1;
4751# ifdef FEAT_XCLIPBOARD
4752 if (rest == 0 || !do_xterm_trace())
4753# endif
4754 break;
4755 }
4756 }
4757 while (FALSE
4758# ifdef FEAT_MOUSE_GPM
4759 || (gpm_process_wanted && mch_gpm_process() == 0)
4760# endif
4761# ifdef FEAT_XCLIPBOARD
4762 || (!avail && rest != 0)
4763# endif
4764 );
4765
4766#else
4767 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4768#endif
4769 return avail;
4770}
4771
4772/*
4773 * Wait "msec" msec until a character is available from file descriptor "fd".
4774 * Time == -1 will block forever.
4775 * When a GUI is being used, this will not be used for input -- webb
4776 * Returns also, when a request from Sniff is waiting -- toni.
4777 * Or when a Linux GPM mouse event is waiting.
4778 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779#if defined(__BEOS__)
4780 int
4781#else
4782 static int
4783#endif
4784RealWaitForChar(fd, msec, check_for_gpm)
4785 int fd;
4786 long msec;
Bram Moolenaar78a15312009-05-15 19:33:18 +00004787 int *check_for_gpm UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004788{
4789 int ret;
Bram Moolenaar67c53842010-05-22 18:28:27 +02004790#ifdef FEAT_NETBEANS_INTG
4791 int nb_fd = (usingNetbeans ? netbeans_filedesc() : -1);
4792#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004793#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004794 static int busy = FALSE;
4795
4796 /* May retry getting characters after an event was handled. */
4797# define MAY_LOOP
4798
4799# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4800 /* Remember at what time we started, so that we know how much longer we
4801 * should wait after being interrupted. */
4802# define USE_START_TV
4803 struct timeval start_tv;
4804
4805 if (msec > 0 && (
4806# ifdef FEAT_XCLIPBOARD
4807 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004808# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004809 ||
4810# endif
4811# endif
4812# ifdef USE_XSMP
4813 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004814# ifdef FEAT_MZSCHEME
4815 ||
4816# endif
4817# endif
4818# ifdef FEAT_MZSCHEME
4819 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004820# endif
4821 ))
4822 gettimeofday(&start_tv, NULL);
4823# endif
4824
4825 /* Handle being called recursively. This may happen for the session
4826 * manager stuff, it may save the file, which does a breakcheck. */
4827 if (busy)
4828 return 0;
4829#endif
4830
4831#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00004832 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004833#endif
4834 {
4835#ifdef MAY_LOOP
4836 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004837# ifdef FEAT_MZSCHEME
4838 int mzquantum_used = FALSE;
4839# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004840#endif
4841#ifndef HAVE_SELECT
Bram Moolenaar67c53842010-05-22 18:28:27 +02004842 struct pollfd fds[6];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004843 int nfd;
4844# ifdef FEAT_XCLIPBOARD
4845 int xterm_idx = -1;
4846# endif
4847# ifdef FEAT_MOUSE_GPM
4848 int gpm_idx = -1;
4849# endif
4850# ifdef USE_XSMP
4851 int xsmp_idx = -1;
4852# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02004853# ifdef FEAT_NETBEANS_INTG
4854 int nb_idx = -1;
4855# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004856 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004857
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004858# ifdef FEAT_MZSCHEME
4859 mzvim_check_threads();
4860 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4861 {
4862 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4863 mzquantum_used = TRUE;
4864 }
4865# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004866 fds[0].fd = fd;
4867 fds[0].events = POLLIN;
4868 nfd = 1;
4869
4870# ifdef FEAT_SNIFF
4871# define SNIFF_IDX 1
4872 if (want_sniff_request)
4873 {
4874 fds[SNIFF_IDX].fd = fd_from_sniff;
4875 fds[SNIFF_IDX].events = POLLIN;
4876 nfd++;
4877 }
4878# endif
4879# ifdef FEAT_XCLIPBOARD
4880 if (xterm_Shell != (Widget)0)
4881 {
4882 xterm_idx = nfd;
4883 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4884 fds[nfd].events = POLLIN;
4885 nfd++;
4886 }
4887# endif
4888# ifdef FEAT_MOUSE_GPM
4889 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4890 {
4891 gpm_idx = nfd;
4892 fds[nfd].fd = gpm_fd;
4893 fds[nfd].events = POLLIN;
4894 nfd++;
4895 }
4896# endif
4897# ifdef USE_XSMP
4898 if (xsmp_icefd != -1)
4899 {
4900 xsmp_idx = nfd;
4901 fds[nfd].fd = xsmp_icefd;
4902 fds[nfd].events = POLLIN;
4903 nfd++;
4904 }
4905# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02004906#ifdef FEAT_NETBEANS_INTG
4907 if (nb_fd != -1)
4908 {
4909 nb_idx = nfd;
4910 fds[nfd].fd = nb_fd;
4911 fds[nfd].events = POLLIN;
4912 nfd++;
4913 }
4914#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004915
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004916 ret = poll(fds, nfd, towait);
4917# ifdef FEAT_MZSCHEME
4918 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00004919 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004920 finished = FALSE;
4921# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004922
4923# ifdef FEAT_SNIFF
4924 if (ret < 0)
4925 sniff_disconnect(1);
4926 else if (want_sniff_request)
4927 {
4928 if (fds[SNIFF_IDX].revents & POLLHUP)
4929 sniff_disconnect(1);
4930 if (fds[SNIFF_IDX].revents & POLLIN)
4931 sniff_request_waiting = 1;
4932 }
4933# endif
4934# ifdef FEAT_XCLIPBOARD
4935 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4936 {
4937 xterm_update(); /* Maybe we should hand out clipboard */
4938 if (--ret == 0 && !input_available())
4939 /* Try again */
4940 finished = FALSE;
4941 }
4942# endif
4943# ifdef FEAT_MOUSE_GPM
4944 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4945 {
4946 *check_for_gpm = 1;
4947 }
4948# endif
4949# ifdef USE_XSMP
4950 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4951 {
4952 if (fds[xsmp_idx].revents & POLLIN)
4953 {
4954 busy = TRUE;
4955 xsmp_handle_requests();
4956 busy = FALSE;
4957 }
4958 else if (fds[xsmp_idx].revents & POLLHUP)
4959 {
4960 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004961 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004962 xsmp_close();
4963 }
4964 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004965 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004966 }
4967# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02004968#ifdef FEAT_NETBEANS_INTG
4969 if (ret > 0 && nb_idx != -1 && fds[nb_idx].revents & POLLIN)
4970 {
4971 netbeans_read();
4972 --ret;
4973 }
4974#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004975
4976
4977#else /* HAVE_SELECT */
4978
4979 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004980 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004981 fd_set rfds, efds;
4982 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004983 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004984
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004985# ifdef FEAT_MZSCHEME
4986 mzvim_check_threads();
4987 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4988 {
4989 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4990 mzquantum_used = TRUE;
4991 }
4992# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004993# ifdef __EMX__
4994 /* don't check for incoming chars if not in raw mode, because select()
4995 * always returns TRUE then (in some version of emx.dll) */
4996 if (curr_tmode != TMODE_RAW)
4997 return 0;
4998# endif
4999
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005000 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005001 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005002 tv.tv_sec = towait / 1000;
5003 tv.tv_usec = (towait % 1000) * (1000000/1000);
5004 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005005 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005006 else
5007 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005008
5009 /*
5010 * Select on ready for reading and exceptional condition (end of file).
5011 */
5012 FD_ZERO(&rfds); /* calls bzero() on a sun */
5013 FD_ZERO(&efds);
5014 FD_SET(fd, &rfds);
5015# if !defined(__QNX__) && !defined(__CYGWIN32__)
5016 /* For QNX select() always returns 1 if this is set. Why? */
5017 FD_SET(fd, &efds);
5018# endif
5019 maxfd = fd;
5020
5021# ifdef FEAT_SNIFF
5022 if (want_sniff_request)
5023 {
5024 FD_SET(fd_from_sniff, &rfds);
5025 FD_SET(fd_from_sniff, &efds);
5026 if (maxfd < fd_from_sniff)
5027 maxfd = fd_from_sniff;
5028 }
5029# endif
5030# ifdef FEAT_XCLIPBOARD
5031 if (xterm_Shell != (Widget)0)
5032 {
5033 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
5034 if (maxfd < ConnectionNumber(xterm_dpy))
5035 maxfd = ConnectionNumber(xterm_dpy);
5036 }
5037# endif
5038# ifdef FEAT_MOUSE_GPM
5039 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5040 {
5041 FD_SET(gpm_fd, &rfds);
5042 FD_SET(gpm_fd, &efds);
5043 if (maxfd < gpm_fd)
5044 maxfd = gpm_fd;
5045 }
5046# endif
5047# ifdef USE_XSMP
5048 if (xsmp_icefd != -1)
5049 {
5050 FD_SET(xsmp_icefd, &rfds);
5051 FD_SET(xsmp_icefd, &efds);
5052 if (maxfd < xsmp_icefd)
5053 maxfd = xsmp_icefd;
5054 }
5055# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005056#ifdef FEAT_NETBEANS_INTG
5057 if (nb_fd != -1)
5058 {
5059 FD_SET(nb_fd, &rfds);
5060 if (maxfd < nb_fd)
5061 maxfd = nb_fd;
5062 }
5063#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005064
5065# ifdef OLD_VMS
5066 /* Old VMS as v6.2 and older have broken select(). It waits more than
5067 * required. Should not be used */
5068 ret = 0;
5069# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005070 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
5071# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00005072# ifdef __TANDEM
5073 if (ret == -1 && errno == ENOTSUP)
5074 {
5075 FD_ZERO(&rfds);
5076 FD_ZERO(&efds);
5077 ret = 0;
5078 }
5079#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005080# ifdef FEAT_MZSCHEME
5081 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005082 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005083 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005084# endif
5085
5086# ifdef FEAT_SNIFF
5087 if (ret < 0 )
5088 sniff_disconnect(1);
5089 else if (ret > 0 && want_sniff_request)
5090 {
5091 if (FD_ISSET(fd_from_sniff, &efds))
5092 sniff_disconnect(1);
5093 if (FD_ISSET(fd_from_sniff, &rfds))
5094 sniff_request_waiting = 1;
5095 }
5096# endif
5097# ifdef FEAT_XCLIPBOARD
5098 if (ret > 0 && xterm_Shell != (Widget)0
5099 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
5100 {
5101 xterm_update(); /* Maybe we should hand out clipboard */
5102 /* continue looping when we only got the X event and the input
5103 * buffer is empty */
5104 if (--ret == 0 && !input_available())
5105 {
5106 /* Try again */
5107 finished = FALSE;
5108 }
5109 }
5110# endif
5111# ifdef FEAT_MOUSE_GPM
5112 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
5113 {
5114 if (FD_ISSET(gpm_fd, &efds))
5115 gpm_close();
5116 else if (FD_ISSET(gpm_fd, &rfds))
5117 *check_for_gpm = 1;
5118 }
5119# endif
5120# ifdef USE_XSMP
5121 if (ret > 0 && xsmp_icefd != -1)
5122 {
5123 if (FD_ISSET(xsmp_icefd, &efds))
5124 {
5125 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005126 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005127 xsmp_close();
5128 if (--ret == 0)
5129 finished = FALSE; /* keep going if event was only one */
5130 }
5131 else if (FD_ISSET(xsmp_icefd, &rfds))
5132 {
5133 busy = TRUE;
5134 xsmp_handle_requests();
5135 busy = FALSE;
5136 if (--ret == 0)
5137 finished = FALSE; /* keep going if event was only one */
5138 }
5139 }
5140# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005141#ifdef FEAT_NETBEANS_INTG
5142 if (ret > 0 && nb_fd != -1 && FD_ISSET(nb_fd, &rfds))
5143 {
5144 netbeans_read();
5145 --ret;
5146 }
5147#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005148
5149#endif /* HAVE_SELECT */
5150
5151#ifdef MAY_LOOP
5152 if (finished || msec == 0)
5153 break;
5154
5155 /* We're going to loop around again, find out for how long */
5156 if (msec > 0)
5157 {
5158# ifdef USE_START_TV
5159 struct timeval mtv;
5160
5161 /* Compute remaining wait time. */
5162 gettimeofday(&mtv, NULL);
5163 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
5164 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
5165# else
5166 /* Guess we got interrupted halfway. */
5167 msec = msec / 2;
5168# endif
5169 if (msec <= 0)
5170 break; /* waited long enough */
5171 }
5172#endif
5173 }
5174
5175 return (ret > 0);
5176}
5177
5178#ifndef VMS
5179
5180#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00005181/*
Bram Moolenaar02743632005-07-25 20:42:36 +00005182 * Expand a path into all matching files and/or directories. Handles "*",
5183 * "?", "[a-z]", "**", etc.
5184 * "path" has backslashes before chars that are not to be expanded.
5185 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005186 */
5187 int
5188mch_expandpath(gap, path, flags)
5189 garray_T *gap;
5190 char_u *path;
5191 int flags; /* EW_* flags */
5192{
Bram Moolenaar02743632005-07-25 20:42:36 +00005193 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005194}
5195#endif
5196
5197/*
5198 * mch_expand_wildcards() - this code does wild-card pattern matching using
5199 * the shell
5200 *
5201 * return OK for success, FAIL for error (you may lose some memory) and put
5202 * an error message in *file.
5203 *
5204 * num_pat is number of input patterns
5205 * pat is array of pointers to input patterns
5206 * num_file is pointer to number of matched file names
5207 * file is pointer to array of pointers to matched file names
5208 */
5209
5210#ifndef SEEK_SET
5211# define SEEK_SET 0
5212#endif
5213#ifndef SEEK_END
5214# define SEEK_END 2
5215#endif
5216
Bram Moolenaar5555acc2006-04-07 21:33:12 +00005217#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00005218
Bram Moolenaar071d4272004-06-13 20:20:40 +00005219 int
5220mch_expand_wildcards(num_pat, pat, num_file, file, flags)
5221 int num_pat;
5222 char_u **pat;
5223 int *num_file;
5224 char_u ***file;
5225 int flags; /* EW_* flags */
5226{
5227 int i;
5228 size_t len;
5229 char_u *p;
5230 int dir;
5231#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00005232 /*
5233 * This is the OS/2 implementation.
5234 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005235# define EXPL_ALLOC_INC 16
5236 char_u **expl_files;
5237 size_t files_alloced, files_free;
5238 char_u *buf;
5239 int has_wildcard;
5240
5241 *num_file = 0; /* default: no files found */
5242 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
5243 files_free = EXPL_ALLOC_INC; /* how much space is not used */
5244 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
5245 if (*file == NULL)
5246 return FAIL;
5247
5248 for (; num_pat > 0; num_pat--, pat++)
5249 {
5250 expl_files = NULL;
5251 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
5252 /* expand environment var or home dir */
5253 buf = expand_env_save(*pat);
5254 else
5255 buf = vim_strsave(*pat);
5256 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005257 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005258 if (has_wildcard) /* yes, so expand them */
5259 expl_files = (char_u **)_fnexplode(buf);
5260
5261 /*
5262 * return value of buf if no wildcards left,
5263 * OR if no match AND EW_NOTFOUND is set.
5264 */
5265 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
5266 || (expl_files == NULL && (flags & EW_NOTFOUND)))
5267 { /* simply save the current contents of *buf */
5268 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
5269 if (expl_files != NULL)
5270 {
5271 expl_files[0] = vim_strsave(buf);
5272 expl_files[1] = NULL;
5273 }
5274 }
5275 vim_free(buf);
5276
5277 /*
5278 * Count number of names resulting from expansion,
5279 * At the same time add a backslash to the end of names that happen to
5280 * be directories, and replace slashes with backslashes.
5281 */
5282 if (expl_files)
5283 {
5284 for (i = 0; (p = expl_files[i]) != NULL; i++)
5285 {
5286 dir = mch_isdir(p);
5287 /* If we don't want dirs and this is one, skip it */
5288 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5289 continue;
5290
Bram Moolenaara2031822006-03-07 22:29:51 +00005291 /* Skip files that are not executable if we check for that. */
5292 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
5293 continue;
5294
Bram Moolenaar071d4272004-06-13 20:20:40 +00005295 if (--files_free == 0)
5296 {
5297 /* need more room in table of pointers */
5298 files_alloced += EXPL_ALLOC_INC;
5299 *file = (char_u **)vim_realloc(*file,
5300 sizeof(char_u **) * files_alloced);
5301 if (*file == NULL)
5302 {
5303 EMSG(_(e_outofmem));
5304 *num_file = 0;
5305 return FAIL;
5306 }
5307 files_free = EXPL_ALLOC_INC;
5308 }
5309 slash_adjust(p);
5310 if (dir)
5311 {
5312 /* For a directory we add a '/', unless it's already
5313 * there. */
5314 len = STRLEN(p);
5315 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5316 {
5317 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005318 if (!after_pathsep((*file)[*num_file],
5319 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005320 {
5321 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005322 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005323 }
5324 }
5325 }
5326 else
5327 {
5328 (*file)[*num_file] = vim_strsave(p);
5329 }
5330
5331 /*
5332 * Error message already given by either alloc or vim_strsave.
5333 * Should return FAIL, but returning OK works also.
5334 */
5335 if ((*file)[*num_file] == NULL)
5336 break;
5337 (*num_file)++;
5338 }
5339 _fnexplodefree((char **)expl_files);
5340 }
5341 }
5342 return OK;
5343
5344#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005345 /*
5346 * This is the non-OS/2 implementation (really Unix).
5347 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005348 int j;
5349 char_u *tempname;
5350 char_u *command;
5351 FILE *fd;
5352 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005353#define STYLE_ECHO 0 /* use "echo", the default */
5354#define STYLE_GLOB 1 /* use "glob", for csh */
5355#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5356#define STYLE_PRINT 3 /* use "print -N", for zsh */
5357#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5358 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005359 int shell_style = STYLE_ECHO;
5360 int check_spaces;
5361 static int did_find_nul = FALSE;
5362 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005363 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005364 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005365
5366 *num_file = 0; /* default: no files found */
5367 *file = NULL;
5368
5369 /*
5370 * If there are no wildcards, just copy the names to allocated memory.
5371 * Saves a lot of time, because we don't have to start a new shell.
5372 */
5373 if (!have_wildcard(num_pat, pat))
5374 return save_patterns(num_pat, pat, num_file, file);
5375
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005376# ifdef HAVE_SANDBOX
5377 /* Don't allow any shell command in the sandbox. */
5378 if (sandbox != 0 && check_secure())
5379 return FAIL;
5380# endif
5381
Bram Moolenaar071d4272004-06-13 20:20:40 +00005382 /*
5383 * Don't allow the use of backticks in secure and restricted mode.
5384 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005385 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005386 for (i = 0; i < num_pat; ++i)
5387 if (vim_strchr(pat[i], '`') != NULL
5388 && (check_restricted() || check_secure()))
5389 return FAIL;
5390
5391 /*
5392 * get a name for the temp file
5393 */
5394 if ((tempname = vim_tempname('o')) == NULL)
5395 {
5396 EMSG(_(e_notmp));
5397 return FAIL;
5398 }
5399
5400 /*
5401 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005402 * file.
5403 * STYLE_BT: NL separated
5404 * If expanding `cmd` execute it directly.
5405 * STYLE_GLOB: NUL separated
5406 * If we use *csh, "glob" will work better than "echo".
5407 * STYLE_PRINT: NL or NUL separated
5408 * If we use *zsh, "print -N" will work better than "glob".
5409 * STYLE_VIMGLOB: NL separated
5410 * If we use *sh*, we define "vimglob()".
5411 * STYLE_ECHO: space separated.
5412 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005413 */
5414 if (num_pat == 1 && *pat[0] == '`'
5415 && (len = STRLEN(pat[0])) > 2
5416 && *(pat[0] + len - 1) == '`')
5417 shell_style = STYLE_BT;
5418 else if ((len = STRLEN(p_sh)) >= 3)
5419 {
5420 if (STRCMP(p_sh + len - 3, "csh") == 0)
5421 shell_style = STYLE_GLOB;
5422 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5423 shell_style = STYLE_PRINT;
5424 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005425 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5426 "sh") != NULL)
5427 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005428
Bram Moolenaarc7247912008-01-13 12:54:11 +00005429 /* Compute the length of the command. We need 2 extra bytes: for the
5430 * optional '&' and for the NUL.
5431 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005432 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005433 if (shell_style == STYLE_VIMGLOB)
5434 len += STRLEN(sh_vimglob_func);
5435
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005436 for (i = 0; i < num_pat; ++i)
5437 {
5438 /* Count the length of the patterns in the same way as they are put in
5439 * "command" below. */
5440#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005441 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005442#else
5443 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005444 for (j = 0; pat[i][j] != NUL; ++j)
5445 {
5446 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5447 ++len; /* may add a backslash */
5448 ++len;
5449 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005450#endif
5451 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005452 command = alloc(len);
5453 if (command == NULL)
5454 {
5455 /* out of memory */
5456 vim_free(tempname);
5457 return FAIL;
5458 }
5459
5460 /*
5461 * Build the shell command:
5462 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5463 * recognizes this).
5464 * - Add the shell command to print the expanded names.
5465 * - Add the temp file name.
5466 * - Add the file name patterns.
5467 */
5468 if (shell_style == STYLE_BT)
5469 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005470 /* change `command; command& ` to (command; command ) */
5471 STRCPY(command, "(");
5472 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005473 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005474 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005475 while (p > command && vim_iswhite(*p))
5476 --p;
5477 if (*p == '&') /* remove trailing '&' */
5478 {
5479 ampersent = TRUE;
5480 *p = ' ';
5481 }
5482 STRCAT(command, ">");
5483 }
5484 else
5485 {
5486 if (flags & EW_NOTFOUND)
5487 STRCPY(command, "set nonomatch; ");
5488 else
5489 STRCPY(command, "unset nonomatch; ");
5490 if (shell_style == STYLE_GLOB)
5491 STRCAT(command, "glob >");
5492 else if (shell_style == STYLE_PRINT)
5493 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005494 else if (shell_style == STYLE_VIMGLOB)
5495 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005496 else
5497 STRCAT(command, "echo >");
5498 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005499
Bram Moolenaar071d4272004-06-13 20:20:40 +00005500 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005501
Bram Moolenaar071d4272004-06-13 20:20:40 +00005502 if (shell_style != STYLE_BT)
5503 for (i = 0; i < num_pat; ++i)
5504 {
5505 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005506 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005507 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005508#ifdef USE_SYSTEM
5509 STRCAT(command, " \"");
5510 STRCAT(command, pat[i]);
5511 STRCAT(command, "\"");
5512#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005513 int intick = FALSE;
5514
Bram Moolenaar071d4272004-06-13 20:20:40 +00005515 p = command + STRLEN(command);
5516 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005517 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005518 {
5519 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005520 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005521 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5522 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005523 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005524 * backslash inside backticks, before a special character
5525 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005526 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005527 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5528 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005529 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005530 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005531 }
5532 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005533 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005534 /* Put a backslash before a special character, but not
5535 * when inside ``. */
5536 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005537
5538 /* Copy one character. */
5539 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005540 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005541 *p = NUL;
5542#endif
5543 }
5544 if (flags & EW_SILENT)
5545 show_shell_mess = FALSE;
5546 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00005547 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005548
5549 /*
5550 * Using zsh -G: If a pattern has no matches, it is just deleted from
5551 * the argument list, otherwise zsh gives an error message and doesn't
5552 * expand any other pattern.
5553 */
5554 if (shell_style == STYLE_PRINT)
5555 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5556
5557 /*
5558 * If we use -f then shell variables set in .cshrc won't get expanded.
5559 * vi can do it, so we will too, but it is only necessary if there is a "$"
5560 * in one of the patterns, otherwise we can still use the fast option.
5561 */
5562 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5563 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5564
5565 /*
5566 * execute the shell command
5567 */
5568 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5569
5570 /* When running in the background, give it some time to create the temp
5571 * file, but don't wait for it to finish. */
5572 if (ampersent)
5573 mch_delay(10L, TRUE);
5574
5575 extra_shell_arg = NULL; /* cleanup */
5576 show_shell_mess = TRUE;
5577 vim_free(command);
5578
Bram Moolenaarc7247912008-01-13 12:54:11 +00005579 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005580 {
5581 mch_remove(tempname);
5582 vim_free(tempname);
5583 /*
5584 * With interactive completion, the error message is not printed.
5585 * However with USE_SYSTEM, I don't know how to turn off error messages
5586 * from the shell, so screen may still get messed up -- webb.
5587 */
5588#ifndef USE_SYSTEM
5589 if (!(flags & EW_SILENT))
5590#endif
5591 {
5592 redraw_later_clear(); /* probably messed up screen */
5593 msg_putchar('\n'); /* clear bottom line quickly */
5594 cmdline_row = Rows - 1; /* continue on last line */
5595#ifdef USE_SYSTEM
5596 if (!(flags & EW_SILENT))
5597#endif
5598 {
5599 MSG(_(e_wildexpand));
5600 msg_start(); /* don't overwrite this message */
5601 }
5602 }
5603 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5604 * EW_NOTFOUND is given */
5605 if (shell_style == STYLE_BT)
5606 return FAIL;
5607 goto notfound;
5608 }
5609
5610 /*
5611 * read the names from the file into memory
5612 */
5613 fd = fopen((char *)tempname, READBIN);
5614 if (fd == NULL)
5615 {
5616 /* Something went wrong, perhaps a file name with a special char. */
5617 if (!(flags & EW_SILENT))
5618 {
5619 MSG(_(e_wildexpand));
5620 msg_start(); /* don't overwrite this message */
5621 }
5622 vim_free(tempname);
5623 goto notfound;
5624 }
5625 fseek(fd, 0L, SEEK_END);
5626 len = ftell(fd); /* get size of temp file */
5627 fseek(fd, 0L, SEEK_SET);
5628 buffer = alloc(len + 1);
5629 if (buffer == NULL)
5630 {
5631 /* out of memory */
5632 mch_remove(tempname);
5633 vim_free(tempname);
5634 fclose(fd);
5635 return FAIL;
5636 }
5637 i = fread((char *)buffer, 1, len, fd);
5638 fclose(fd);
5639 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00005640 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005641 {
5642 /* unexpected read error */
5643 EMSG2(_(e_notread), tempname);
5644 vim_free(tempname);
5645 vim_free(buffer);
5646 return FAIL;
5647 }
5648 vim_free(tempname);
5649
Bram Moolenaarc7247912008-01-13 12:54:11 +00005650# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005651 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5652 p = buffer;
5653 for (i = 0; i < len; ++i)
5654 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5655 *p++ = buffer[i];
5656 len = p - buffer;
5657# endif
5658
5659
5660 /* file names are separated with Space */
5661 if (shell_style == STYLE_ECHO)
5662 {
5663 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5664 p = buffer;
5665 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5666 {
5667 while (*p != ' ' && *p != '\n')
5668 ++p;
5669 p = skipwhite(p); /* skip to next entry */
5670 }
5671 }
5672 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005673 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005674 {
5675 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5676 p = buffer;
5677 for (i = 0; *p != NUL; ++i) /* count number of entries */
5678 {
5679 while (*p != '\n' && *p != NUL)
5680 ++p;
5681 if (*p != NUL)
5682 ++p;
5683 p = skipwhite(p); /* skip leading white space */
5684 }
5685 }
5686 /* file names are separated with NUL */
5687 else
5688 {
5689 /*
5690 * Some versions of zsh use spaces instead of NULs to separate
5691 * results. Only do this when there is no NUL before the end of the
5692 * buffer, otherwise we would never be able to use file names with
5693 * embedded spaces when zsh does use NULs.
5694 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5695 * don't check for spaces again.
5696 */
5697 check_spaces = FALSE;
5698 if (shell_style == STYLE_PRINT && !did_find_nul)
5699 {
5700 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaar78a15312009-05-15 19:33:18 +00005701 if (len && (int)STRLEN(buffer) < (int)len - 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005702 did_find_nul = TRUE;
5703 else
5704 check_spaces = TRUE;
5705 }
5706
5707 /*
5708 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5709 * already is one, for STYLE_GLOB it needs to be added.
5710 */
5711 if (len && buffer[len - 1] == NUL)
5712 --len;
5713 else
5714 buffer[len] = NUL;
5715 i = 0;
5716 for (p = buffer; p < buffer + len; ++p)
5717 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5718 {
5719 ++i;
5720 *p = NUL;
5721 }
5722 if (len)
5723 ++i; /* count last entry */
5724 }
5725 if (i == 0)
5726 {
5727 /*
5728 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5729 * /bin/sh will happily expand it to nothing rather than returning an
5730 * error; and hey, it's good to check anyway -- webb.
5731 */
5732 vim_free(buffer);
5733 goto notfound;
5734 }
5735 *num_file = i;
5736 *file = (char_u **)alloc(sizeof(char_u *) * i);
5737 if (*file == NULL)
5738 {
5739 /* out of memory */
5740 vim_free(buffer);
5741 return FAIL;
5742 }
5743
5744 /*
5745 * Isolate the individual file names.
5746 */
5747 p = buffer;
5748 for (i = 0; i < *num_file; ++i)
5749 {
5750 (*file)[i] = p;
5751 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005752 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
5753 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005754 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00005755 while (!(shell_style == STYLE_ECHO && *p == ' ')
5756 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005757 ++p;
5758 if (p == buffer + len) /* last entry */
5759 *p = NUL;
5760 else
5761 {
5762 *p++ = NUL;
5763 p = skipwhite(p); /* skip to next entry */
5764 }
5765 }
5766 else /* NUL separates */
5767 {
5768 while (*p && p < buffer + len) /* skip entry */
5769 ++p;
5770 ++p; /* skip NUL */
5771 }
5772 }
5773
5774 /*
5775 * Move the file names to allocated memory.
5776 */
5777 for (j = 0, i = 0; i < *num_file; ++i)
5778 {
5779 /* Require the files to exist. Helps when using /bin/sh */
5780 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5781 continue;
5782
5783 /* check if this entry should be included */
5784 dir = (mch_isdir((*file)[i]));
5785 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5786 continue;
5787
Bram Moolenaara2031822006-03-07 22:29:51 +00005788 /* Skip files that are not executable if we check for that. */
5789 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
5790 continue;
5791
Bram Moolenaar071d4272004-06-13 20:20:40 +00005792 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5793 if (p)
5794 {
5795 STRCPY(p, (*file)[i]);
5796 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00005797 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005798 (*file)[j++] = p;
5799 }
5800 }
5801 vim_free(buffer);
5802 *num_file = j;
5803
5804 if (*num_file == 0) /* rejected all entries */
5805 {
5806 vim_free(*file);
5807 *file = NULL;
5808 goto notfound;
5809 }
5810
5811 return OK;
5812
5813notfound:
5814 if (flags & EW_NOTFOUND)
5815 return save_patterns(num_pat, pat, num_file, file);
5816 return FAIL;
5817
5818#endif /* __EMX__ */
5819}
5820
5821#endif /* VMS */
5822
5823#ifndef __EMX__
5824 static int
5825save_patterns(num_pat, pat, num_file, file)
5826 int num_pat;
5827 char_u **pat;
5828 int *num_file;
5829 char_u ***file;
5830{
5831 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005832 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005833
5834 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5835 if (*file == NULL)
5836 return FAIL;
5837 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005838 {
5839 s = vim_strsave(pat[i]);
5840 if (s != NULL)
5841 /* Be compatible with expand_filename(): halve the number of
5842 * backslashes. */
5843 backslash_halve(s);
5844 (*file)[i] = s;
5845 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005846 *num_file = num_pat;
5847 return OK;
5848}
5849#endif
5850
5851
5852/*
5853 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5854 * expand.
5855 */
5856 int
5857mch_has_exp_wildcard(p)
5858 char_u *p;
5859{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005860 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005861 {
5862#ifndef OS2
5863 if (*p == '\\' && p[1] != NUL)
5864 ++p;
5865 else
5866#endif
5867 if (vim_strchr((char_u *)
5868#ifdef VMS
5869 "*?%"
5870#else
5871# ifdef OS2
5872 "*?"
5873# else
5874 "*?[{'"
5875# endif
5876#endif
5877 , *p) != NULL)
5878 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005879 }
5880 return FALSE;
5881}
5882
5883/*
5884 * Return TRUE if the string "p" contains a wildcard.
5885 * Don't recognize '~' at the end as a wildcard.
5886 */
5887 int
5888mch_has_wildcard(p)
5889 char_u *p;
5890{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005891 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005892 {
5893#ifndef OS2
5894 if (*p == '\\' && p[1] != NUL)
5895 ++p;
5896 else
5897#endif
5898 if (vim_strchr((char_u *)
5899#ifdef VMS
5900 "*?%$"
5901#else
5902# ifdef OS2
5903# ifdef VIM_BACKTICK
5904 "*?$`"
5905# else
5906 "*?$"
5907# endif
5908# else
5909 "*?[{`'$"
5910# endif
5911#endif
5912 , *p) != NULL
5913 || (*p == '~' && p[1] != NUL))
5914 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005915 }
5916 return FALSE;
5917}
5918
5919#ifndef __EMX__
5920 static int
5921have_wildcard(num, file)
5922 int num;
5923 char_u **file;
5924{
5925 int i;
5926
5927 for (i = 0; i < num; i++)
5928 if (mch_has_wildcard(file[i]))
5929 return 1;
5930 return 0;
5931}
5932
5933 static int
5934have_dollars(num, file)
5935 int num;
5936 char_u **file;
5937{
5938 int i;
5939
5940 for (i = 0; i < num; i++)
5941 if (vim_strchr(file[i], '$') != NULL)
5942 return TRUE;
5943 return FALSE;
5944}
5945#endif /* ifndef __EMX__ */
5946
5947#ifndef HAVE_RENAME
5948/*
5949 * Scaled-down version of rename(), which is missing in Xenix.
5950 * This version can only move regular files and will fail if the
5951 * destination exists.
5952 */
5953 int
5954mch_rename(src, dest)
5955 const char *src, *dest;
5956{
5957 struct stat st;
5958
5959 if (stat(dest, &st) >= 0) /* fail if destination exists */
5960 return -1;
5961 if (link(src, dest) != 0) /* link file to new name */
5962 return -1;
5963 if (mch_remove(src) == 0) /* delete link to old name */
5964 return 0;
5965 return -1;
5966}
5967#endif /* !HAVE_RENAME */
5968
5969#ifdef FEAT_MOUSE_GPM
5970/*
5971 * Initializes connection with gpm (if it isn't already opened)
5972 * Return 1 if succeeded (or connection already opened), 0 if failed
5973 */
5974 static int
5975gpm_open()
5976{
5977 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5978
5979 if (!gpm_flag)
5980 {
5981 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5982 gpm_connect.defaultMask = ~GPM_HARD;
5983 /* Default handling for mouse move*/
5984 gpm_connect.minMod = 0; /* Handle any modifier keys */
5985 gpm_connect.maxMod = 0xffff;
5986 if (Gpm_Open(&gpm_connect, 0) > 0)
5987 {
5988 /* gpm library tries to handling TSTP causes
5989 * problems. Anyways, we close connection to Gpm whenever
5990 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005991 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00005992 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00005993# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00005994 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00005995# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005996 return 1; /* succeed */
5997 }
5998 if (gpm_fd == -2)
5999 Gpm_Close(); /* We don't want to talk to xterm via gpm */
6000 return 0;
6001 }
6002 return 1; /* already open */
6003}
6004
6005/*
6006 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00006007 */
6008 static void
6009gpm_close()
6010{
6011 if (gpm_flag && gpm_fd >= 0) /* if Open */
6012 Gpm_Close();
6013}
6014
6015/* Reads gpm event and adds special keys to input buf. Returns length of
6016 * generated key sequence.
6017 * This function is made after gui_send_mouse_event
6018 */
6019 static int
6020mch_gpm_process()
6021{
6022 int button;
6023 static Gpm_Event gpm_event;
6024 char_u string[6];
6025 int_u vim_modifiers;
6026 int row,col;
6027 unsigned char buttons_mask;
6028 unsigned char gpm_modifiers;
6029 static unsigned char old_buttons = 0;
6030
6031 Gpm_GetEvent(&gpm_event);
6032
6033#ifdef FEAT_GUI
6034 /* Don't put events in the input queue now. */
6035 if (hold_gui_events)
6036 return 0;
6037#endif
6038
6039 row = gpm_event.y - 1;
6040 col = gpm_event.x - 1;
6041
6042 string[0] = ESC; /* Our termcode */
6043 string[1] = 'M';
6044 string[2] = 'G';
6045 switch (GPM_BARE_EVENTS(gpm_event.type))
6046 {
6047 case GPM_DRAG:
6048 string[3] = MOUSE_DRAG;
6049 break;
6050 case GPM_DOWN:
6051 buttons_mask = gpm_event.buttons & ~old_buttons;
6052 old_buttons = gpm_event.buttons;
6053 switch (buttons_mask)
6054 {
6055 case GPM_B_LEFT:
6056 button = MOUSE_LEFT;
6057 break;
6058 case GPM_B_MIDDLE:
6059 button = MOUSE_MIDDLE;
6060 break;
6061 case GPM_B_RIGHT:
6062 button = MOUSE_RIGHT;
6063 break;
6064 default:
6065 return 0;
6066 /*Don't know what to do. Can more than one button be
6067 * reported in one event? */
6068 }
6069 string[3] = (char_u)(button | 0x20);
6070 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
6071 break;
6072 case GPM_UP:
6073 string[3] = MOUSE_RELEASE;
6074 old_buttons &= ~gpm_event.buttons;
6075 break;
6076 default:
6077 return 0;
6078 }
6079 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
6080 gpm_modifiers = gpm_event.modifiers;
6081 vim_modifiers = 0x0;
6082 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
6083 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
6084 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
6085 */
6086 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
6087 vim_modifiers |= MOUSE_SHIFT;
6088
6089 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
6090 vim_modifiers |= MOUSE_CTRL;
6091 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
6092 vim_modifiers |= MOUSE_ALT;
6093 string[3] |= vim_modifiers;
6094 string[4] = (char_u)(col + ' ' + 1);
6095 string[5] = (char_u)(row + ' ' + 1);
6096 add_to_input_buf(string, 6);
6097 return 6;
6098}
6099#endif /* FEAT_MOUSE_GPM */
6100
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006101#ifdef FEAT_SYSMOUSE
6102/*
6103 * Initialize connection with sysmouse.
6104 * Let virtual console inform us with SIGUSR2 for pending sysmouse
6105 * output, any sysmouse output than will be processed via sig_sysmouse().
6106 * Return OK if succeeded, FAIL if failed.
6107 */
6108 static int
6109sysmouse_open()
6110{
6111 struct mouse_info mouse;
6112
6113 mouse.operation = MOUSE_MODE;
6114 mouse.u.mode.mode = 0;
6115 mouse.u.mode.signal = SIGUSR2;
6116 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
6117 {
6118 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
6119 mouse.operation = MOUSE_SHOW;
6120 ioctl(1, CONS_MOUSECTL, &mouse);
6121 return OK;
6122 }
6123 return FAIL;
6124}
6125
6126/*
6127 * Stop processing SIGUSR2 signals, and also make sure that
6128 * virtual console do not send us any sysmouse related signal.
6129 */
6130 static void
6131sysmouse_close()
6132{
6133 struct mouse_info mouse;
6134
6135 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
6136 mouse.operation = MOUSE_MODE;
6137 mouse.u.mode.mode = 0;
6138 mouse.u.mode.signal = 0;
6139 ioctl(1, CONS_MOUSECTL, &mouse);
6140}
6141
6142/*
6143 * Gets info from sysmouse and adds special keys to input buf.
6144 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006145 static RETSIGTYPE
6146sig_sysmouse SIGDEFARG(sigarg)
6147{
6148 struct mouse_info mouse;
6149 struct video_info video;
6150 char_u string[6];
6151 int row, col;
6152 int button;
6153 int buttons;
6154 static int oldbuttons = 0;
6155
6156#ifdef FEAT_GUI
6157 /* Don't put events in the input queue now. */
6158 if (hold_gui_events)
6159 return;
6160#endif
6161
6162 mouse.operation = MOUSE_GETINFO;
6163 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
6164 && ioctl(1, FBIO_MODEINFO, &video) != -1
6165 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
6166 && video.vi_cheight > 0 && video.vi_cwidth > 0)
6167 {
6168 row = mouse.u.data.y / video.vi_cheight;
6169 col = mouse.u.data.x / video.vi_cwidth;
6170 buttons = mouse.u.data.buttons;
6171 string[0] = ESC; /* Our termcode */
6172 string[1] = 'M';
6173 string[2] = 'S';
6174 if (oldbuttons == buttons && buttons != 0)
6175 {
6176 button = MOUSE_DRAG;
6177 }
6178 else
6179 {
6180 switch (buttons)
6181 {
6182 case 0:
6183 button = MOUSE_RELEASE;
6184 break;
6185 case 1:
6186 button = MOUSE_LEFT;
6187 break;
6188 case 2:
6189 button = MOUSE_MIDDLE;
6190 break;
6191 case 4:
6192 button = MOUSE_RIGHT;
6193 break;
6194 default:
6195 return;
6196 }
6197 oldbuttons = buttons;
6198 }
6199 string[3] = (char_u)(button);
6200 string[4] = (char_u)(col + ' ' + 1);
6201 string[5] = (char_u)(row + ' ' + 1);
6202 add_to_input_buf(string, 6);
6203 }
6204 return;
6205}
6206#endif /* FEAT_SYSMOUSE */
6207
Bram Moolenaar071d4272004-06-13 20:20:40 +00006208#if defined(FEAT_LIBCALL) || defined(PROTO)
6209typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
6210typedef char_u * (*INTPROCSTR)__ARGS((int));
6211typedef int (*STRPROCINT)__ARGS((char_u *));
6212typedef int (*INTPROCINT)__ARGS((int));
6213
6214/*
6215 * Call a DLL routine which takes either a string or int param
6216 * and returns an allocated string.
6217 */
6218 int
6219mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
6220 char_u *libname;
6221 char_u *funcname;
6222 char_u *argstring; /* NULL when using a argint */
6223 int argint;
6224 char_u **string_result;/* NULL when using number_result */
6225 int *number_result;
6226{
6227# if defined(USE_DLOPEN)
6228 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006229 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006230# else
6231 shl_t hinstLib;
6232# endif
6233 STRPROCSTR ProcAdd;
6234 INTPROCSTR ProcAddI;
6235 char_u *retval_str = NULL;
6236 int retval_int = 0;
6237 int success = FALSE;
6238
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006239 /*
6240 * Get a handle to the DLL module.
6241 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006242# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006243 /* First clear any error, it's not cleared by the dlopen() call. */
6244 (void)dlerror();
6245
Bram Moolenaar071d4272004-06-13 20:20:40 +00006246 hinstLib = dlopen((char *)libname, RTLD_LAZY
6247# ifdef RTLD_LOCAL
6248 | RTLD_LOCAL
6249# endif
6250 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006251 if (hinstLib == NULL)
6252 {
6253 /* "dlerr" must be used before dlclose() */
6254 dlerr = (char *)dlerror();
6255 if (dlerr != NULL)
6256 EMSG2(_("dlerror = \"%s\""), dlerr);
6257 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006258# else
6259 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
6260# endif
6261
6262 /* If the handle is valid, try to get the function address. */
6263 if (hinstLib != NULL)
6264 {
6265# ifdef HAVE_SETJMP_H
6266 /*
6267 * Catch a crash when calling the library function. For example when
6268 * using a number where a string pointer is expected.
6269 */
6270 mch_startjmp();
6271 if (SETJMP(lc_jump_env) != 0)
6272 {
6273 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006274# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006275 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006276# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006277 mch_didjmp();
6278 }
6279 else
6280# endif
6281 {
6282 retval_str = NULL;
6283 retval_int = 0;
6284
6285 if (argstring != NULL)
6286 {
6287# if defined(USE_DLOPEN)
6288 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006289 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006290# else
6291 if (shl_findsym(&hinstLib, (const char *)funcname,
6292 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
6293 ProcAdd = NULL;
6294# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006295 if ((success = (ProcAdd != NULL
6296# if defined(USE_DLOPEN)
6297 && dlerr == NULL
6298# endif
6299 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006300 {
6301 if (string_result == NULL)
6302 retval_int = ((STRPROCINT)ProcAdd)(argstring);
6303 else
6304 retval_str = (ProcAdd)(argstring);
6305 }
6306 }
6307 else
6308 {
6309# if defined(USE_DLOPEN)
6310 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006311 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006312# else
6313 if (shl_findsym(&hinstLib, (const char *)funcname,
6314 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
6315 ProcAddI = NULL;
6316# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006317 if ((success = (ProcAddI != NULL
6318# if defined(USE_DLOPEN)
6319 && dlerr == NULL
6320# endif
6321 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006322 {
6323 if (string_result == NULL)
6324 retval_int = ((INTPROCINT)ProcAddI)(argint);
6325 else
6326 retval_str = (ProcAddI)(argint);
6327 }
6328 }
6329
6330 /* Save the string before we free the library. */
6331 /* Assume that a "1" or "-1" result is an illegal pointer. */
6332 if (string_result == NULL)
6333 *number_result = retval_int;
6334 else if (retval_str != NULL
6335 && retval_str != (char_u *)1
6336 && retval_str != (char_u *)-1)
6337 *string_result = vim_strsave(retval_str);
6338 }
6339
6340# ifdef HAVE_SETJMP_H
6341 mch_endjmp();
6342# ifdef SIGHASARG
6343 if (lc_signal != 0)
6344 {
6345 int i;
6346
6347 /* try to find the name of this signal */
6348 for (i = 0; signal_info[i].sig != -1; i++)
6349 if (lc_signal == signal_info[i].sig)
6350 break;
6351 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6352 }
6353# endif
6354# endif
6355
Bram Moolenaar071d4272004-06-13 20:20:40 +00006356# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006357 /* "dlerr" must be used before dlclose() */
6358 if (dlerr != NULL)
6359 EMSG2(_("dlerror = \"%s\""), dlerr);
6360
6361 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006362 (void)dlclose(hinstLib);
6363# else
6364 (void)shl_unload(hinstLib);
6365# endif
6366 }
6367
6368 if (!success)
6369 {
6370 EMSG2(_(e_libcall), funcname);
6371 return FAIL;
6372 }
6373
6374 return OK;
6375}
6376#endif
6377
6378#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6379static int xterm_trace = -1; /* default: disabled */
6380static int xterm_button;
6381
6382/*
6383 * Setup a dummy window for X selections in a terminal.
6384 */
6385 void
6386setup_term_clip()
6387{
6388 int z = 0;
6389 char *strp = "";
6390 Widget AppShell;
6391
6392 if (!x_connect_to_server())
6393 return;
6394
6395 open_app_context();
6396 if (app_context != NULL && xterm_Shell == (Widget)0)
6397 {
6398 int (*oldhandler)();
6399#if defined(HAVE_SETJMP_H)
6400 int (*oldIOhandler)();
6401#endif
6402# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6403 struct timeval start_tv;
6404
6405 if (p_verbose > 0)
6406 gettimeofday(&start_tv, NULL);
6407# endif
6408
6409 /* Ignore X errors while opening the display */
6410 oldhandler = XSetErrorHandler(x_error_check);
6411
6412#if defined(HAVE_SETJMP_H)
6413 /* Ignore X IO errors while opening the display */
6414 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6415 mch_startjmp();
6416 if (SETJMP(lc_jump_env) != 0)
6417 {
6418 mch_didjmp();
6419 xterm_dpy = NULL;
6420 }
6421 else
6422#endif
6423 {
6424 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6425 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6426#if defined(HAVE_SETJMP_H)
6427 mch_endjmp();
6428#endif
6429 }
6430
6431#if defined(HAVE_SETJMP_H)
6432 /* Now handle X IO errors normally. */
6433 (void)XSetIOErrorHandler(oldIOhandler);
6434#endif
6435 /* Now handle X errors normally. */
6436 (void)XSetErrorHandler(oldhandler);
6437
6438 if (xterm_dpy == NULL)
6439 {
6440 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006441 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006442 return;
6443 }
6444
6445 /* Catch terminating error of the X server connection. */
6446 (void)XSetIOErrorHandler(x_IOerror_handler);
6447
6448# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6449 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006450 {
6451 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006452 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006453 verbose_leave();
6454 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006455# endif
6456
6457 /* Create a Shell to make converters work. */
6458 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6459 applicationShellWidgetClass, xterm_dpy,
6460 NULL);
6461 if (AppShell == (Widget)0)
6462 return;
6463 xterm_Shell = XtVaCreatePopupShell("VIM",
6464 topLevelShellWidgetClass, AppShell,
6465 XtNmappedWhenManaged, 0,
6466 XtNwidth, 1,
6467 XtNheight, 1,
6468 NULL);
6469 if (xterm_Shell == (Widget)0)
6470 return;
6471
6472 x11_setup_atoms(xterm_dpy);
6473 if (x11_display == NULL)
6474 x11_display = xterm_dpy;
6475
6476 XtRealizeWidget(xterm_Shell);
6477 XSync(xterm_dpy, False);
6478 xterm_update();
6479 }
6480 if (xterm_Shell != (Widget)0)
6481 {
6482 clip_init(TRUE);
6483 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6484 x11_window = (Window)atol(strp);
6485 /* Check if $WINDOWID is valid. */
6486 if (test_x11_window(xterm_dpy) == FAIL)
6487 x11_window = 0;
6488 if (x11_window != 0)
6489 xterm_trace = 0;
6490 }
6491}
6492
6493 void
6494start_xterm_trace(button)
6495 int button;
6496{
6497 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6498 return;
6499 xterm_trace = 1;
6500 xterm_button = button;
6501 do_xterm_trace();
6502}
6503
6504
6505 void
6506stop_xterm_trace()
6507{
6508 if (xterm_trace < 0)
6509 return;
6510 xterm_trace = 0;
6511}
6512
6513/*
6514 * Query the xterm pointer and generate mouse termcodes if necessary
6515 * return TRUE if dragging is active, else FALSE
6516 */
6517 static int
6518do_xterm_trace()
6519{
6520 Window root, child;
6521 int root_x, root_y;
6522 int win_x, win_y;
6523 int row, col;
6524 int_u mask_return;
6525 char_u buf[50];
6526 char_u *strp;
6527 long got_hints;
6528 static char_u *mouse_code;
6529 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6530 static int prev_row = 0, prev_col = 0;
6531 static XSizeHints xterm_hints;
6532
6533 if (xterm_trace <= 0)
6534 return FALSE;
6535
6536 if (xterm_trace == 1)
6537 {
6538 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006539 * have changed recently. */
6540 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6541 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006542 || xterm_hints.width_inc <= 1
6543 || xterm_hints.height_inc <= 1)
6544 {
6545 xterm_trace = -1; /* Not enough data -- disable tracing */
6546 return FALSE;
6547 }
6548
6549 /* Rely on the same mouse code for the duration of this */
6550 mouse_code = find_termcode(mouse_name);
6551 prev_row = mouse_row;
6552 prev_row = mouse_col;
6553 xterm_trace = 2;
6554
6555 /* Find the offset of the chars, there might be a scrollbar on the
6556 * left of the window and/or a menu on the top (eterm etc.) */
6557 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6558 &win_x, &win_y, &mask_return);
6559 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6560 - (xterm_hints.height_inc / 2);
6561 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6562 xterm_hints.y = 2;
6563 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6564 - (xterm_hints.width_inc / 2);
6565 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6566 xterm_hints.x = 2;
6567 return TRUE;
6568 }
6569 if (mouse_code == NULL)
6570 {
6571 xterm_trace = 0;
6572 return FALSE;
6573 }
6574
6575 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6576 &win_x, &win_y, &mask_return);
6577
6578 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6579 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6580 if (row == prev_row && col == prev_col)
6581 return TRUE;
6582
6583 STRCPY(buf, mouse_code);
6584 strp = buf + STRLEN(buf);
6585 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6586 *strp++ = (char_u)(col + ' ' + 1);
6587 *strp++ = (char_u)(row + ' ' + 1);
6588 *strp = 0;
6589 add_to_input_buf(buf, STRLEN(buf));
6590
6591 prev_row = row;
6592 prev_col = col;
6593 return TRUE;
6594}
6595
6596# if defined(FEAT_GUI) || defined(PROTO)
6597/*
6598 * Destroy the display, window and app_context. Required for GTK.
6599 */
6600 void
6601clear_xterm_clip()
6602{
6603 if (xterm_Shell != (Widget)0)
6604 {
6605 XtDestroyWidget(xterm_Shell);
6606 xterm_Shell = (Widget)0;
6607 }
6608 if (xterm_dpy != NULL)
6609 {
Bram Moolenaare8208012008-06-20 09:59:25 +00006610# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006611 /* Lesstif and Solaris crash here, lose some memory */
6612 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00006613# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006614 if (x11_display == xterm_dpy)
6615 x11_display = NULL;
6616 xterm_dpy = NULL;
6617 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006618# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006619 if (app_context != (XtAppContext)NULL)
6620 {
6621 /* Lesstif and Solaris crash here, lose some memory */
6622 XtDestroyApplicationContext(app_context);
6623 app_context = (XtAppContext)NULL;
6624 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006625# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006626}
6627# endif
6628
6629/*
6630 * Catch up with any queued X events. This may put keyboard input into the
6631 * input buffer, call resize call-backs, trigger timers etc. If there is
6632 * nothing in the X event queue (& no timers pending), then we return
6633 * immediately.
6634 */
6635 static void
6636xterm_update()
6637{
6638 XEvent event;
6639
6640 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6641 {
6642 XtAppNextEvent(app_context, &event);
6643#ifdef FEAT_CLIENTSERVER
6644 {
6645 XPropertyEvent *e = (XPropertyEvent *)&event;
6646
6647 if (e->type == PropertyNotify && e->window == commWindow
6648 && e->atom == commProperty && e->state == PropertyNewValue)
6649 serverEventProc(xterm_dpy, &event);
6650 }
6651#endif
6652 XtDispatchEvent(&event);
6653 }
6654}
6655
6656 int
6657clip_xterm_own_selection(cbd)
6658 VimClipboard *cbd;
6659{
6660 if (xterm_Shell != (Widget)0)
6661 return clip_x11_own_selection(xterm_Shell, cbd);
6662 return FAIL;
6663}
6664
6665 void
6666clip_xterm_lose_selection(cbd)
6667 VimClipboard *cbd;
6668{
6669 if (xterm_Shell != (Widget)0)
6670 clip_x11_lose_selection(xterm_Shell, cbd);
6671}
6672
6673 void
6674clip_xterm_request_selection(cbd)
6675 VimClipboard *cbd;
6676{
6677 if (xterm_Shell != (Widget)0)
6678 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6679}
6680
6681 void
6682clip_xterm_set_selection(cbd)
6683 VimClipboard *cbd;
6684{
6685 clip_x11_set_selection(cbd);
6686}
6687#endif
6688
6689
6690#if defined(USE_XSMP) || defined(PROTO)
6691/*
6692 * Code for X Session Management Protocol.
6693 */
6694static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6695static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6696static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6697static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6698static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6699
6700
6701# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6702static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6703
6704/*
6705 * This is our chance to ask the user if they want to save,
6706 * or abort the logout
6707 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006708 static void
6709xsmp_handle_interaction(smc_conn, client_data)
6710 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006711 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006712{
6713 cmdmod_T save_cmdmod;
6714 int cancel_shutdown = False;
6715
6716 save_cmdmod = cmdmod;
6717 cmdmod.confirm = TRUE;
6718 if (check_changed_any(FALSE))
6719 /* Mustn't logout */
6720 cancel_shutdown = True;
6721 cmdmod = save_cmdmod;
6722 setcursor(); /* position cursor */
6723 out_flush();
6724
6725 /* Done interaction */
6726 SmcInteractDone(smc_conn, cancel_shutdown);
6727
6728 /* Finish off
6729 * Only end save-yourself here if we're not cancelling shutdown;
6730 * we'll get a cancelled callback later in which we'll end it.
6731 * Hopefully get around glitchy SMs (like GNOME-1)
6732 */
6733 if (!cancel_shutdown)
6734 {
6735 xsmp.save_yourself = False;
6736 SmcSaveYourselfDone(smc_conn, True);
6737 }
6738}
6739# endif
6740
6741/*
6742 * Callback that starts save-yourself.
6743 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006744 static void
6745xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6746 shutdown, interact_style, fast)
6747 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006748 SmPointer client_data UNUSED;
6749 int save_type UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006750 Bool shutdown;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006751 int interact_style UNUSED;
6752 Bool fast UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006753{
6754 /* Handle already being in saveyourself */
6755 if (xsmp.save_yourself)
6756 SmcSaveYourselfDone(smc_conn, True);
6757 xsmp.save_yourself = True;
6758 xsmp.shutdown = shutdown;
6759
6760 /* First up, preserve all files */
6761 out_flush();
6762 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6763
6764 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006765 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006766
6767# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6768 /* Now see if we can ask about unsaved files */
6769 if (shutdown && !fast && gui.in_use)
6770 /* Need to interact with user, but need SM's permission */
6771 SmcInteractRequest(smc_conn, SmDialogError,
6772 xsmp_handle_interaction, client_data);
6773 else
6774# endif
6775 {
6776 /* Can stop the cycle here */
6777 SmcSaveYourselfDone(smc_conn, True);
6778 xsmp.save_yourself = False;
6779 }
6780}
6781
6782
6783/*
6784 * Callback to warn us of imminent death.
6785 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006786 static void
6787xsmp_die(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006788 SmcConn smc_conn UNUSED;
6789 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006790{
6791 xsmp_close();
6792
6793 /* quit quickly leaving swapfiles for modified buffers behind */
6794 getout_preserve_modified(0);
6795}
6796
6797
6798/*
6799 * Callback to tell us that save-yourself has completed.
6800 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006801 static void
6802xsmp_save_complete(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006803 SmcConn smc_conn UNUSED;
6804 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006805{
6806 xsmp.save_yourself = False;
6807}
6808
6809
6810/*
6811 * Callback to tell us that an instigated shutdown was cancelled
6812 * (maybe even by us)
6813 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006814 static void
6815xsmp_shutdown_cancelled(smc_conn, client_data)
6816 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006817 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006818{
6819 if (xsmp.save_yourself)
6820 SmcSaveYourselfDone(smc_conn, True);
6821 xsmp.save_yourself = False;
6822 xsmp.shutdown = False;
6823}
6824
6825
6826/*
6827 * Callback to tell us that a new ICE connection has been established.
6828 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006829 static void
6830xsmp_ice_connection(iceConn, clientData, opening, watchData)
6831 IceConn iceConn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006832 IcePointer clientData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006833 Bool opening;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00006834 IcePointer *watchData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006835{
6836 /* Intercept creation of ICE connection fd */
6837 if (opening)
6838 {
6839 xsmp_icefd = IceConnectionNumber(iceConn);
6840 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6841 }
6842}
6843
6844
6845/* Handle any ICE processing that's required; return FAIL if SM lost */
6846 int
6847xsmp_handle_requests()
6848{
6849 Bool rep;
6850
6851 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6852 == IceProcessMessagesIOError)
6853 {
6854 /* Lost ICE */
6855 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006856 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006857 xsmp_close();
6858 return FAIL;
6859 }
6860 else
6861 return OK;
6862}
6863
6864static int dummy;
6865
6866/* Set up X Session Management Protocol */
6867 void
6868xsmp_init(void)
6869{
6870 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006871 SmcCallbacks smcallbacks;
6872#if 0
6873 SmPropValue smname;
6874 SmProp smnameprop;
6875 SmProp *smprops[1];
6876#endif
6877
6878 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006879 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006880
6881 xsmp.save_yourself = xsmp.shutdown = False;
6882
6883 /* Set up SM callbacks - must have all, even if they're not used */
6884 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6885 smcallbacks.save_yourself.client_data = NULL;
6886 smcallbacks.die.callback = xsmp_die;
6887 smcallbacks.die.client_data = NULL;
6888 smcallbacks.save_complete.callback = xsmp_save_complete;
6889 smcallbacks.save_complete.client_data = NULL;
6890 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6891 smcallbacks.shutdown_cancelled.client_data = NULL;
6892
6893 /* Set up a watch on ICE connection creations. The "dummy" argument is
6894 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6895 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6896 {
6897 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006898 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006899 return;
6900 }
6901
6902 /* Create an SM connection */
6903 xsmp.smcconn = SmcOpenConnection(
6904 NULL,
6905 NULL,
6906 SmProtoMajor,
6907 SmProtoMinor,
6908 SmcSaveYourselfProcMask | SmcDieProcMask
6909 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6910 &smcallbacks,
6911 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00006912 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00006913 sizeof(errorstring),
6914 errorstring);
6915 if (xsmp.smcconn == NULL)
6916 {
6917 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00006918
Bram Moolenaar071d4272004-06-13 20:20:40 +00006919 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006920 {
6921 vim_snprintf(errorreport, sizeof(errorreport),
6922 _("XSMP SmcOpenConnection failed: %s"), errorstring);
6923 verb_msg((char_u *)errorreport);
6924 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006925 return;
6926 }
6927 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6928
6929#if 0
6930 /* ID ourselves */
6931 smname.value = "vim";
6932 smname.length = 3;
6933 smnameprop.name = "SmProgram";
6934 smnameprop.type = "SmARRAY8";
6935 smnameprop.num_vals = 1;
6936 smnameprop.vals = &smname;
6937
6938 smprops[0] = &smnameprop;
6939 SmcSetProperties(xsmp.smcconn, 1, smprops);
6940#endif
6941}
6942
6943
6944/* Shut down XSMP comms. */
6945 void
6946xsmp_close()
6947{
6948 if (xsmp_icefd != -1)
6949 {
6950 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00006951 if (xsmp.clientid != NULL)
6952 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00006953 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006954 xsmp_icefd = -1;
6955 }
6956}
6957#endif /* USE_XSMP */
6958
6959
6960#ifdef EBCDIC
6961/* Translate character to its CTRL- value */
6962char CtrlTable[] =
6963{
6964/* 00 - 5E */
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, 0,
6967 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6968 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6969 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6970 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6971/* ^ */ 0x1E,
6972/* - */ 0x1F,
6973/* 61 - 6C */
6974 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6975/* _ */ 0x1F,
6976/* 6E - 80 */
6977 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6978/* a */ 0x01,
6979/* b */ 0x02,
6980/* c */ 0x03,
6981/* d */ 0x37,
6982/* e */ 0x2D,
6983/* f */ 0x2E,
6984/* g */ 0x2F,
6985/* h */ 0x16,
6986/* i */ 0x05,
6987/* 8A - 90 */
6988 0, 0, 0, 0, 0, 0, 0,
6989/* j */ 0x15,
6990/* k */ 0x0B,
6991/* l */ 0x0C,
6992/* m */ 0x0D,
6993/* n */ 0x0E,
6994/* o */ 0x0F,
6995/* p */ 0x10,
6996/* q */ 0x11,
6997/* r */ 0x12,
6998/* 9A - A1 */
6999 0, 0, 0, 0, 0, 0, 0, 0,
7000/* s */ 0x13,
7001/* t */ 0x3C,
7002/* u */ 0x3D,
7003/* v */ 0x32,
7004/* w */ 0x26,
7005/* x */ 0x18,
7006/* y */ 0x19,
7007/* z */ 0x3F,
7008/* AA - AC */
7009 0, 0, 0,
7010/* [ */ 0x27,
7011/* AE - BC */
7012 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7013/* ] */ 0x1D,
7014/* BE - C0 */ 0, 0, 0,
7015/* A */ 0x01,
7016/* B */ 0x02,
7017/* C */ 0x03,
7018/* D */ 0x37,
7019/* E */ 0x2D,
7020/* F */ 0x2E,
7021/* G */ 0x2F,
7022/* H */ 0x16,
7023/* I */ 0x05,
7024/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
7025/* J */ 0x15,
7026/* K */ 0x0B,
7027/* L */ 0x0C,
7028/* M */ 0x0D,
7029/* N */ 0x0E,
7030/* O */ 0x0F,
7031/* P */ 0x10,
7032/* Q */ 0x11,
7033/* R */ 0x12,
7034/* DA - DF */ 0, 0, 0, 0, 0, 0,
7035/* \ */ 0x1C,
7036/* E1 */ 0,
7037/* S */ 0x13,
7038/* T */ 0x3C,
7039/* U */ 0x3D,
7040/* V */ 0x32,
7041/* W */ 0x26,
7042/* X */ 0x18,
7043/* Y */ 0x19,
7044/* Z */ 0x3F,
7045/* EA - FF*/ 0, 0, 0, 0, 0, 0,
7046 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7047};
7048
7049char MetaCharTable[]=
7050{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7051 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
7052 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
7053 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
7054 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
7055};
7056
7057
7058/* TODO: Use characters NOT numbers!!! */
7059char CtrlCharTable[]=
7060{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7061 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
7062 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
7063 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
7064 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
7065};
7066
7067
7068#endif