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