blob: 8f059be8fe3031089b93952b8e308a55367b429a [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 Moolenaar5bd32f42014-04-02 14:05:38 +020049#ifdef HAVE_SMACK
50# include <attr/xattr.h>
51# include <linux/xattr.h>
52# ifndef SMACK_LABEL_LEN
53# define SMACK_LABEL_LEN 1024
54# endif
55#endif
56
Bram Moolenaar071d4272004-06-13 20:20:40 +000057/*
58 * Use this prototype for select, some include files have a wrong prototype
59 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000060#ifndef __TANDEM
61# undef select
62# ifdef __BEOS__
63# define select beos_select
64# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000065#endif
66
Bram Moolenaara2442432007-04-26 14:26:37 +000067#ifdef __CYGWIN__
68# ifndef WIN32
Bram Moolenaar0d1498e2008-06-29 12:00:49 +000069# include <cygwin/version.h>
70# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() and/or
71 * for cygwin_conv_path() */
Bram Moolenaar693e40c2013-02-26 14:56:42 +010072# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
73# define WIN32_LEAN_AND_MEAN
74# include <windows.h>
75# include "winclip.pro"
76# endif
Bram Moolenaara2442432007-04-26 14:26:37 +000077# endif
78#endif
79
Bram Moolenaar071d4272004-06-13 20:20:40 +000080#if defined(HAVE_SELECT)
81extern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
82#endif
83
84#ifdef FEAT_MOUSE_GPM
85# include <gpm.h>
86/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
87 * I just copied relevant defines here. A cleaner solution would be to put gpm
88 * code into separate file and include there linux/keyboard.h
89 */
90/* #include <linux/keyboard.h> */
91# define KG_SHIFT 0
92# define KG_CTRL 2
93# define KG_ALT 3
94# define KG_ALTGR 1
95# define KG_SHIFTL 4
96# define KG_SHIFTR 5
97# define KG_CTRLL 6
98# define KG_CTRLR 7
99# define KG_CAPSSHIFT 8
100
101static void gpm_close __ARGS((void));
102static int gpm_open __ARGS((void));
103static int mch_gpm_process __ARGS((void));
104#endif
105
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000106#ifdef FEAT_SYSMOUSE
107# include <sys/consio.h>
108# include <sys/fbio.h>
109
110static int sysmouse_open __ARGS((void));
111static void sysmouse_close __ARGS((void));
112static RETSIGTYPE sig_sysmouse __ARGS(SIGPROTOARG);
113#endif
114
Bram Moolenaar071d4272004-06-13 20:20:40 +0000115/*
116 * end of autoconf section. To be extended...
117 */
118
119/* Are the following #ifdefs still required? And why? Is that for X11? */
120
121#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
122# ifdef SIGWINCH
123# undef SIGWINCH
124# endif
125# ifdef TIOCGWINSZ
126# undef TIOCGWINSZ
127# endif
128#endif
129
130#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
131# define SIGWINCH SIGWINDOW
132#endif
133
134#ifdef FEAT_X11
135# include <X11/Xlib.h>
136# include <X11/Xutil.h>
137# include <X11/Xatom.h>
138# ifdef FEAT_XCLIPBOARD
139# include <X11/Intrinsic.h>
140# include <X11/Shell.h>
141# include <X11/StringDefs.h>
142static Widget xterm_Shell = (Widget)0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +0100143static void clip_update __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000144static void xterm_update __ARGS((void));
145# endif
146
147# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
148Window x11_window = 0;
149# endif
150Display *x11_display = NULL;
151
152# ifdef FEAT_TITLE
153static int get_x11_windis __ARGS((void));
154static void set_x11_title __ARGS((char_u *));
155static void set_x11_icon __ARGS((char_u *));
156# endif
157#endif
158
159#ifdef FEAT_TITLE
160static int get_x11_title __ARGS((int));
161static int get_x11_icon __ARGS((int));
162
163static char_u *oldtitle = NULL;
164static int did_set_title = FALSE;
165static char_u *oldicon = NULL;
166static int did_set_icon = FALSE;
167#endif
168
169static void may_core_dump __ARGS((void));
170
Bram Moolenaar205b8862011-09-07 15:04:31 +0200171#ifdef HAVE_UNION_WAIT
172typedef union wait waitstatus;
173#else
174typedef int waitstatus;
175#endif
Bram Moolenaar9f118812011-09-08 23:24:14 +0200176static pid_t wait4pid __ARGS((pid_t, waitstatus *));
Bram Moolenaar205b8862011-09-07 15:04:31 +0200177
Bram Moolenaar071d4272004-06-13 20:20:40 +0000178static int WaitForChar __ARGS((long));
Bram Moolenaar4ffa0702013-12-11 17:12:37 +0100179#if defined(__BEOS__) || defined(VMS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000180int RealWaitForChar __ARGS((int, long, int *));
181#else
182static int RealWaitForChar __ARGS((int, long, int *));
183#endif
184
185#ifdef FEAT_XCLIPBOARD
186static int do_xterm_trace __ARGS((void));
Bram Moolenaarcf851ce2005-06-16 21:52:47 +0000187# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000188#endif
189
190static void handle_resize __ARGS((void));
191
192#if defined(SIGWINCH)
193static RETSIGTYPE sig_winch __ARGS(SIGPROTOARG);
194#endif
195#if defined(SIGINT)
196static RETSIGTYPE catch_sigint __ARGS(SIGPROTOARG);
197#endif
198#if defined(SIGPWR)
199static RETSIGTYPE catch_sigpwr __ARGS(SIGPROTOARG);
200#endif
201#if defined(SIGALRM) && defined(FEAT_X11) \
202 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
203# define SET_SIG_ALARM
204static RETSIGTYPE sig_alarm __ARGS(SIGPROTOARG);
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000205/* volatile because it is used in signal handler sig_alarm(). */
206static volatile int sig_alarm_called;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000207#endif
208static RETSIGTYPE deathtrap __ARGS(SIGPROTOARG);
209
Bram Moolenaardf177f62005-02-22 08:39:57 +0000210static void catch_int_signal __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000211static void set_signals __ARGS((void));
212static void catch_signals __ARGS((RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)()));
213#ifndef __EMX__
214static int have_wildcard __ARGS((int, char_u **));
215static int have_dollars __ARGS((int, char_u **));
216#endif
217
Bram Moolenaar071d4272004-06-13 20:20:40 +0000218#ifndef __EMX__
219static int save_patterns __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file));
220#endif
221
222#ifndef SIG_ERR
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000223# define SIG_ERR ((RETSIGTYPE (*)())-1)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000224#endif
225
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000226/* volatile because it is used in signal handler sig_winch(). */
227static volatile int do_resize = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228#ifndef __EMX__
229static char_u *extra_shell_arg = NULL;
230static int show_shell_mess = TRUE;
231#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000232/* volatile because it is used in signal handler deathtrap(). */
233static volatile int deadly_signal = 0; /* The signal we caught */
234/* volatile because it is used in signal handler deathtrap(). */
235static volatile int in_mch_delay = FALSE; /* sleeping in mch_delay() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236
237static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
238
239#ifdef USE_XSMP
240typedef struct
241{
242 SmcConn smcconn; /* The SM connection ID */
243 IceConn iceconn; /* The ICE connection ID */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200244 char *clientid; /* The client ID for the current smc session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000245 Bool save_yourself; /* If we're in the middle of a save_yourself */
246 Bool shutdown; /* If we're in shutdown mode */
247} xsmp_config_T;
248
249static xsmp_config_T xsmp;
250#endif
251
252#ifdef SYS_SIGLIST_DECLARED
253/*
254 * I have seen
255 * extern char *_sys_siglist[NSIG];
256 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
257 * that describe the signals. That is nearly what we want here. But
258 * autoconf does only check for sys_siglist (without the underscore), I
259 * do not want to change everything today.... jw.
260 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.in
261 */
262#endif
263
264static struct signalinfo
265{
266 int sig; /* Signal number, eg. SIGSEGV etc */
267 char *name; /* Signal name (not char_u!). */
268 char deadly; /* Catch as a deadly signal? */
269} signal_info[] =
270{
271#ifdef SIGHUP
272 {SIGHUP, "HUP", TRUE},
273#endif
274#ifdef SIGQUIT
275 {SIGQUIT, "QUIT", TRUE},
276#endif
277#ifdef SIGILL
278 {SIGILL, "ILL", TRUE},
279#endif
280#ifdef SIGTRAP
281 {SIGTRAP, "TRAP", TRUE},
282#endif
283#ifdef SIGABRT
284 {SIGABRT, "ABRT", TRUE},
285#endif
286#ifdef SIGEMT
287 {SIGEMT, "EMT", TRUE},
288#endif
289#ifdef SIGFPE
290 {SIGFPE, "FPE", TRUE},
291#endif
292#ifdef SIGBUS
293 {SIGBUS, "BUS", TRUE},
294#endif
Bram Moolenaar75676462013-01-30 14:55:42 +0100295#if defined(SIGSEGV) && !defined(FEAT_MZSCHEME)
296 /* MzScheme uses SEGV in its garbage collector */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000297 {SIGSEGV, "SEGV", TRUE},
298#endif
299#ifdef SIGSYS
300 {SIGSYS, "SYS", TRUE},
301#endif
302#ifdef SIGALRM
303 {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
304#endif
305#ifdef SIGTERM
306 {SIGTERM, "TERM", TRUE},
307#endif
Bram Moolenaarb292a2a2011-02-09 18:47:40 +0100308#if defined(SIGVTALRM) && !defined(FEAT_RUBY)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000309 {SIGVTALRM, "VTALRM", TRUE},
310#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000311#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
312 /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
313 * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000314 {SIGPROF, "PROF", TRUE},
315#endif
316#ifdef SIGXCPU
317 {SIGXCPU, "XCPU", TRUE},
318#endif
319#ifdef SIGXFSZ
320 {SIGXFSZ, "XFSZ", TRUE},
321#endif
322#ifdef SIGUSR1
323 {SIGUSR1, "USR1", TRUE},
324#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000325#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
326 /* Used for sysmouse handling */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000327 {SIGUSR2, "USR2", TRUE},
328#endif
329#ifdef SIGINT
330 {SIGINT, "INT", FALSE},
331#endif
332#ifdef SIGWINCH
333 {SIGWINCH, "WINCH", FALSE},
334#endif
335#ifdef SIGTSTP
336 {SIGTSTP, "TSTP", FALSE},
337#endif
338#ifdef SIGPIPE
339 {SIGPIPE, "PIPE", FALSE},
340#endif
341 {-1, "Unknown!", FALSE}
342};
343
Bram Moolenaar25724922009-07-14 15:38:41 +0000344 int
345mch_chdir(path)
346 char *path;
347{
348 if (p_verbose >= 5)
349 {
350 verbose_enter();
351 smsg((char_u *)"chdir(%s)", path);
352 verbose_leave();
353 }
354# ifdef VMS
355 return chdir(vms_fixfilename(path));
356# else
357 return chdir(path);
358# endif
359}
360
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000361/*
362 * Write s[len] to the screen.
363 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000364 void
365mch_write(s, len)
366 char_u *s;
367 int len;
368{
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +0000369 ignored = (int)write(1, (char *)s, len);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000370 if (p_wd) /* Unix is too fast, slow down a bit more */
371 RealWaitForChar(read_cmd_fd, p_wd, NULL);
372}
373
374/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000375 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376 * Get a characters from the keyboard.
377 * Return the number of characters that are available.
378 * If wtime == 0 do not wait for characters.
379 * If wtime == n wait a short time for characters.
380 * If wtime == -1 wait forever for characters.
381 */
382 int
383mch_inchar(buf, maxlen, wtime, tb_change_cnt)
384 char_u *buf;
385 int maxlen;
386 long wtime; /* don't use "time", MIPS cannot handle it */
387 int tb_change_cnt;
388{
389 int len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390
Bram Moolenaar93c88e02015-09-15 14:12:05 +0200391#ifdef MESSAGE_QUEUE
392 parse_queued_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200393#endif
394
Bram Moolenaar071d4272004-06-13 20:20:40 +0000395 /* Check if window changed size while we were busy, perhaps the ":set
396 * columns=99" command was used. */
397 while (do_resize)
398 handle_resize();
399
400 if (wtime >= 0)
401 {
402 while (WaitForChar(wtime) == 0) /* no character available */
403 {
404 if (!do_resize) /* return if not interrupted by resize */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000405 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406 handle_resize();
Bram Moolenaar93c88e02015-09-15 14:12:05 +0200407#ifdef MESSAGE_QUEUE
408 parse_queued_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200409#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410 }
411 }
412 else /* wtime == -1 */
413 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000414 /*
415 * If there is no character available within 'updatetime' seconds
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000416 * flush all the swap files to disk.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000417 * Also done when interrupted by SIGWINCH.
418 */
419 if (WaitForChar(p_ut) == 0)
420 {
421#ifdef FEAT_AUTOCMD
Bram Moolenaard35f9712005-12-18 22:02:33 +0000422 if (trigger_cursorhold() && maxlen >= 3
423 && !typebuf_changed(tb_change_cnt))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424 {
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000425 buf[0] = K_SPECIAL;
426 buf[1] = KS_EXTRA;
427 buf[2] = (int)KE_CURSORHOLD;
428 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000429 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000430#endif
Bram Moolenaard4098f52005-06-27 22:37:13 +0000431 before_blocking();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 }
433 }
434
435 for (;;) /* repeat until we got a character */
436 {
437 while (do_resize) /* window changed size */
438 handle_resize();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200439
Bram Moolenaar93c88e02015-09-15 14:12:05 +0200440#ifdef MESSAGE_QUEUE
441 parse_queued_messages();
Bram Moolenaar67c53842010-05-22 18:28:27 +0200442#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443 /*
Bram Moolenaar48bae372010-07-29 23:12:15 +0200444 * We want to be interrupted by the winch signal
445 * or by an event on the monitored file descriptors.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446 */
Bram Moolenaar67c53842010-05-22 18:28:27 +0200447 if (WaitForChar(-1L) == 0)
448 {
449 if (do_resize) /* interrupted by SIGWINCH signal */
450 handle_resize();
451 return 0;
452 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453
454 /* If input was put directly in typeahead buffer bail out here. */
455 if (typebuf_changed(tb_change_cnt))
456 return 0;
457
458 /*
459 * For some terminals we only get one character at a time.
460 * We want the get all available characters, so we could keep on
461 * trying until none is available
462 * For some other terminals this is quite slow, that's why we don't do
463 * it.
464 */
465 len = read_from_input_buf(buf, (long)maxlen);
466 if (len > 0)
467 {
468#ifdef OS2
469 int i;
470
471 for (i = 0; i < len; i++)
472 if (buf[i] == 0)
473 buf[i] = K_NUL;
474#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000475 return len;
476 }
477 }
478}
479
480 static void
481handle_resize()
482{
483 do_resize = FALSE;
484 shell_resized();
485}
486
487/*
488 * return non-zero if a character is available
489 */
490 int
491mch_char_avail()
492{
493 return WaitForChar(0L);
494}
495
496#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
497# ifdef HAVE_SYS_RESOURCE_H
Bram Moolenaar8f0b2d42009-05-16 14:41:10 +0000498# include <sys/resource.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000499# endif
500# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
501# include <sys/sysctl.h>
502# endif
503# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
504# include <sys/sysinfo.h>
505# endif
506
507/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000508 * Return total amount of memory available in Kbyte.
509 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511 long_u
512mch_total_mem(special)
Bram Moolenaar78a15312009-05-15 19:33:18 +0000513 int special UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000514{
515# ifdef __EMX__
Bram Moolenaar914572a2007-05-01 11:37:47 +0000516 return ulimit(3, 0L) >> 10; /* always 32MB? */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517# else
518 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000519 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000520
521# ifdef HAVE_SYSCTL
522 int mib[2], physmem;
523 size_t len;
524
525 /* BSD way of getting the amount of RAM available. */
526 mib[0] = CTL_HW;
527 mib[1] = HW_USERMEM;
528 len = sizeof(physmem);
529 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
530 mem = (long_u)physmem;
531# endif
532
533# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
534 if (mem == 0)
535 {
536 struct sysinfo sinfo;
537
538 /* Linux way of getting amount of RAM available */
539 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000540 {
541# ifdef HAVE_SYSINFO_MEM_UNIT
542 /* avoid overflow as much as possible */
543 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
544 {
545 sinfo.mem_unit = sinfo.mem_unit >> 1;
546 --shiftright;
547 }
548 mem = sinfo.totalram * sinfo.mem_unit;
549# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 mem = sinfo.totalram;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000551# endif
552 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000553 }
554# endif
555
556# ifdef HAVE_SYSCONF
557 if (mem == 0)
558 {
559 long pagesize, pagecount;
560
561 /* Solaris way of getting amount of RAM available */
562 pagesize = sysconf(_SC_PAGESIZE);
563 pagecount = sysconf(_SC_PHYS_PAGES);
564 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000565 {
566 /* avoid overflow as much as possible */
567 while (shiftright > 0 && (pagesize & 1) == 0)
568 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000569 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000570 --shiftright;
571 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000573 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574 }
575# endif
576
577 /* Return the minimum of the physical memory and the user limit, because
578 * using more than the user limit may cause Vim to be terminated. */
579# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
580 {
581 struct rlimit rlp;
582
583 if (getrlimit(RLIMIT_DATA, &rlp) == 0
584 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
585# ifdef RLIM_INFINITY
586 && rlp.rlim_cur != RLIM_INFINITY
587# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000588 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000589 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000590 {
591 mem = (long_u)rlp.rlim_cur;
592 shiftright = 10;
593 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 }
595# endif
596
597 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000598 return mem >> shiftright;
599 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000600# endif
601}
602#endif
603
604 void
605mch_delay(msec, ignoreinput)
606 long msec;
607 int ignoreinput;
608{
609 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000610#ifdef FEAT_MZSCHEME
611 long total = msec; /* remember original value */
612#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613
614 if (ignoreinput)
615 {
616 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000617 * here. But we don't want QUIT to kill us (CTRL-\ used in a
618 * shell may produce SIGQUIT). */
619 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620 old_tmode = curr_tmode;
621 if (curr_tmode == TMODE_RAW)
622 settmode(TMODE_SLEEP);
623
624 /*
625 * Everybody sleeps in a different way...
626 * Prefer nanosleep(), some versions of usleep() can only sleep up to
627 * one second.
628 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000629#ifdef FEAT_MZSCHEME
630 do
631 {
632 /* if total is large enough, wait by portions in p_mzq */
633 if (total > p_mzq)
634 msec = p_mzq;
635 else
636 msec = total;
637 total -= msec;
638#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000639#ifdef HAVE_NANOSLEEP
640 {
641 struct timespec ts;
642
643 ts.tv_sec = msec / 1000;
644 ts.tv_nsec = (msec % 1000) * 1000000;
645 (void)nanosleep(&ts, NULL);
646 }
647#else
648# ifdef HAVE_USLEEP
649 while (msec >= 1000)
650 {
651 usleep((unsigned int)(999 * 1000));
652 msec -= 999;
653 }
654 usleep((unsigned int)(msec * 1000));
655# else
656# ifndef HAVE_SELECT
657 poll(NULL, 0, (int)msec);
658# else
659# ifdef __EMX__
660 _sleep2(msec);
661# else
662 {
663 struct timeval tv;
664
665 tv.tv_sec = msec / 1000;
666 tv.tv_usec = (msec % 1000) * 1000;
667 /*
668 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
669 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
670 */
671 select(0, NULL, NULL, NULL, &tv);
672 }
673# endif /* __EMX__ */
674# endif /* HAVE_SELECT */
675# endif /* HAVE_NANOSLEEP */
676#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000677#ifdef FEAT_MZSCHEME
678 }
679 while (total > 0);
680#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000681
682 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000683 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000684 }
685 else
686 WaitForChar(msec);
687}
688
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000689#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000690 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
691# define HAVE_CHECK_STACK_GROWTH
692/*
693 * Support for checking for an almost-out-of-stack-space situation.
694 */
695
696/*
697 * Return a pointer to an item on the stack. Used to find out if the stack
698 * grows up or down.
699 */
700static void check_stack_growth __ARGS((char *p));
701static int stack_grows_downwards;
702
703/*
704 * Find out if the stack grows upwards or downwards.
705 * "p" points to a variable on the stack of the caller.
706 */
707 static void
708check_stack_growth(p)
709 char *p;
710{
711 int i;
712
713 stack_grows_downwards = (p > (char *)&i);
714}
715#endif
716
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000717#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718static char *stack_limit = NULL;
719
720#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
721# include <pthread.h>
722# include <pthread_np.h>
723#endif
724
725/*
726 * Find out until how var the stack can grow without getting into trouble.
727 * Called when starting up and when switching to the signal stack in
728 * deathtrap().
729 */
730 static void
731get_stack_limit()
732{
733 struct rlimit rlp;
734 int i;
735 long lim;
736
737 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
738 * limit doesn't fit in a long (rlim_cur might be "long long"). */
739 if (getrlimit(RLIMIT_STACK, &rlp) == 0
740 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
741# ifdef RLIM_INFINITY
742 && rlp.rlim_cur != RLIM_INFINITY
743# endif
744 )
745 {
746 lim = (long)rlp.rlim_cur;
747#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
748 {
749 pthread_attr_t attr;
750 size_t size;
751
752 /* On FreeBSD the initial thread always has a fixed stack size, no
753 * matter what the limits are set to. Normally it's 1 Mbyte. */
754 pthread_attr_init(&attr);
755 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
756 {
757 pthread_attr_getstacksize(&attr, &size);
758 if (lim > (long)size)
759 lim = (long)size;
760 }
761 pthread_attr_destroy(&attr);
762 }
763#endif
764 if (stack_grows_downwards)
765 {
766 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
767 if (stack_limit >= (char *)&i)
768 /* overflow, set to 1/16 of current stack position */
769 stack_limit = (char *)((long)&i / 16L);
770 }
771 else
772 {
773 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
774 if (stack_limit <= (char *)&i)
775 stack_limit = NULL; /* overflow */
776 }
777 }
778}
779
780/*
781 * Return FAIL when running out of stack space.
782 * "p" must point to any variable local to the caller that's on the stack.
783 */
784 int
785mch_stackcheck(p)
786 char *p;
787{
788 if (stack_limit != NULL)
789 {
790 if (stack_grows_downwards)
791 {
792 if (p < stack_limit)
793 return FAIL;
794 }
795 else if (p > stack_limit)
796 return FAIL;
797 }
798 return OK;
799}
800#endif
801
802#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
803/*
804 * Support for using the signal stack.
805 * This helps when we run out of stack space, which causes a SIGSEGV. The
806 * signal handler then must run on another stack, since the normal stack is
807 * completely full.
808 */
809
Bram Moolenaar39766a72013-11-03 00:41:00 +0100810#if defined(HAVE_AVAILABILITYMACROS_H)
Bram Moolenaar4cc95d12013-11-02 21:49:32 +0100811# include <AvailabilityMacros.h>
812#endif
813
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814#ifndef SIGSTKSZ
815# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
816#endif
817
818# ifdef HAVE_SIGALTSTACK
819static stack_t sigstk; /* for sigaltstack() */
820# else
821static struct sigstack sigstk; /* for sigstack() */
822# endif
823
824static void init_signal_stack __ARGS((void));
825static char *signal_stack;
826
827 static void
828init_signal_stack()
829{
830 if (signal_stack != NULL)
831 {
832# ifdef HAVE_SIGALTSTACK
Bram Moolenaar1a3d0862007-08-30 09:47:38 +0000833# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
834 || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
836 * "struct sigaltstack" needs to be declared. */
837 extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
838# endif
839
840# ifdef HAVE_SS_BASE
841 sigstk.ss_base = signal_stack;
842# else
843 sigstk.ss_sp = signal_stack;
844# endif
845 sigstk.ss_size = SIGSTKSZ;
846 sigstk.ss_flags = 0;
847 (void)sigaltstack(&sigstk, NULL);
848# else
849 sigstk.ss_sp = signal_stack;
850 if (stack_grows_downwards)
851 sigstk.ss_sp += SIGSTKSZ - 1;
852 sigstk.ss_onstack = 0;
853 (void)sigstack(&sigstk, NULL);
854# endif
855 }
856}
857#endif
858
859/*
Bram Moolenaar76243bd2009-03-02 01:47:02 +0000860 * We need correct prototypes for a signal function, otherwise mean compilers
Bram Moolenaar071d4272004-06-13 20:20:40 +0000861 * will barf when the second argument to signal() is ``wrong''.
862 * Let me try it with a few tricky defines from my own osdef.h (jw).
863 */
864#if defined(SIGWINCH)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 static RETSIGTYPE
866sig_winch SIGDEFARG(sigarg)
867{
868 /* this is not required on all systems, but it doesn't hurt anybody */
869 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
870 do_resize = TRUE;
871 SIGRETURN;
872}
873#endif
874
875#if defined(SIGINT)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 static RETSIGTYPE
877catch_sigint SIGDEFARG(sigarg)
878{
879 /* this is not required on all systems, but it doesn't hurt anybody */
880 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
881 got_int = TRUE;
882 SIGRETURN;
883}
884#endif
885
886#if defined(SIGPWR)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 static RETSIGTYPE
888catch_sigpwr SIGDEFARG(sigarg)
889{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000890 /* this is not required on all systems, but it doesn't hurt anybody */
891 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000892 /*
893 * I'm not sure we get the SIGPWR signal when the system is really going
894 * down or when the batteries are almost empty. Just preserve the swap
895 * files and don't exit, that can't do any harm.
896 */
897 ml_sync_all(FALSE, FALSE);
898 SIGRETURN;
899}
900#endif
901
902#ifdef SET_SIG_ALARM
903/*
904 * signal function for alarm().
905 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000906 static RETSIGTYPE
907sig_alarm SIGDEFARG(sigarg)
908{
909 /* doesn't do anything, just to break a system call */
910 sig_alarm_called = TRUE;
911 SIGRETURN;
912}
913#endif
914
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000915#if (defined(HAVE_SETJMP_H) \
916 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
917 || defined(FEAT_LIBCALL))) \
918 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000919/*
920 * A simplistic version of setjmp() that only allows one level of using.
921 * Don't call twice before calling mch_endjmp()!.
922 * Usage:
923 * mch_startjmp();
924 * if (SETJMP(lc_jump_env) != 0)
925 * {
926 * mch_didjmp();
927 * EMSG("crash!");
928 * }
929 * else
930 * {
931 * do_the_work;
932 * mch_endjmp();
933 * }
934 * Note: Can't move SETJMP() here, because a function calling setjmp() must
935 * not return before the saved environment is used.
936 * Returns OK for normal return, FAIL when the protected code caused a
937 * problem and LONGJMP() was used.
938 */
939 void
940mch_startjmp()
941{
942#ifdef SIGHASARG
943 lc_signal = 0;
944#endif
945 lc_active = TRUE;
946}
947
948 void
949mch_endjmp()
950{
951 lc_active = FALSE;
952}
953
954 void
955mch_didjmp()
956{
957# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
958 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
959 * otherwise catching the signal only works once. */
960 init_signal_stack();
961# endif
962}
963#endif
964
965/*
966 * This function handles deadly signals.
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200967 * It tries to preserve any swap files and exit properly.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000968 * (partly from Elvis).
Bram Moolenaarbec9c202013-09-05 21:41:39 +0200969 * NOTE: Avoid unsafe functions, such as allocating memory, they can result in
970 * a deadlock.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971 */
972 static RETSIGTYPE
973deathtrap SIGDEFARG(sigarg)
974{
975 static int entered = 0; /* count the number of times we got here.
976 Note: when memory has been corrupted
977 this may get an arbitrary value! */
978#ifdef SIGHASARG
979 int i;
980#endif
981
982#if defined(HAVE_SETJMP_H)
983 /*
984 * Catch a crash in protected code.
985 * Restores the environment saved in lc_jump_env, which looks like
986 * SETJMP() returns 1.
987 */
988 if (lc_active)
989 {
990# if defined(SIGHASARG)
991 lc_signal = sigarg;
992# endif
993 lc_active = FALSE; /* don't jump again */
994 LONGJMP(lc_jump_env, 1);
995 /* NOTREACHED */
996 }
997#endif
998
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000999#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +00001000# ifdef SIGQUIT
1001 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
1002 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
1003 * pressing CTRL-\, but we don't want Vim to exit then. */
1004 if (in_mch_delay && sigarg == SIGQUIT)
1005 SIGRETURN;
1006# endif
1007
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001008 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
1009 * here. This avoids that a non-reentrant function is interrupted, e.g.,
1010 * free(). Calling free() again may then cause a crash. */
1011 if (entered == 0
1012 && (0
1013# ifdef SIGHUP
1014 || sigarg == SIGHUP
1015# endif
1016# ifdef SIGQUIT
1017 || sigarg == SIGQUIT
1018# endif
1019# ifdef SIGTERM
1020 || sigarg == SIGTERM
1021# endif
1022# ifdef SIGPWR
1023 || sigarg == SIGPWR
1024# endif
1025# ifdef SIGUSR1
1026 || sigarg == SIGUSR1
1027# endif
1028# ifdef SIGUSR2
1029 || sigarg == SIGUSR2
1030# endif
1031 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001032 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001033 SIGRETURN;
1034#endif
1035
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036 /* Remember how often we have been called. */
1037 ++entered;
1038
1039#ifdef FEAT_EVAL
1040 /* Set the v:dying variable. */
1041 set_vim_var_nr(VV_DYING, (long)entered);
1042#endif
1043
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001044#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045 /* Since we are now using the signal stack, need to reset the stack
1046 * limit. Otherwise using a regexp will fail. */
1047 get_stack_limit();
1048#endif
1049
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +00001050#if 0
1051 /* This is for opening gdb the moment Vim crashes.
1052 * You need to manually adjust the file name and Vim executable name.
1053 * Suggested by SungHyun Nam. */
1054 {
1055# define VI_GDB_FILE "/tmp/vimgdb"
1056# define VIM_NAME "/usr/bin/vim"
1057 FILE *fp = fopen(VI_GDB_FILE, "w");
1058 if (fp)
1059 {
1060 fprintf(fp,
1061 "file %s\n"
1062 "attach %d\n"
1063 "set height 1000\n"
1064 "bt full\n"
1065 , VIM_NAME, getpid());
1066 fclose(fp);
1067 system("xterm -e gdb -x "VI_GDB_FILE);
1068 unlink(VI_GDB_FILE);
1069 }
1070 }
1071#endif
1072
Bram Moolenaar071d4272004-06-13 20:20:40 +00001073#ifdef SIGHASARG
1074 /* try to find the name of this signal */
1075 for (i = 0; signal_info[i].sig != -1; i++)
1076 if (sigarg == signal_info[i].sig)
1077 break;
1078 deadly_signal = sigarg;
1079#endif
1080
1081 full_screen = FALSE; /* don't write message to the GUI, it might be
1082 * part of the problem... */
1083 /*
1084 * If something goes wrong after entering here, we may get here again.
1085 * When this happens, give a message and try to exit nicely (resetting the
1086 * terminal mode, etc.)
1087 * When this happens twice, just exit, don't even try to give a message,
1088 * stack may be corrupt or something weird.
1089 * When this still happens again (or memory was corrupted in such a way
1090 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1091 */
1092 if (entered >= 3)
1093 {
1094 reset_signals(); /* don't catch any signals anymore */
1095 may_core_dump();
1096 if (entered >= 4)
1097 _exit(8);
1098 exit(7);
1099 }
1100 if (entered == 2)
1101 {
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001102 /* No translation, it may call malloc(). */
1103 OUT_STR("Vim: Double signal, exiting\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104 out_flush();
1105 getout(1);
1106 }
1107
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001108 /* No translation, it may call malloc(). */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001109#ifdef SIGHASARG
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001110 sprintf((char *)IObuff, "Vim: Caught deadly signal %s\n",
Bram Moolenaar071d4272004-06-13 20:20:40 +00001111 signal_info[i].name);
1112#else
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001113 sprintf((char *)IObuff, "Vim: Caught deadly signal\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001114#endif
Bram Moolenaarbec9c202013-09-05 21:41:39 +02001115
1116 /* Preserve files and exit. This sets the really_exiting flag to prevent
1117 * calling free(). */
1118 preserve_exit();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001119
Bram Moolenaar009b2592004-10-24 19:18:58 +00001120#ifdef NBDEBUG
1121 reset_signals();
1122 may_core_dump();
1123 abort();
1124#endif
1125
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126 SIGRETURN;
1127}
1128
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001129#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001130/*
1131 * On Solaris with multi-threading, suspending might not work immediately.
1132 * Catch the SIGCONT signal, which will be used as an indication whether the
1133 * suspending has been done or not.
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001134 *
1135 * On Linux, signal is not always handled immediately either.
1136 * See https://bugs.launchpad.net/bugs/291373
1137 *
Bram Moolenaarb292a2a2011-02-09 18:47:40 +01001138 * volatile because it is used in signal handler sigcont_handler().
Bram Moolenaar071d4272004-06-13 20:20:40 +00001139 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001140static volatile int sigcont_received;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001141static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1142
1143/*
1144 * signal handler for SIGCONT
1145 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001146 static RETSIGTYPE
1147sigcont_handler SIGDEFARG(sigarg)
1148{
1149 sigcont_received = TRUE;
1150 SIGRETURN;
1151}
1152#endif
1153
Bram Moolenaar62b42182010-09-21 22:09:37 +02001154# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1155static void loose_clipboard __ARGS((void));
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001156# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001157static void save_clipboard __ARGS((void));
1158static void restore_clipboard __ARGS((void));
1159
1160static void *clip_star_save = NULL;
1161static void *clip_plus_save = NULL;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001162# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001163
1164/*
1165 * Called when Vim is going to sleep or execute a shell command.
1166 * We can't respond to requests for the X selections. Lose them, otherwise
1167 * other applications will hang. But first copy the text to cut buffer 0.
1168 */
1169 static void
1170loose_clipboard()
1171{
1172 if (clip_star.owned || clip_plus.owned)
1173 {
1174 x11_export_final_selection();
1175 if (clip_star.owned)
1176 clip_lose_selection(&clip_star);
1177 if (clip_plus.owned)
1178 clip_lose_selection(&clip_plus);
1179 if (x11_display != NULL)
1180 XFlush(x11_display);
1181 }
1182}
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001183
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001184# ifdef USE_SYSTEM
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01001185/*
1186 * Save clipboard text to restore later.
1187 */
1188 static void
1189save_clipboard()
1190{
1191 if (clip_star.owned)
1192 clip_star_save = get_register('*', TRUE);
1193 if (clip_plus.owned)
1194 clip_plus_save = get_register('+', TRUE);
1195}
1196
1197/*
1198 * Restore clipboard text if no one own the X selection.
1199 */
1200 static void
1201restore_clipboard()
1202{
1203 if (clip_star_save != NULL)
1204 {
1205 if (!clip_gen_owner_exists(&clip_star))
1206 put_register('*', clip_star_save);
1207 else
1208 free_register(clip_star_save);
1209 clip_star_save = NULL;
1210 }
1211 if (clip_plus_save != NULL)
1212 {
1213 if (!clip_gen_owner_exists(&clip_plus))
1214 put_register('+', clip_plus_save);
1215 else
1216 free_register(clip_plus_save);
1217 clip_plus_save = NULL;
1218 }
1219}
Bram Moolenaar090cfc12013-03-19 12:35:42 +01001220# endif
Bram Moolenaar62b42182010-09-21 22:09:37 +02001221#endif
1222
Bram Moolenaar071d4272004-06-13 20:20:40 +00001223/*
1224 * If the machine has job control, use it to suspend the program,
1225 * otherwise fake it by starting a new shell.
1226 */
1227 void
1228mch_suspend()
1229{
1230 /* BeOS does have SIGTSTP, but it doesn't work. */
1231#if defined(SIGTSTP) && !defined(__BEOS__)
1232 out_flush(); /* needed to make cursor visible on some systems */
1233 settmode(TMODE_COOK);
1234 out_flush(); /* needed to disable mouse on some systems */
1235
1236# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar62b42182010-09-21 22:09:37 +02001237 loose_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001238# endif
1239
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001240# if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001241 sigcont_received = FALSE;
1242# endif
1243 kill(0, SIGTSTP); /* send ourselves a STOP signal */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001244# if defined(_REENTRANT) && defined(SIGCONT)
1245 /*
1246 * Wait for the SIGCONT signal to be handled. It generally happens
1247 * immediately, but somehow not all the time. Do not call pause()
1248 * because there would be race condition which would hang Vim if
1249 * signal happened in between the test of sigcont_received and the
1250 * call to pause(). If signal is not yet received, call sleep(0)
1251 * to just yield CPU. Signal should then be received. If somehow
1252 * it's still not received, sleep 1, 2, 3 ms. Don't bother waiting
1253 * further if signal is not received after 1+2+3+4 ms (not expected
1254 * to happen).
1255 */
1256 {
Bram Moolenaar262735e2009-07-14 10:20:22 +00001257 long wait_time;
1258 for (wait_time = 0; !sigcont_received && wait_time <= 3L; wait_time++)
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001259 /* Loop is not entered most of the time */
Bram Moolenaar262735e2009-07-14 10:20:22 +00001260 mch_delay(wait_time, FALSE);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001261 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001262# endif
1263
1264# ifdef FEAT_TITLE
1265 /*
1266 * Set oldtitle to NULL, so the current title is obtained again.
1267 */
1268 vim_free(oldtitle);
1269 oldtitle = NULL;
1270# endif
1271 settmode(TMODE_RAW);
1272 need_check_timestamps = TRUE;
1273 did_check_timestamps = FALSE;
1274#else
1275 suspend_shell();
1276#endif
1277}
1278
1279 void
1280mch_init()
1281{
1282 Columns = 80;
1283 Rows = 24;
1284
1285 out_flush();
1286 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001287
Bram Moolenaar56718732006-03-15 22:53:57 +00001288#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001289 mac_conv_init();
1290#endif
Bram Moolenaar693e40c2013-02-26 14:56:42 +01001291#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
1292 win_clip_init();
1293#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001294}
1295
1296 static void
1297set_signals()
1298{
1299#if defined(SIGWINCH)
1300 /*
1301 * WINDOW CHANGE signal is handled with sig_winch().
1302 */
1303 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1304#endif
1305
1306 /*
1307 * We want the STOP signal to work, to make mch_suspend() work.
1308 * For "rvim" the STOP signal is ignored.
1309 */
1310#ifdef SIGTSTP
1311 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1312#endif
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001313#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001314 signal(SIGCONT, sigcont_handler);
1315#endif
1316
1317 /*
1318 * We want to ignore breaking of PIPEs.
1319 */
1320#ifdef SIGPIPE
1321 signal(SIGPIPE, SIG_IGN);
1322#endif
1323
Bram Moolenaar071d4272004-06-13 20:20:40 +00001324#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001325 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001326#endif
1327
1328 /*
1329 * Ignore alarm signals (Perl's alarm() generates it).
1330 */
1331#ifdef SIGALRM
1332 signal(SIGALRM, SIG_IGN);
1333#endif
1334
1335 /*
1336 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1337 * work will be lost.
1338 */
1339#ifdef SIGPWR
1340 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1341#endif
1342
1343 /*
1344 * Arrange for other signals to gracefully shutdown Vim.
1345 */
1346 catch_signals(deathtrap, SIG_ERR);
1347
1348#if defined(FEAT_GUI) && defined(SIGHUP)
1349 /*
1350 * When the GUI is running, ignore the hangup signal.
1351 */
1352 if (gui.in_use)
1353 signal(SIGHUP, SIG_IGN);
1354#endif
1355}
1356
Bram Moolenaardf177f62005-02-22 08:39:57 +00001357#if defined(SIGINT) || defined(PROTO)
1358/*
1359 * Catch CTRL-C (only works while in Cooked mode).
1360 */
1361 static void
1362catch_int_signal()
1363{
1364 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1365}
1366#endif
1367
Bram Moolenaar071d4272004-06-13 20:20:40 +00001368 void
1369reset_signals()
1370{
1371 catch_signals(SIG_DFL, SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00001372#if defined(_REENTRANT) && defined(SIGCONT)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001373 /* SIGCONT isn't in the list, because its default action is ignore */
1374 signal(SIGCONT, SIG_DFL);
1375#endif
1376}
1377
1378 static void
1379catch_signals(func_deadly, func_other)
1380 RETSIGTYPE (*func_deadly)();
1381 RETSIGTYPE (*func_other)();
1382{
1383 int i;
1384
1385 for (i = 0; signal_info[i].sig != -1; i++)
1386 if (signal_info[i].deadly)
1387 {
1388#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1389 struct sigaction sa;
1390
1391 /* Setup to use the alternate stack for the signal function. */
1392 sa.sa_handler = func_deadly;
1393 sigemptyset(&sa.sa_mask);
1394# if defined(__linux__) && defined(_REENTRANT)
1395 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1396 * thread handling in combination with using the alternate stack:
1397 * pthread library functions try to use the stack pointer to
1398 * identify the current thread, causing a SEGV signal, which
1399 * recursively calls deathtrap() and hangs. */
1400 sa.sa_flags = 0;
1401# else
1402 sa.sa_flags = SA_ONSTACK;
1403# endif
1404 sigaction(signal_info[i].sig, &sa, NULL);
1405#else
1406# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1407 struct sigvec sv;
1408
1409 /* Setup to use the alternate stack for the signal function. */
1410 sv.sv_handler = func_deadly;
1411 sv.sv_mask = 0;
1412 sv.sv_flags = SV_ONSTACK;
1413 sigvec(signal_info[i].sig, &sv, NULL);
1414# else
1415 signal(signal_info[i].sig, func_deadly);
1416# endif
1417#endif
1418 }
1419 else if (func_other != SIG_ERR)
1420 signal(signal_info[i].sig, func_other);
1421}
1422
1423/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001424 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001425 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1426 * return TRUE
1427 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1428 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
Bram Moolenaar67c53842010-05-22 18:28:27 +02001429 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001430 * Returns TRUE when Vim should exit.
1431 */
1432 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001433vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001434 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001435{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001436 static int got_signal = 0;
1437 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001438
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001439 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001440 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001441 case SIGNAL_BLOCK: blocked = TRUE;
1442 break;
1443
1444 case SIGNAL_UNBLOCK: blocked = FALSE;
1445 if (got_signal != 0)
1446 {
1447 kill(getpid(), got_signal);
1448 got_signal = 0;
1449 }
1450 break;
1451
1452 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001453 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001454 got_signal = sig;
1455#ifdef SIGPWR
1456 if (sig != SIGPWR)
1457#endif
1458 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001459 break;
1460 }
1461 return FALSE;
1462}
1463
1464/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001465 * Check_win checks whether we have an interactive stdout.
1466 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001467 int
1468mch_check_win(argc, argv)
Bram Moolenaar78a15312009-05-15 19:33:18 +00001469 int argc UNUSED;
1470 char **argv UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001471{
1472#ifdef OS2
1473 /*
1474 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1475 * name, mostly it's just "vim" and found in the path, which is unusable.
1476 */
1477 if (mch_isFullName(argv[0]))
1478 exe_name = vim_strsave((char_u *)argv[0]);
1479#endif
1480 if (isatty(1))
1481 return OK;
1482 return FAIL;
1483}
1484
1485/*
1486 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1487 */
1488 int
1489mch_input_isatty()
1490{
1491 if (isatty(read_cmd_fd))
1492 return TRUE;
1493 return FALSE;
1494}
1495
1496#ifdef FEAT_X11
1497
1498# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1499 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1500
1501static void xopen_message __ARGS((struct timeval *tvp));
1502
1503/*
1504 * Give a message about the elapsed time for opening the X window.
1505 */
1506 static void
1507xopen_message(tvp)
1508 struct timeval *tvp; /* must contain start time */
1509{
1510 struct timeval end_tv;
1511
1512 /* Compute elapsed time. */
1513 gettimeofday(&end_tv, NULL);
1514 smsg((char_u *)_("Opening the X display took %ld msec"),
1515 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001516 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001517}
1518# endif
1519#endif
1520
1521#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1522/*
1523 * A few functions shared by X11 title and clipboard code.
1524 */
1525static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1526static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1527static int x_connect_to_server __ARGS((void));
1528static int test_x11_window __ARGS((Display *dpy));
1529
1530static int got_x_error = FALSE;
1531
1532/*
1533 * X Error handler, otherwise X just exits! (very rude) -- webb
1534 */
1535 static int
1536x_error_handler(dpy, error_event)
1537 Display *dpy;
1538 XErrorEvent *error_event;
1539{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001540 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001541 STRCAT(IObuff, _("\nVim: Got X error\n"));
1542
1543 /* We cannot print a message and continue, because no X calls are allowed
1544 * here (causes my system to hang). Silently continuing might be an
1545 * alternative... */
1546 preserve_exit(); /* preserve files and exit */
1547
1548 return 0; /* NOTREACHED */
1549}
1550
1551/*
1552 * Another X Error handler, just used to check for errors.
1553 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001554 static int
1555x_error_check(dpy, error_event)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001556 Display *dpy UNUSED;
1557 XErrorEvent *error_event UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001558{
1559 got_x_error = TRUE;
1560 return 0;
1561}
1562
1563#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1564# if defined(HAVE_SETJMP_H)
1565/*
1566 * An X IO Error handler, used to catch error while opening the display.
1567 */
1568static int x_IOerror_check __ARGS((Display *dpy));
1569
Bram Moolenaar071d4272004-06-13 20:20:40 +00001570 static int
1571x_IOerror_check(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001572 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001573{
1574 /* This function should not return, it causes exit(). Longjump instead. */
1575 LONGJMP(lc_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001576# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001577 return 0; /* avoid the compiler complains about missing return value */
1578# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001579}
1580# endif
1581
1582/*
1583 * An X IO Error handler, used to catch terminal errors.
1584 */
1585static int x_IOerror_handler __ARGS((Display *dpy));
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001586static void may_restore_clipboard __ARGS((void));
1587static int xterm_dpy_was_reset = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001588
Bram Moolenaar071d4272004-06-13 20:20:40 +00001589 static int
1590x_IOerror_handler(dpy)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00001591 Display *dpy UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001592{
1593 xterm_dpy = NULL;
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001594 xterm_dpy_was_reset = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001595 x11_window = 0;
1596 x11_display = NULL;
1597 xterm_Shell = (Widget)0;
1598
1599 /* This function should not return, it causes exit(). Longjump instead. */
1600 LONGJMP(x_jump_env, 1);
Bram Moolenaarfe17e762013-06-29 14:17:02 +02001601# if defined(VMS) || defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaarb4990bf2010-02-11 18:19:38 +01001602 return 0; /* avoid the compiler complains about missing return value */
1603# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001604}
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001605
1606/*
1607 * If the X11 connection was lost try to restore it.
1608 * Helps when the X11 server was stopped and restarted while Vim was inactive
Bram Moolenaarcaad4f02014-12-17 14:36:14 +01001609 * (e.g. through tmux).
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001610 */
1611 static void
1612may_restore_clipboard()
1613{
1614 if (xterm_dpy_was_reset)
1615 {
1616 xterm_dpy_was_reset = FALSE;
Bram Moolenaar527a6782014-12-17 17:59:31 +01001617
1618# ifndef LESSTIF_VERSION
1619 /* This has been reported to avoid Vim getting stuck. */
1620 if (app_context != (XtAppContext)NULL)
1621 {
1622 XtDestroyApplicationContext(app_context);
1623 app_context = (XtAppContext)NULL;
1624 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
1625 }
1626# endif
1627
Bram Moolenaarb1e26502014-11-19 18:48:46 +01001628 setup_term_clip();
1629 get_x11_title(FALSE);
1630 }
1631}
Bram Moolenaar071d4272004-06-13 20:20:40 +00001632#endif
1633
1634/*
1635 * Return TRUE when connection to the X server is desired.
1636 */
1637 static int
1638x_connect_to_server()
1639{
Bram Moolenaar071d4272004-06-13 20:20:40 +00001640#if defined(FEAT_CLIENTSERVER)
1641 if (x_force_connect)
1642 return TRUE;
1643#endif
1644 if (x_no_connect)
1645 return FALSE;
1646
1647 /* Check for a match with "exclude:" from 'clipboard'. */
1648 if (clip_exclude_prog != NULL)
1649 {
Bram Moolenaardffa5b82014-11-19 16:38:07 +01001650 if (vim_regexec_prog(&clip_exclude_prog, FALSE, T_NAME, (colnr_T)0))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001651 return FALSE;
1652 }
1653 return TRUE;
1654}
1655
1656/*
1657 * Test if "dpy" and x11_window are valid by getting the window title.
1658 * I don't actually want it yet, so there may be a simpler call to use, but
1659 * this will cause the error handler x_error_check() to be called if anything
1660 * is wrong, such as the window pointer being invalid (as can happen when the
1661 * user changes his DISPLAY, but not his WINDOWID) -- webb
1662 */
1663 static int
1664test_x11_window(dpy)
1665 Display *dpy;
1666{
1667 int (*old_handler)();
1668 XTextProperty text_prop;
1669
1670 old_handler = XSetErrorHandler(x_error_check);
1671 got_x_error = FALSE;
1672 if (XGetWMName(dpy, x11_window, &text_prop))
1673 XFree((void *)text_prop.value);
1674 XSync(dpy, False);
1675 (void)XSetErrorHandler(old_handler);
1676
1677 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001678 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001679
1680 return (got_x_error ? FAIL : OK);
1681}
1682#endif
1683
1684#ifdef FEAT_TITLE
1685
1686#ifdef FEAT_X11
1687
1688static int get_x11_thing __ARGS((int get_title, int test_only));
1689
1690/*
1691 * try to get x11 window and display
1692 *
1693 * return FAIL for failure, OK otherwise
1694 */
1695 static int
1696get_x11_windis()
1697{
1698 char *winid;
1699 static int result = -1;
1700#define XD_NONE 0 /* x11_display not set here */
1701#define XD_HERE 1 /* x11_display opened here */
1702#define XD_GUI 2 /* x11_display used from gui.dpy */
1703#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1704 static int x11_display_from = XD_NONE;
1705 static int did_set_error_handler = FALSE;
1706
1707 if (!did_set_error_handler)
1708 {
1709 /* X just exits if it finds an error otherwise! */
1710 (void)XSetErrorHandler(x_error_handler);
1711 did_set_error_handler = TRUE;
1712 }
1713
Bram Moolenaar9372a112005-12-06 19:59:18 +00001714#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001715 if (gui.in_use)
1716 {
1717 /*
1718 * If the X11 display was opened here before, for the window where Vim
1719 * was started, close that one now to avoid a memory leak.
1720 */
1721 if (x11_display_from == XD_HERE && x11_display != NULL)
1722 {
1723 XCloseDisplay(x11_display);
1724 x11_display_from = XD_NONE;
1725 }
1726 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1727 {
1728 x11_display_from = XD_GUI;
1729 return OK;
1730 }
1731 x11_display = NULL;
1732 return FAIL;
1733 }
1734 else if (x11_display_from == XD_GUI)
1735 {
1736 /* GUI must have stopped somehow, clear x11_display */
1737 x11_window = 0;
1738 x11_display = NULL;
1739 x11_display_from = XD_NONE;
1740 }
1741#endif
1742
1743 /* When started with the "-X" argument, don't try connecting. */
1744 if (!x_connect_to_server())
1745 return FAIL;
1746
1747 /*
1748 * If WINDOWID not set, should try another method to find out
1749 * what the current window number is. The only code I know for
1750 * this is very complicated.
1751 * We assume that zero is invalid for WINDOWID.
1752 */
1753 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1754 x11_window = (Window)atol(winid);
1755
1756#ifdef FEAT_XCLIPBOARD
1757 if (xterm_dpy != NULL && x11_window != 0)
1758 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001759 /* We may have checked it already, but Gnome terminal can move us to
1760 * another window, so we need to check every time. */
1761 if (x11_display_from != XD_XTERM)
1762 {
1763 /*
1764 * If the X11 display was opened here before, for the window where
1765 * Vim was started, close that one now to avoid a memory leak.
1766 */
1767 if (x11_display_from == XD_HERE && x11_display != NULL)
1768 XCloseDisplay(x11_display);
1769 x11_display = xterm_dpy;
1770 x11_display_from = XD_XTERM;
1771 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001772 if (test_x11_window(x11_display) == FAIL)
1773 {
1774 /* probably bad $WINDOWID */
1775 x11_window = 0;
1776 x11_display = NULL;
1777 x11_display_from = XD_NONE;
1778 return FAIL;
1779 }
1780 return OK;
1781 }
1782#endif
1783
1784 if (x11_window == 0 || x11_display == NULL)
1785 result = -1;
1786
1787 if (result != -1) /* Have already been here and set this */
1788 return result; /* Don't do all these X calls again */
1789
1790 if (x11_window != 0 && x11_display == NULL)
1791 {
1792#ifdef SET_SIG_ALARM
1793 RETSIGTYPE (*sig_save)();
1794#endif
1795#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1796 struct timeval start_tv;
1797
1798 if (p_verbose > 0)
1799 gettimeofday(&start_tv, NULL);
1800#endif
1801
1802#ifdef SET_SIG_ALARM
1803 /*
1804 * Opening the Display may hang if the DISPLAY setting is wrong, or
1805 * the network connection is bad. Set an alarm timer to get out.
1806 */
1807 sig_alarm_called = FALSE;
1808 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1809 (RETSIGTYPE (*)())sig_alarm);
1810 alarm(2);
1811#endif
1812 x11_display = XOpenDisplay(NULL);
1813
1814#ifdef SET_SIG_ALARM
1815 alarm(0);
1816 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1817 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001818 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001819#endif
1820 if (x11_display != NULL)
1821 {
1822# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1823 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001824 {
1825 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001826 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001827 verbose_leave();
1828 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829# endif
1830 if (test_x11_window(x11_display) == FAIL)
1831 {
1832 /* Maybe window id is bad */
1833 x11_window = 0;
1834 XCloseDisplay(x11_display);
1835 x11_display = NULL;
1836 }
1837 else
1838 x11_display_from = XD_HERE;
1839 }
1840 }
1841 if (x11_window == 0 || x11_display == NULL)
1842 return (result = FAIL);
Bram Moolenaar727c8762010-10-20 19:17:48 +02001843
1844# ifdef FEAT_EVAL
1845 set_vim_var_nr(VV_WINDOWID, (long)x11_window);
1846# endif
1847
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848 return (result = OK);
1849}
1850
1851/*
1852 * Determine original x11 Window Title
1853 */
1854 static int
1855get_x11_title(test_only)
1856 int test_only;
1857{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001858 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001859}
1860
1861/*
1862 * Determine original x11 Window icon
1863 */
1864 static int
1865get_x11_icon(test_only)
1866 int test_only;
1867{
1868 int retval = FALSE;
1869
1870 retval = get_x11_thing(FALSE, test_only);
1871
1872 /* could not get old icon, use terminal name */
1873 if (oldicon == NULL && !test_only)
1874 {
1875 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001876 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00001878 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879 }
1880
1881 return retval;
1882}
1883
1884 static int
1885get_x11_thing(get_title, test_only)
1886 int get_title; /* get title string */
1887 int test_only;
1888{
1889 XTextProperty text_prop;
1890 int retval = FALSE;
1891 Status status;
1892
1893 if (get_x11_windis() == OK)
1894 {
1895 /* Get window/icon name if any */
1896 if (get_title)
1897 status = XGetWMName(x11_display, x11_window, &text_prop);
1898 else
1899 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1900
1901 /*
1902 * If terminal is xterm, then x11_window may be a child window of the
1903 * outer xterm window that actually contains the window/icon name, so
1904 * keep traversing up the tree until a window with a title/icon is
1905 * found.
1906 */
1907 /* Previously this was only done for xterm and alikes. I don't see a
1908 * reason why it would fail for other terminal emulators.
1909 * if (term_is_xterm) */
1910 {
1911 Window root;
1912 Window parent;
1913 Window win = x11_window;
1914 Window *children;
1915 unsigned int num_children;
1916
1917 while (!status || text_prop.value == NULL)
1918 {
1919 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1920 &num_children))
1921 break;
1922 if (children)
1923 XFree((void *)children);
1924 if (parent == root || parent == 0)
1925 break;
1926
1927 win = parent;
1928 if (get_title)
1929 status = XGetWMName(x11_display, win, &text_prop);
1930 else
1931 status = XGetWMIconName(x11_display, win, &text_prop);
1932 }
1933 }
1934 if (status && text_prop.value != NULL)
1935 {
1936 retval = TRUE;
1937 if (!test_only)
1938 {
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001939#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
1940 if (text_prop.encoding == XA_STRING
1941# ifdef FEAT_MBYTE
1942 && !has_mbyte
1943# endif
1944 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00001945 {
1946#endif
1947 if (get_title)
1948 oldtitle = vim_strsave((char_u *)text_prop.value);
1949 else
1950 oldicon = vim_strsave((char_u *)text_prop.value);
Bram Moolenaarf82bac32010-07-25 22:30:20 +02001951#if defined(FEAT_XFONTSET) || defined(FEAT_MBYTE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001952 }
1953 else
1954 {
1955 char **cl;
1956 Status transform_status;
1957 int n = 0;
1958
1959 transform_status = XmbTextPropertyToTextList(x11_display,
1960 &text_prop,
1961 &cl, &n);
1962 if (transform_status >= Success && n > 0 && cl[0])
1963 {
1964 if (get_title)
1965 oldtitle = vim_strsave((char_u *) cl[0]);
1966 else
1967 oldicon = vim_strsave((char_u *) cl[0]);
1968 XFreeStringList(cl);
1969 }
1970 else
1971 {
1972 if (get_title)
1973 oldtitle = vim_strsave((char_u *)text_prop.value);
1974 else
1975 oldicon = vim_strsave((char_u *)text_prop.value);
1976 }
1977 }
1978#endif
1979 }
1980 XFree((void *)text_prop.value);
1981 }
1982 }
1983 return retval;
1984}
1985
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02001986/* Xutf8 functions are not avaialble on older systems. Note that on some
1987 * systems X_HAVE_UTF8_STRING may be defined in a header file but
1988 * Xutf8SetWMProperties() is not in the X11 library. Configure checks for
1989 * that and defines HAVE_XUTF8SETWMPROPERTIES. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001990#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
Bram Moolenaarcbc246a2014-10-11 14:47:26 +02001991# if X_HAVE_UTF8_STRING && HAVE_XUTF8SETWMPROPERTIES
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992# define USE_UTF8_STRING
1993# endif
1994#endif
1995
1996/*
1997 * Set x11 Window Title
1998 *
1999 * get_x11_windis() must be called before this and have returned OK
2000 */
2001 static void
2002set_x11_title(title)
2003 char_u *title;
2004{
2005 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
2006 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
2007 * supported everywhere and STRING doesn't work for multi-byte titles.
2008 */
2009#ifdef USE_UTF8_STRING
2010 if (enc_utf8)
2011 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
2012 NULL, NULL, 0, NULL, NULL, NULL);
2013 else
2014#endif
2015 {
2016#if XtSpecificationRelease >= 4
2017# ifdef FEAT_XFONTSET
2018 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
2019 NULL, NULL, 0, NULL, NULL, NULL);
2020# else
2021 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002022 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023
2024 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002025 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002026 XSetWMProperties(x11_display, x11_window, &text_prop,
2027 NULL, NULL, 0, NULL, NULL, NULL);
2028# endif
2029#else
2030 XStoreName(x11_display, x11_window, (char *)title);
2031#endif
2032 }
2033 XFlush(x11_display);
2034}
2035
2036/*
2037 * Set x11 Window icon
2038 *
2039 * get_x11_windis() must be called before this and have returned OK
2040 */
2041 static void
2042set_x11_icon(icon)
2043 char_u *icon;
2044{
2045 /* See above for comments about using X*SetWMProperties(). */
2046#ifdef USE_UTF8_STRING
2047 if (enc_utf8)
2048 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2049 NULL, 0, NULL, NULL, NULL);
2050 else
2051#endif
2052 {
2053#if XtSpecificationRelease >= 4
2054# ifdef FEAT_XFONTSET
2055 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
2056 NULL, 0, NULL, NULL, NULL);
2057# else
2058 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002059 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060
Bram Moolenaar9d75c832005-01-25 21:57:23 +00002061 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002062 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
2063 NULL, 0, NULL, NULL, NULL);
2064# endif
2065#else
2066 XSetIconName(x11_display, x11_window, (char *)icon);
2067#endif
2068 }
2069 XFlush(x11_display);
2070}
2071
2072#else /* FEAT_X11 */
2073
Bram Moolenaar071d4272004-06-13 20:20:40 +00002074 static int
2075get_x11_title(test_only)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002076 int test_only UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002077{
2078 return FALSE;
2079}
2080
2081 static int
2082get_x11_icon(test_only)
2083 int test_only;
2084{
2085 if (!test_only)
2086 {
2087 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002088 oldicon = vim_strsave(T_NAME + 8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002089 else
Bram Moolenaar20de1c22009-07-22 11:28:11 +00002090 oldicon = vim_strsave(T_NAME);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 }
2092 return FALSE;
2093}
2094
2095#endif /* FEAT_X11 */
2096
2097 int
2098mch_can_restore_title()
2099{
2100 return get_x11_title(TRUE);
2101}
2102
2103 int
2104mch_can_restore_icon()
2105{
2106 return get_x11_icon(TRUE);
2107}
2108
2109/*
2110 * Set the window title and icon.
2111 */
2112 void
2113mch_settitle(title, icon)
2114 char_u *title;
2115 char_u *icon;
2116{
2117 int type = 0;
2118 static int recursive = 0;
2119
2120 if (T_NAME == NULL) /* no terminal name (yet) */
2121 return;
2122 if (title == NULL && icon == NULL) /* nothing to do */
2123 return;
2124
2125 /* When one of the X11 functions causes a deadly signal, we get here again
2126 * recursively. Avoid hanging then (something is probably locked). */
2127 if (recursive)
2128 return;
2129 ++recursive;
2130
2131 /*
2132 * if the window ID and the display is known, we may use X11 calls
2133 */
2134#ifdef FEAT_X11
2135 if (get_x11_windis() == OK)
2136 type = 1;
2137#else
2138# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
2139 if (gui.in_use)
2140 type = 1;
2141# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002142#endif
2143
2144 /*
Bram Moolenaarf82bac32010-07-25 22:30:20 +02002145 * Note: if "t_ts" is set, title is set with escape sequence rather
Bram Moolenaar071d4272004-06-13 20:20:40 +00002146 * than x11 calls, because the x11 calls don't always work
2147 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148 if ((type || *T_TS != NUL) && title != NULL)
2149 {
2150 if (oldtitle == NULL
2151#ifdef FEAT_GUI
2152 && !gui.in_use
2153#endif
2154 ) /* first call but not in GUI, save title */
2155 (void)get_x11_title(FALSE);
2156
2157 if (*T_TS != NUL) /* it's OK if t_fs is empty */
2158 term_settitle(title);
2159#ifdef FEAT_X11
2160 else
2161# ifdef FEAT_GUI_GTK
2162 if (!gui.in_use) /* don't do this if GTK+ is running */
2163# endif
2164 set_x11_title(title); /* x11 */
2165#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00002166#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00002167 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
2168 else
2169 gui_mch_settitle(title, icon);
2170#endif
2171 did_set_title = TRUE;
2172 }
2173
2174 if ((type || *T_CIS != NUL) && icon != NULL)
2175 {
2176 if (oldicon == NULL
2177#ifdef FEAT_GUI
2178 && !gui.in_use
2179#endif
2180 ) /* first call, save icon */
2181 get_x11_icon(FALSE);
2182
2183 if (*T_CIS != NUL)
2184 {
2185 out_str(T_CIS); /* set icon start */
2186 out_str_nf(icon);
2187 out_str(T_CIE); /* set icon end */
2188 out_flush();
2189 }
2190#ifdef FEAT_X11
2191 else
2192# ifdef FEAT_GUI_GTK
2193 if (!gui.in_use) /* don't do this if GTK+ is running */
2194# endif
2195 set_x11_icon(icon); /* x11 */
2196#endif
2197 did_set_icon = TRUE;
2198 }
2199 --recursive;
2200}
2201
2202/*
2203 * Restore the window/icon title.
2204 * "which" is one of:
2205 * 1 only restore title
2206 * 2 only restore icon
2207 * 3 restore title and icon
2208 */
2209 void
2210mch_restore_title(which)
2211 int which;
2212{
2213 /* only restore the title or icon when it has been set */
2214 mch_settitle(((which & 1) && did_set_title) ?
2215 (oldtitle ? oldtitle : p_titleold) : NULL,
2216 ((which & 2) && did_set_icon) ? oldicon : NULL);
2217}
2218
2219#endif /* FEAT_TITLE */
2220
2221/*
2222 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002223 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002224 */
2225 int
2226vim_is_xterm(name)
2227 char_u *name;
2228{
2229 if (name == NULL)
2230 return FALSE;
2231 return (STRNICMP(name, "xterm", 5) == 0
2232 || STRNICMP(name, "nxterm", 6) == 0
2233 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002234 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002235 || STRNICMP(name, "rxvt", 4) == 0
2236 || STRCMP(name, "builtin_xterm") == 0);
2237}
2238
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002239#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2240/*
2241 * Return TRUE if "name" appears to be that of a terminal
2242 * known to support the xterm-style mouse protocol.
2243 * Relies on term_is_xterm having been set to its correct value.
2244 */
2245 int
2246use_xterm_like_mouse(name)
2247 char_u *name;
2248{
2249 return (name != NULL
2250 && (term_is_xterm || STRNICMP(name, "screen", 6) == 0));
2251}
2252#endif
2253
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2255/*
2256 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2257 * Return 1 for "xterm".
2258 * Return 2 for "xterm2".
Bram Moolenaarc8427482011-10-20 21:09:35 +02002259 * Return 3 for "urxvt".
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002260 * Return 4 for "sgr".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002261 */
2262 int
2263use_xterm_mouse()
2264{
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02002265 if (ttym_flags == TTYM_SGR)
2266 return 4;
Bram Moolenaarc8427482011-10-20 21:09:35 +02002267 if (ttym_flags == TTYM_URXVT)
2268 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269 if (ttym_flags == TTYM_XTERM2)
2270 return 2;
2271 if (ttym_flags == TTYM_XTERM)
2272 return 1;
2273 return 0;
2274}
2275#endif
2276
2277 int
2278vim_is_iris(name)
2279 char_u *name;
2280{
2281 if (name == NULL)
2282 return FALSE;
2283 return (STRNICMP(name, "iris-ansi", 9) == 0
2284 || STRCMP(name, "builtin_iris-ansi") == 0);
2285}
2286
2287 int
2288vim_is_vt300(name)
2289 char_u *name;
2290{
2291 if (name == NULL)
2292 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002293 /* catch VT100 - VT5xx */
2294 return ((STRNICMP(name, "vt", 2) == 0
2295 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296 || STRCMP(name, "builtin_vt320") == 0);
2297}
2298
2299/*
2300 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2301 * This should include all windowed terminal emulators.
2302 */
2303 int
2304vim_is_fastterm(name)
2305 char_u *name;
2306{
2307 if (name == NULL)
2308 return FALSE;
2309 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2310 return TRUE;
2311 return ( STRNICMP(name, "hpterm", 6) == 0
2312 || STRNICMP(name, "sun-cmd", 7) == 0
2313 || STRNICMP(name, "screen", 6) == 0
2314 || STRNICMP(name, "dtterm", 6) == 0);
2315}
2316
2317/*
2318 * Insert user name in s[len].
2319 * Return OK if a name found.
2320 */
2321 int
2322mch_get_user_name(s, len)
2323 char_u *s;
2324 int len;
2325{
2326#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002327 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328 return OK;
2329#else
2330 return mch_get_uname(getuid(), s, len);
2331#endif
2332}
2333
2334/*
2335 * Insert user name for "uid" in s[len].
2336 * Return OK if a name found.
2337 */
2338 int
2339mch_get_uname(uid, s, len)
2340 uid_t uid;
2341 char_u *s;
2342 int len;
2343{
2344#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2345 struct passwd *pw;
2346
2347 if ((pw = getpwuid(uid)) != NULL
2348 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2349 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002350 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002351 return OK;
2352 }
2353#endif
2354 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2355 return FAIL; /* a number is not a name */
2356}
2357
2358/*
2359 * Insert host name is s[len].
2360 */
2361
2362#ifdef HAVE_SYS_UTSNAME_H
2363 void
2364mch_get_host_name(s, len)
2365 char_u *s;
2366 int len;
2367{
2368 struct utsname vutsname;
2369
2370 if (uname(&vutsname) < 0)
2371 *s = NUL;
2372 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002373 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002374}
2375#else /* HAVE_SYS_UTSNAME_H */
2376
2377# ifdef HAVE_SYS_SYSTEMINFO_H
2378# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2379# endif
2380
2381 void
2382mch_get_host_name(s, len)
2383 char_u *s;
2384 int len;
2385{
2386# ifdef VAXC
2387 vaxc$gethostname((char *)s, len);
2388# else
2389 gethostname((char *)s, len);
2390# endif
2391 s[len - 1] = NUL; /* make sure it's terminated */
2392}
2393#endif /* HAVE_SYS_UTSNAME_H */
2394
2395/*
2396 * return process ID
2397 */
2398 long
2399mch_get_pid()
2400{
2401 return (long)getpid();
2402}
2403
2404#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2405static char *strerror __ARGS((int));
2406
2407 static char *
2408strerror(err)
2409 int err;
2410{
2411 extern int sys_nerr;
2412 extern char *sys_errlist[];
2413 static char er[20];
2414
2415 if (err > 0 && err < sys_nerr)
2416 return (sys_errlist[err]);
2417 sprintf(er, "Error %d", err);
2418 return er;
2419}
2420#endif
2421
2422/*
2423 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2424 * Return OK for success, FAIL for failure.
2425 */
2426 int
2427mch_dirname(buf, len)
2428 char_u *buf;
2429 int len;
2430{
2431#if defined(USE_GETCWD)
2432 if (getcwd((char *)buf, len) == NULL)
2433 {
2434 STRCPY(buf, strerror(errno));
2435 return FAIL;
2436 }
2437 return OK;
2438#else
2439 return (getwd((char *)buf) != NULL ? OK : FAIL);
2440#endif
2441}
2442
2443#if defined(OS2) || defined(PROTO)
2444/*
2445 * Replace all slashes by backslashes.
2446 * When 'shellslash' set do it the other way around.
2447 */
2448 void
2449slash_adjust(p)
2450 char_u *p;
2451{
2452 while (*p)
2453 {
2454 if (*p == psepcN)
2455 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002456 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002457 }
2458}
2459#endif
2460
2461/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002462 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002463 *
2464 * return FAIL for failure, OK for success
2465 */
2466 int
2467mch_FullName(fname, buf, len, force)
2468 char_u *fname, *buf;
2469 int len;
2470 int force; /* also expand when already absolute path */
2471{
2472 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002473#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002474 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002475#endif
2476#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002477 int fd = -1;
2478 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002479#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002480 char_u olddir[MAXPATHL];
2481 char_u *p;
2482 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002483#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002484 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2485 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002486#endif
2487
Bram Moolenaar38323e42007-03-06 19:22:53 +00002488#ifdef VMS
2489 fname = vms_fixfilename(fname);
2490#endif
2491
Bram Moolenaara2442432007-04-26 14:26:37 +00002492#ifdef __CYGWIN__
2493 /*
2494 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2495 */
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002496# if CYGWIN_VERSION_DLL_MAJOR >= 1007
2497 cygwin_conv_path(CCP_WIN_A_TO_POSIX, fname, posix_fname, MAXPATHL);
2498# else
Bram Moolenaarbf820722008-06-21 11:12:49 +00002499 cygwin_conv_to_posix_path(fname, posix_fname);
Bram Moolenaar0d1498e2008-06-29 12:00:49 +00002500# endif
Bram Moolenaarbf820722008-06-21 11:12:49 +00002501 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002502#endif
2503
Bram Moolenaar071d4272004-06-13 20:20:40 +00002504 /* expand it if forced or not an absolute path */
2505 if (force || !mch_isFullName(fname))
2506 {
2507 /*
2508 * If the file name has a path, change to that directory for a moment,
2509 * and then do the getwd() (and get back to where we were).
2510 * This will get the correct path name with "../" things.
2511 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002512#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002513 only_drive = 0;
2514 if (((p = vim_strrchr(fname, '/')) != NULL)
2515 || ((p = vim_strrchr(fname, '\\')) != NULL)
2516 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002517#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002518 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002519#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002520 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002521#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002522 /*
2523 * Use fchdir() if possible, it's said to be faster and more
2524 * reliable. But on SunOS 4 it might not work. Check this by
2525 * doing a fchdir() right now.
2526 */
2527 if (!dont_fchdir)
2528 {
2529 fd = open(".", O_RDONLY | O_EXTRA, 0);
2530 if (fd >= 0 && fchdir(fd) < 0)
2531 {
2532 close(fd);
2533 fd = -1;
2534 dont_fchdir = TRUE; /* don't try again */
2535 }
2536 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002537#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002538
2539 /* Only change directory when we are sure we can return to where
2540 * we are now. After doing "su" chdir(".") might not work. */
2541 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002542#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002543 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002544#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002545 (mch_dirname(olddir, MAXPATHL) == FAIL
2546 || mch_chdir((char *)olddir) != 0))
2547 {
2548 p = NULL; /* can't get current dir: don't chdir */
2549 retval = FAIL;
2550 }
2551 else
2552 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002553#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002554 /*
2555 * compensate for case where ':' from "D:" was the only
2556 * path separator detected in the file name; the _next_
2557 * character has to be removed, and then restored later.
2558 */
2559 if (only_drive)
2560 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002561#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002562 /* The directory is copied into buf[], to be able to remove
2563 * the file name without changing it (could be a string in
2564 * read-only memory) */
2565 if (p - fname >= len)
2566 retval = FAIL;
2567 else
2568 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002569 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002570 if (mch_chdir((char *)buf))
2571 retval = FAIL;
2572 else
2573 fname = p + 1;
2574 *buf = NUL;
2575 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002576#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002577 if (only_drive)
2578 {
2579 p--;
2580 if (retval != FAIL)
2581 fname--;
2582 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002583#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002584 }
2585 }
2586 if (mch_dirname(buf, len) == FAIL)
2587 {
2588 retval = FAIL;
2589 *buf = NUL;
2590 }
2591 if (p != NULL)
2592 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002593#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002594 if (fd >= 0)
2595 {
Bram Moolenaar25724922009-07-14 15:38:41 +00002596 if (p_verbose >= 5)
2597 {
2598 verbose_enter();
2599 MSG("fchdir() to previous dir");
2600 verbose_leave();
2601 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002602 l = fchdir(fd);
2603 close(fd);
2604 }
2605 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002606#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002607 l = mch_chdir((char *)olddir);
2608 if (l != 0)
2609 EMSG(_(e_prev_dir));
2610 }
2611
2612 l = STRLEN(buf);
Bram Moolenaardac75692012-10-14 04:35:45 +02002613 if (l >= len - 1)
2614 retval = FAIL; /* no space for trailing "/" */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002615#ifndef VMS
Bram Moolenaardac75692012-10-14 04:35:45 +02002616 else if (l > 0 && buf[l - 1] != '/' && *fname != NUL
Bram Moolenaar071d4272004-06-13 20:20:40 +00002617 && STRCMP(fname, ".") != 0)
Bram Moolenaardac75692012-10-14 04:35:45 +02002618 STRCAT(buf, "/");
Bram Moolenaar38323e42007-03-06 19:22:53 +00002619#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002620 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002621
Bram Moolenaar071d4272004-06-13 20:20:40 +00002622 /* Catch file names which are too long. */
Bram Moolenaar78a15312009-05-15 19:33:18 +00002623 if (retval == FAIL || (int)(STRLEN(buf) + STRLEN(fname)) >= len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002624 return FAIL;
2625
2626 /* Do not append ".", "/dir/." is equal to "/dir". */
2627 if (STRCMP(fname, ".") != 0)
2628 STRCAT(buf, fname);
2629
2630 return OK;
2631}
2632
2633/*
2634 * Return TRUE if "fname" does not depend on the current directory.
2635 */
2636 int
2637mch_isFullName(fname)
2638 char_u *fname;
2639{
2640#ifdef __EMX__
2641 return _fnisabs(fname);
2642#else
2643# ifdef VMS
2644 return ( fname[0] == '/' || fname[0] == '.' ||
2645 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2646 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2647 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2648# else
2649 return (*fname == '/' || *fname == '~');
2650# endif
2651#endif
2652}
2653
Bram Moolenaar24552be2005-12-10 20:17:30 +00002654#if defined(USE_FNAME_CASE) || defined(PROTO)
2655/*
2656 * Set the case of the file name, if it already exists. This will cause the
2657 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002658 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002659 */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002660 void
2661fname_case(name, len)
2662 char_u *name;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00002663 int len UNUSED; /* buffer size, only used when name gets longer */
Bram Moolenaar24552be2005-12-10 20:17:30 +00002664{
2665 struct stat st;
2666 char_u *slash, *tail;
2667 DIR *dirp;
2668 struct dirent *dp;
2669
2670 if (lstat((char *)name, &st) >= 0)
2671 {
2672 /* Open the directory where the file is located. */
2673 slash = vim_strrchr(name, '/');
2674 if (slash == NULL)
2675 {
2676 dirp = opendir(".");
2677 tail = name;
2678 }
2679 else
2680 {
2681 *slash = NUL;
2682 dirp = opendir((char *)name);
2683 *slash = '/';
2684 tail = slash + 1;
2685 }
2686
2687 if (dirp != NULL)
2688 {
2689 while ((dp = readdir(dirp)) != NULL)
2690 {
2691 /* Only accept names that differ in case and are the same byte
2692 * length. TODO: accept different length name. */
2693 if (STRICMP(tail, dp->d_name) == 0
2694 && STRLEN(tail) == STRLEN(dp->d_name))
2695 {
2696 char_u newname[MAXPATHL + 1];
2697 struct stat st2;
2698
2699 /* Verify the inode is equal. */
2700 vim_strncpy(newname, name, MAXPATHL);
2701 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2702 MAXPATHL - (tail - name));
2703 if (lstat((char *)newname, &st2) >= 0
2704 && st.st_ino == st2.st_ino
2705 && st.st_dev == st2.st_dev)
2706 {
2707 STRCPY(tail, dp->d_name);
2708 break;
2709 }
2710 }
2711 }
2712
2713 closedir(dirp);
2714 }
2715 }
2716}
2717#endif
2718
Bram Moolenaar071d4272004-06-13 20:20:40 +00002719/*
2720 * Get file permissions for 'name'.
2721 * Returns -1 when it doesn't exist.
2722 */
2723 long
2724mch_getperm(name)
2725 char_u *name;
2726{
2727 struct stat statb;
2728
2729 /* Keep the #ifdef outside of stat(), it may be a macro. */
2730#ifdef VMS
2731 if (stat((char *)vms_fixfilename(name), &statb))
2732#else
2733 if (stat((char *)name, &statb))
2734#endif
2735 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002736#ifdef __INTERIX
2737 /* The top bit makes the value negative, which means the file doesn't
2738 * exist. Remove the bit, we don't use it. */
2739 return statb.st_mode & ~S_ADDACE;
2740#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002741 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002742#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002743}
2744
2745/*
2746 * set file permission for 'name' to 'perm'
2747 *
2748 * return FAIL for failure, OK otherwise
2749 */
2750 int
2751mch_setperm(name, perm)
2752 char_u *name;
2753 long perm;
2754{
2755 return (chmod((char *)
2756#ifdef VMS
2757 vms_fixfilename(name),
2758#else
2759 name,
2760#endif
2761 (mode_t)perm) == 0 ? OK : FAIL);
2762}
2763
2764#if defined(HAVE_ACL) || defined(PROTO)
2765# ifdef HAVE_SYS_ACL_H
2766# include <sys/acl.h>
2767# endif
2768# ifdef HAVE_SYS_ACCESS_H
2769# include <sys/access.h>
2770# endif
2771
2772# ifdef HAVE_SOLARIS_ACL
2773typedef struct vim_acl_solaris_T {
2774 int acl_cnt;
2775 aclent_t *acl_entry;
2776} vim_acl_solaris_T;
2777# endif
2778
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002779#if defined(HAVE_SELINUX) || defined(PROTO)
2780/*
2781 * Copy security info from "from_file" to "to_file".
2782 */
2783 void
2784mch_copy_sec(from_file, to_file)
2785 char_u *from_file;
2786 char_u *to_file;
2787{
2788 if (from_file == NULL)
2789 return;
2790
2791 if (selinux_enabled == -1)
2792 selinux_enabled = is_selinux_enabled();
2793
2794 if (selinux_enabled > 0)
2795 {
2796 security_context_t from_context = NULL;
2797 security_context_t to_context = NULL;
2798
2799 if (getfilecon((char *)from_file, &from_context) < 0)
2800 {
2801 /* If the filesystem doesn't support extended attributes,
2802 the original had no special security context and the
2803 target cannot have one either. */
2804 if (errno == EOPNOTSUPP)
2805 return;
2806
2807 MSG_PUTS(_("\nCould not get security context for "));
2808 msg_outtrans(from_file);
2809 msg_putchar('\n');
2810 return;
2811 }
2812 if (getfilecon((char *)to_file, &to_context) < 0)
2813 {
2814 MSG_PUTS(_("\nCould not get security context for "));
2815 msg_outtrans(to_file);
2816 msg_putchar('\n');
2817 freecon (from_context);
2818 return ;
2819 }
2820 if (strcmp(from_context, to_context) != 0)
2821 {
2822 if (setfilecon((char *)to_file, from_context) < 0)
2823 {
2824 MSG_PUTS(_("\nCould not set security context for "));
2825 msg_outtrans(to_file);
2826 msg_putchar('\n');
2827 }
2828 }
2829 freecon(to_context);
2830 freecon(from_context);
2831 }
2832}
2833#endif /* HAVE_SELINUX */
2834
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002835#if defined(HAVE_SMACK) && !defined(PROTO)
2836/*
2837 * Copy security info from "from_file" to "to_file".
2838 */
2839 void
2840mch_copy_sec(from_file, to_file)
2841 char_u *from_file;
2842 char_u *to_file;
2843{
Bram Moolenaar62f167f2014-04-23 12:52:40 +02002844 static const char * const smack_copied_attributes[] =
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002845 {
2846 XATTR_NAME_SMACK,
2847 XATTR_NAME_SMACKEXEC,
2848 XATTR_NAME_SMACKMMAP
2849 };
2850
2851 char buffer[SMACK_LABEL_LEN];
2852 const char *name;
2853 int index;
2854 int ret;
2855 ssize_t size;
2856
2857 if (from_file == NULL)
2858 return;
2859
2860 for (index = 0 ; index < (int)(sizeof(smack_copied_attributes)
2861 / sizeof(smack_copied_attributes)[0]) ; index++)
2862 {
2863 /* get the name of the attribute to copy */
2864 name = smack_copied_attributes[index];
2865
2866 /* get the value of the attribute in buffer */
2867 size = getxattr((char*)from_file, name, buffer, sizeof(buffer));
2868 if (size >= 0)
2869 {
2870 /* copy the attribute value of buffer */
2871 ret = setxattr((char*)to_file, name, buffer, (size_t)size, 0);
2872 if (ret < 0)
2873 {
2874 MSG_PUTS(_("Could not set security context "));
2875 MSG_PUTS(name);
2876 MSG_PUTS(_(" for "));
2877 msg_outtrans(to_file);
2878 msg_putchar('\n');
2879 }
2880 }
2881 else
2882 {
2883 /* what reason of not having the attribute value? */
2884 switch (errno)
2885 {
2886 case ENOTSUP:
2887 /* extended attributes aren't supported or enabled */
2888 /* should a message be echoed? not sure... */
2889 return; /* leave because it isn't usefull to continue */
2890
2891 case ERANGE:
2892 default:
2893 /* no enough size OR unexpected error */
2894 MSG_PUTS(_("Could not get security context "));
2895 MSG_PUTS(name);
2896 MSG_PUTS(_(" for "));
2897 msg_outtrans(from_file);
2898 MSG_PUTS(_(". Removing it!\n"));
2899 /* FALLTHROUGH to remove the attribute */
2900
2901 case ENODATA:
2902 /* no attribute of this name */
2903 ret = removexattr((char*)to_file, name);
Bram Moolenaar57a728d2014-04-02 23:09:26 +02002904 /* Silently ignore errors, apparently this happens when
2905 * smack is not actually being used. */
Bram Moolenaar5bd32f42014-04-02 14:05:38 +02002906 break;
2907 }
2908 }
2909 }
2910}
2911#endif /* HAVE_SMACK */
2912
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913/*
2914 * Return a pointer to the ACL of file "fname" in allocated memory.
2915 * Return NULL if the ACL is not available for whatever reason.
2916 */
2917 vim_acl_T
2918mch_get_acl(fname)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002919 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002920{
2921 vim_acl_T ret = NULL;
2922#ifdef HAVE_POSIX_ACL
2923 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2924#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002925#ifdef HAVE_SOLARIS_ZFS_ACL
2926 acl_t *aclent;
2927
2928 if (acl_get((char *)fname, 0, &aclent) < 0)
2929 return NULL;
2930 ret = (vim_acl_T)aclent;
2931#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002932#ifdef HAVE_SOLARIS_ACL
2933 vim_acl_solaris_T *aclent;
2934
2935 aclent = malloc(sizeof(vim_acl_solaris_T));
2936 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2937 {
2938 free(aclent);
2939 return NULL;
2940 }
2941 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2942 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2943 {
2944 free(aclent->acl_entry);
2945 free(aclent);
2946 return NULL;
2947 }
2948 ret = (vim_acl_T)aclent;
2949#else
2950#if defined(HAVE_AIX_ACL)
2951 int aclsize;
2952 struct acl *aclent;
2953
2954 aclsize = sizeof(struct acl);
2955 aclent = malloc(aclsize);
2956 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2957 {
2958 if (errno == ENOSPC)
2959 {
2960 aclsize = aclent->acl_len;
2961 aclent = realloc(aclent, aclsize);
2962 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2963 {
2964 free(aclent);
2965 return NULL;
2966 }
2967 }
2968 else
2969 {
2970 free(aclent);
2971 return NULL;
2972 }
2973 }
2974 ret = (vim_acl_T)aclent;
2975#endif /* HAVE_AIX_ACL */
2976#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002977#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002978#endif /* HAVE_POSIX_ACL */
2979 return ret;
2980}
2981
2982/*
2983 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2984 */
2985 void
2986mch_set_acl(fname, aclent)
Bram Moolenaar78a15312009-05-15 19:33:18 +00002987 char_u *fname UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002988 vim_acl_T aclent;
2989{
2990 if (aclent == NULL)
2991 return;
2992#ifdef HAVE_POSIX_ACL
2993 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2994#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01002995#ifdef HAVE_SOLARIS_ZFS_ACL
2996 acl_set((char *)fname, (acl_t *)aclent);
2997#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002998#ifdef HAVE_SOLARIS_ACL
2999 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
3000 ((vim_acl_solaris_T *)aclent)->acl_entry);
3001#else
3002#ifdef HAVE_AIX_ACL
3003 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
3004#endif /* HAVE_AIX_ACL */
3005#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003006#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003007#endif /* HAVE_POSIX_ACL */
3008}
3009
3010 void
3011mch_free_acl(aclent)
3012 vim_acl_T aclent;
3013{
3014 if (aclent == NULL)
3015 return;
3016#ifdef HAVE_POSIX_ACL
3017 acl_free((acl_t)aclent);
3018#else
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003019#ifdef HAVE_SOLARIS_ZFS_ACL
3020 acl_free((acl_t *)aclent);
3021#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003022#ifdef HAVE_SOLARIS_ACL
3023 free(((vim_acl_solaris_T *)aclent)->acl_entry);
3024 free(aclent);
3025#else
3026#ifdef HAVE_AIX_ACL
3027 free(aclent);
3028#endif /* HAVE_AIX_ACL */
3029#endif /* HAVE_SOLARIS_ACL */
Bram Moolenaar8d462f92012-02-05 22:51:33 +01003030#endif /* HAVE_SOLARIS_ZFS_ACL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003031#endif /* HAVE_POSIX_ACL */
3032}
3033#endif
3034
3035/*
3036 * Set hidden flag for "name".
3037 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038 void
3039mch_hide(name)
Bram Moolenaar78a15312009-05-15 19:33:18 +00003040 char_u *name UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003041{
3042 /* can't hide a file */
3043}
3044
3045/*
3046 * return TRUE if "name" is a directory
3047 * return FALSE if "name" is not a directory
3048 * return FALSE for error
3049 */
3050 int
3051mch_isdir(name)
3052 char_u *name;
3053{
3054 struct stat statb;
3055
3056 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
3057 return FALSE;
3058 if (stat((char *)name, &statb))
3059 return FALSE;
3060#ifdef _POSIX_SOURCE
3061 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
3062#else
3063 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
3064#endif
3065}
3066
Bram Moolenaar071d4272004-06-13 20:20:40 +00003067static int executable_file __ARGS((char_u *name));
3068
3069/*
3070 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
3071 */
3072 static int
3073executable_file(name)
3074 char_u *name;
3075{
3076 struct stat st;
3077
3078 if (stat((char *)name, &st))
3079 return 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003080#ifdef VMS
3081 /* Like on Unix system file can have executable rights but not necessarily
3082 * be an executable, but on Unix is not a default for an ordianry file to
3083 * have an executable flag - on VMS it is in most cases.
3084 * Therefore, this check does not have any sense - let keep us to the
3085 * conventions instead:
3086 * *.COM and *.EXE files are the executables - the rest are not. This is
3087 * not ideal but better then it was.
3088 */
3089 int vms_executable = 0;
3090 if (S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0)
3091 {
3092 if (strstr(vms_tolower((char*)name),".exe") != NULL
3093 || strstr(vms_tolower((char*)name),".com")!= NULL)
3094 vms_executable = 1;
3095 }
3096 return vms_executable;
3097#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003099#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003100}
3101
3102/*
3103 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
Bram Moolenaarb5971142015-03-21 17:32:19 +01003104 * If "use_path" is FALSE only check if "name" is executable.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003105 * Return -1 if unknown.
3106 */
3107 int
Bram Moolenaarb5971142015-03-21 17:32:19 +01003108mch_can_exe(name, path, use_path)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003109 char_u *name;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003110 char_u **path;
Bram Moolenaarb5971142015-03-21 17:32:19 +01003111 int use_path;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003112{
3113 char_u *buf;
3114 char_u *p, *e;
3115 int retval;
3116
Bram Moolenaarb5971142015-03-21 17:32:19 +01003117 /* When "use_path" is false and if it's an absolute or relative path don't
3118 * need to use $PATH. */
3119 if (!use_path || mch_isFullName(name) || (name[0] == '.'
3120 && (name[1] == '/' || (name[1] == '.' && name[2] == '/'))))
Bram Moolenaar206f0112014-03-12 16:51:55 +01003121 {
Bram Moolenaarb5971142015-03-21 17:32:19 +01003122 /* There must be a path separator, files in the current directory
3123 * can't be executed. */
3124 if (gettail(name) != name && executable_file(name))
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003125 {
3126 if (path != NULL)
3127 {
3128 if (name[0] == '.')
3129 *path = FullName_save(name, TRUE);
3130 else
3131 *path = vim_strsave(name);
3132 }
3133 return TRUE;
3134 }
3135 return FALSE;
Bram Moolenaar206f0112014-03-12 16:51:55 +01003136 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003137
3138 p = (char_u *)getenv("PATH");
3139 if (p == NULL || *p == NUL)
3140 return -1;
3141 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
3142 if (buf == NULL)
3143 return -1;
3144
3145 /*
3146 * Walk through all entries in $PATH to check if "name" exists there and
3147 * is an executable file.
3148 */
3149 for (;;)
3150 {
3151 e = (char_u *)strchr((char *)p, ':');
3152 if (e == NULL)
3153 e = p + STRLEN(p);
3154 if (e - p <= 1) /* empty entry means current dir */
3155 STRCPY(buf, "./");
3156 else
3157 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00003158 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159 add_pathsep(buf);
3160 }
3161 STRCAT(buf, name);
3162 retval = executable_file(buf);
3163 if (retval == 1)
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003164 {
3165 if (path != NULL)
3166 {
3167 if (buf[0] == '.')
3168 *path = FullName_save(buf, TRUE);
3169 else
3170 *path = vim_strsave(buf);
3171 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003172 break;
Bram Moolenaarc7f02552014-04-01 21:00:59 +02003173 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003174
3175 if (*e != ':')
3176 break;
3177 p = e + 1;
3178 }
3179
3180 vim_free(buf);
3181 return retval;
3182}
Bram Moolenaar071d4272004-06-13 20:20:40 +00003183
3184/*
3185 * Check what "name" is:
3186 * NODE_NORMAL: file or directory (or doesn't exist)
3187 * NODE_WRITABLE: writable device, socket, fifo, etc.
3188 * NODE_OTHER: non-writable things
3189 */
3190 int
3191mch_nodetype(name)
3192 char_u *name;
3193{
3194 struct stat st;
3195
3196 if (stat((char *)name, &st))
3197 return NODE_NORMAL;
3198 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
3199 return NODE_NORMAL;
3200#ifndef OS2
3201 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
3202 return NODE_OTHER;
3203#endif
3204 /* Everything else is writable? */
3205 return NODE_WRITABLE;
3206}
3207
3208 void
3209mch_early_init()
3210{
3211#ifdef HAVE_CHECK_STACK_GROWTH
3212 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003213
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214 check_stack_growth((char *)&i);
3215
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003216# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003217 get_stack_limit();
3218# endif
3219
3220#endif
3221
3222 /*
3223 * Setup an alternative stack for signals. Helps to catch signals when
3224 * running out of stack space.
3225 * Use of sigaltstack() is preferred, it's more portable.
3226 * Ignore any errors.
3227 */
3228#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
Bram Moolenaar5a221812008-11-12 12:08:45 +00003229 signal_stack = (char *)alloc(SIGSTKSZ);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003230 init_signal_stack();
3231#endif
3232}
3233
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003234#if defined(EXITFREE) || defined(PROTO)
3235 void
3236mch_free_mem()
3237{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003238# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3239 if (clip_star.owned)
3240 clip_lose_selection(&clip_star);
3241 if (clip_plus.owned)
3242 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003243# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00003244# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003245 if (xterm_Shell != (Widget)0)
3246 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00003247# ifndef LESSTIF_VERSION
3248 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003249 if (xterm_dpy != NULL)
3250 XtCloseDisplay(xterm_dpy);
3251 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00003252 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003253 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00003254# ifdef FEAT_X11
3255 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
3256# endif
3257 }
3258# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003259# endif
Bram Moolenaar0eda7ac2010-06-26 05:38:18 +02003260# if defined(FEAT_X11)
Bram Moolenaare8208012008-06-20 09:59:25 +00003261 if (x11_display != NULL
3262# ifdef FEAT_XCLIPBOARD
3263 && x11_display != xterm_dpy
3264# endif
3265 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003266 XCloseDisplay(x11_display);
3267# endif
3268# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
3269 vim_free(signal_stack);
3270 signal_stack = NULL;
3271# endif
3272# ifdef FEAT_TITLE
3273 vim_free(oldtitle);
3274 vim_free(oldicon);
3275# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003276}
3277#endif
3278
Bram Moolenaar071d4272004-06-13 20:20:40 +00003279static void exit_scroll __ARGS((void));
3280
3281/*
3282 * Output a newline when exiting.
3283 * Make sure the newline goes to the same stream as the text.
3284 */
3285 static void
3286exit_scroll()
3287{
Bram Moolenaardf177f62005-02-22 08:39:57 +00003288 if (silent_mode)
3289 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003290 if (newline_on_exit || msg_didout)
3291 {
3292 if (msg_use_printf())
3293 {
3294 if (info_message)
3295 mch_msg("\n");
3296 else
3297 mch_errmsg("\r\n");
3298 }
3299 else
3300 out_char('\n');
3301 }
3302 else
3303 {
3304 restore_cterm_colors(); /* get original colors back */
3305 msg_clr_eos_force(); /* clear the rest of the display */
3306 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
3307 }
3308}
3309
3310 void
3311mch_exit(r)
3312 int r;
3313{
3314 exiting = TRUE;
3315
3316#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
3317 x11_export_final_selection();
3318#endif
3319
3320#ifdef FEAT_GUI
3321 if (!gui.in_use)
3322#endif
3323 {
3324 settmode(TMODE_COOK);
3325#ifdef FEAT_TITLE
3326 mch_restore_title(3); /* restore xterm title and icon name */
3327#endif
3328 /*
3329 * When t_ti is not empty but it doesn't cause swapping terminal
3330 * pages, need to output a newline when msg_didout is set. But when
3331 * t_ti does swap pages it should not go to the shell page. Do this
3332 * before stoptermcap().
3333 */
3334 if (swapping_screen() && !newline_on_exit)
3335 exit_scroll();
3336
3337 /* Stop termcap: May need to check for T_CRV response, which
3338 * requires RAW mode. */
3339 stoptermcap();
3340
3341 /*
3342 * A newline is only required after a message in the alternate screen.
3343 * This is set to TRUE by wait_return().
3344 */
3345 if (!swapping_screen() || newline_on_exit)
3346 exit_scroll();
3347
3348 /* Cursor may have been switched off without calling starttermcap()
3349 * when doing "vim -u vimrc" and vimrc contains ":q". */
3350 if (full_screen)
3351 cursor_on();
3352 }
3353 out_flush();
3354 ml_close_all(TRUE); /* remove all memfiles */
3355 may_core_dump();
3356#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003357 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003358 gui_exit(r);
3359#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003360
Bram Moolenaar56718732006-03-15 22:53:57 +00003361#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003362 mac_conv_cleanup();
3363#endif
3364
Bram Moolenaar071d4272004-06-13 20:20:40 +00003365#ifdef __QNX__
3366 /* A core dump won't be created if the signal handler
3367 * doesn't return, so we can't call exit() */
3368 if (deadly_signal != 0)
3369 return;
3370#endif
3371
Bram Moolenaar009b2592004-10-24 19:18:58 +00003372#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02003373 netbeans_send_disconnect();
Bram Moolenaar009b2592004-10-24 19:18:58 +00003374#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003375
3376#ifdef EXITFREE
3377 free_all_mem();
3378#endif
3379
Bram Moolenaar071d4272004-06-13 20:20:40 +00003380 exit(r);
3381}
3382
3383 static void
3384may_core_dump()
3385{
3386 if (deadly_signal != 0)
3387 {
3388 signal(deadly_signal, SIG_DFL);
3389 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3390 }
3391}
3392
3393#ifndef VMS
3394
3395 void
3396mch_settmode(tmode)
3397 int tmode;
3398{
3399 static int first = TRUE;
3400
3401 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3402#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3403 /*
3404 * for "new" tty systems
3405 */
3406# ifdef HAVE_TERMIOS_H
3407 static struct termios told;
3408 struct termios tnew;
3409# else
3410 static struct termio told;
3411 struct termio tnew;
3412# endif
3413
3414 if (first)
3415 {
3416 first = FALSE;
3417# if defined(HAVE_TERMIOS_H)
3418 tcgetattr(read_cmd_fd, &told);
3419# else
3420 ioctl(read_cmd_fd, TCGETA, &told);
3421# endif
3422 }
3423
3424 tnew = told;
3425 if (tmode == TMODE_RAW)
3426 {
3427 /*
3428 * ~ICRNL enables typing ^V^M
3429 */
3430 tnew.c_iflag &= ~ICRNL;
3431 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3432# if defined(IEXTEN) && !defined(__MINT__)
3433 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3434 /* but it breaks function keys on MINT */
3435# endif
3436 );
3437# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3438 tnew.c_oflag &= ~ONLCR;
3439# endif
3440 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3441 tnew.c_cc[VTIME] = 0; /* don't wait */
3442 }
3443 else if (tmode == TMODE_SLEEP)
3444 tnew.c_lflag &= ~(ECHO);
3445
3446# if defined(HAVE_TERMIOS_H)
3447 {
3448 int n = 10;
3449
3450 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3451 * few times. */
3452 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3453 && errno == EINTR && n > 0)
3454 --n;
3455 }
3456# else
3457 ioctl(read_cmd_fd, TCSETA, &tnew);
3458# endif
3459
3460#else
3461
3462 /*
3463 * for "old" tty systems
3464 */
3465# ifndef TIOCSETN
3466# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3467# endif
3468 static struct sgttyb ttybold;
3469 struct sgttyb ttybnew;
3470
3471 if (first)
3472 {
3473 first = FALSE;
3474 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3475 }
3476
3477 ttybnew = ttybold;
3478 if (tmode == TMODE_RAW)
3479 {
3480 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3481 ttybnew.sg_flags |= RAW;
3482 }
3483 else if (tmode == TMODE_SLEEP)
3484 ttybnew.sg_flags &= ~(ECHO);
3485 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3486#endif
3487 curr_tmode = tmode;
3488}
3489
3490/*
3491 * Try to get the code for "t_kb" from the stty setting
3492 *
3493 * Even if termcap claims a backspace key, the user's setting *should*
3494 * prevail. stty knows more about reality than termcap does, and if
3495 * somebody's usual erase key is DEL (which, for most BSD users, it will
3496 * be), they're going to get really annoyed if their erase key starts
3497 * doing forward deletes for no reason. (Eric Fischer)
3498 */
3499 void
3500get_stty()
3501{
3502 char_u buf[2];
3503 char_u *p;
3504
3505 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3506#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3507 /* for "new" tty systems */
3508# ifdef HAVE_TERMIOS_H
3509 struct termios keys;
3510# else
3511 struct termio keys;
3512# endif
3513
3514# if defined(HAVE_TERMIOS_H)
3515 if (tcgetattr(read_cmd_fd, &keys) != -1)
3516# else
3517 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3518# endif
3519 {
3520 buf[0] = keys.c_cc[VERASE];
3521 intr_char = keys.c_cc[VINTR];
3522#else
3523 /* for "old" tty systems */
3524 struct sgttyb keys;
3525
3526 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3527 {
3528 buf[0] = keys.sg_erase;
3529 intr_char = keys.sg_kill;
3530#endif
3531 buf[1] = NUL;
3532 add_termcode((char_u *)"kb", buf, FALSE);
3533
3534 /*
3535 * If <BS> and <DEL> are now the same, redefine <DEL>.
3536 */
3537 p = find_termcode((char_u *)"kD");
3538 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3539 do_fixdel(NULL);
3540 }
3541#if 0
3542 } /* to keep cindent happy */
3543#endif
3544}
3545
3546#endif /* VMS */
3547
3548#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3549/*
3550 * Set mouse clicks on or off.
3551 */
3552 void
3553mch_setmouse(on)
3554 int on;
3555{
3556 static int ison = FALSE;
3557 int xterm_mouse_vers;
3558
3559 if (on == ison) /* return quickly if nothing to do */
3560 return;
3561
3562 xterm_mouse_vers = use_xterm_mouse();
Bram Moolenaarc8427482011-10-20 21:09:35 +02003563
3564# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003565 if (ttym_flags == TTYM_URXVT)
3566 {
Bram Moolenaarc8427482011-10-20 21:09:35 +02003567 out_str_nf((char_u *)
3568 (on
3569 ? IF_EB("\033[?1015h", ESC_STR "[?1015h")
3570 : IF_EB("\033[?1015l", ESC_STR "[?1015l")));
3571 ison = on;
3572 }
3573# endif
3574
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003575# ifdef FEAT_MOUSE_SGR
3576 if (ttym_flags == TTYM_SGR)
3577 {
3578 out_str_nf((char_u *)
3579 (on
3580 ? IF_EB("\033[?1006h", ESC_STR "[?1006h")
3581 : IF_EB("\033[?1006l", ESC_STR "[?1006l")));
3582 ison = on;
3583 }
3584# endif
3585
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586 if (xterm_mouse_vers > 0)
3587 {
3588 if (on) /* enable mouse events, use mouse tracking if available */
3589 out_str_nf((char_u *)
3590 (xterm_mouse_vers > 1
3591 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3592 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3593 else /* disable mouse events, could probably always send the same */
3594 out_str_nf((char_u *)
3595 (xterm_mouse_vers > 1
3596 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3597 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3598 ison = on;
3599 }
3600
3601# ifdef FEAT_MOUSE_DEC
3602 else if (ttym_flags == TTYM_DEC)
3603 {
3604 if (on) /* enable mouse events */
3605 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3606 else /* disable mouse events */
3607 out_str_nf((char_u *)"\033['z");
3608 ison = on;
3609 }
3610# endif
3611
3612# ifdef FEAT_MOUSE_GPM
3613 else
3614 {
3615 if (on)
3616 {
3617 if (gpm_open())
3618 ison = TRUE;
3619 }
3620 else
3621 {
3622 gpm_close();
3623 ison = FALSE;
3624 }
3625 }
3626# endif
3627
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003628# ifdef FEAT_SYSMOUSE
3629 else
3630 {
3631 if (on)
3632 {
3633 if (sysmouse_open() == OK)
3634 ison = TRUE;
3635 }
3636 else
3637 {
3638 sysmouse_close();
3639 ison = FALSE;
3640 }
3641 }
3642# endif
3643
Bram Moolenaar071d4272004-06-13 20:20:40 +00003644# ifdef FEAT_MOUSE_JSB
3645 else
3646 {
3647 if (on)
3648 {
3649 /* D - Enable Mouse up/down messages
3650 * L - Enable Left Button Reporting
3651 * M - Enable Middle Button Reporting
3652 * R - Enable Right Button Reporting
3653 * K - Enable SHIFT and CTRL key Reporting
3654 * + - Enable Advanced messaging of mouse moves and up/down messages
3655 * Q - Quiet No Ack
3656 * # - Numeric value of mouse pointer required
3657 * 0 = Multiview 2000 cursor, used as standard
3658 * 1 = Windows Arrow
3659 * 2 = Windows I Beam
3660 * 3 = Windows Hour Glass
3661 * 4 = Windows Cross Hair
3662 * 5 = Windows UP Arrow
3663 */
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003664# ifdef JSBTERM_MOUSE_NONADVANCED
3665 /* Disables full feedback of pointer movements */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003666 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3667 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003668# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3670 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
Bram Moolenaarf8de1612013-04-15 15:32:25 +02003671# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003672 ison = TRUE;
3673 }
3674 else
3675 {
3676 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3677 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3678 ison = FALSE;
3679 }
3680 }
3681# endif
3682# ifdef FEAT_MOUSE_PTERM
3683 else
3684 {
3685 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3686 if (on)
3687 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3688 else
3689 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3690 ison = on;
3691 }
3692# endif
3693}
3694
3695/*
3696 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3697 */
3698 void
3699check_mouse_termcode()
3700{
3701# ifdef FEAT_MOUSE_XTERM
3702 if (use_xterm_mouse()
Bram Moolenaarc8427482011-10-20 21:09:35 +02003703# ifdef FEAT_MOUSE_URXVT
3704 && use_xterm_mouse() != 3
3705# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003706# ifdef FEAT_GUI
3707 && !gui.in_use
3708# endif
3709 )
3710 {
3711 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003712 ? IF_EB("\233M", CSI_STR "M")
3713 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714 if (*p_mouse != NUL)
3715 {
3716 /* force mouse off and maybe on to send possibly new mouse
3717 * activation sequence to the xterm, with(out) drag tracing. */
3718 mch_setmouse(FALSE);
3719 setmouse();
3720 }
3721 }
3722 else
3723 del_mouse_termcode(KS_MOUSE);
3724# endif
3725
3726# ifdef FEAT_MOUSE_GPM
3727 if (!use_xterm_mouse()
3728# ifdef FEAT_GUI
3729 && !gui.in_use
3730# endif
3731 )
3732 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3733# endif
3734
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003735# ifdef FEAT_SYSMOUSE
3736 if (!use_xterm_mouse()
3737# ifdef FEAT_GUI
3738 && !gui.in_use
3739# endif
3740 )
3741 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3742# endif
3743
Bram Moolenaar071d4272004-06-13 20:20:40 +00003744# ifdef FEAT_MOUSE_JSB
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003745 /* Conflicts with xterm mouse: "\033[" and "\033[M" ??? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746 if (!use_xterm_mouse()
3747# ifdef FEAT_GUI
3748 && !gui.in_use
3749# endif
3750 )
3751 set_mouse_termcode(KS_JSBTERM_MOUSE,
3752 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3753 else
3754 del_mouse_termcode(KS_JSBTERM_MOUSE);
3755# endif
3756
3757# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003758 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003759 * define it in the GUI or when using an xterm. */
3760 if (!use_xterm_mouse()
3761# ifdef FEAT_GUI
3762 && !gui.in_use
3763# endif
3764 )
3765 set_mouse_termcode(KS_NETTERM_MOUSE,
3766 (char_u *)IF_EB("\033}", ESC_STR "}"));
3767 else
3768 del_mouse_termcode(KS_NETTERM_MOUSE);
3769# endif
3770
3771# ifdef FEAT_MOUSE_DEC
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003772 /* Conflicts with xterm mouse: "\033[" and "\033[M" */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003773 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003774# ifdef FEAT_GUI
3775 && !gui.in_use
3776# endif
3777 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003778 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3779 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003780 else
3781 del_mouse_termcode(KS_DEC_MOUSE);
3782# endif
3783# ifdef FEAT_MOUSE_PTERM
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003784 /* same conflict as the dec mouse */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003785 if (!use_xterm_mouse()
Bram Moolenaar071d4272004-06-13 20:20:40 +00003786# ifdef FEAT_GUI
3787 && !gui.in_use
3788# endif
3789 )
3790 set_mouse_termcode(KS_PTERM_MOUSE,
3791 (char_u *) IF_EB("\033[", ESC_STR "["));
3792 else
3793 del_mouse_termcode(KS_PTERM_MOUSE);
3794# endif
Bram Moolenaarc8427482011-10-20 21:09:35 +02003795# ifdef FEAT_MOUSE_URXVT
Bram Moolenaar4e067c82014-07-30 17:21:58 +02003796 /* same conflict as the dec mouse */
Bram Moolenaarcbc17d62014-05-22 21:22:19 +02003797 if (use_xterm_mouse() == 3
Bram Moolenaarc8427482011-10-20 21:09:35 +02003798# ifdef FEAT_GUI
3799 && !gui.in_use
3800# endif
3801 )
3802 {
3803 set_mouse_termcode(KS_URXVT_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3804 ? IF_EB("\233", CSI_STR)
3805 : IF_EB("\033[", ESC_STR "[")));
3806
3807 if (*p_mouse != NUL)
3808 {
3809 mch_setmouse(FALSE);
3810 setmouse();
3811 }
3812 }
3813 else
3814 del_mouse_termcode(KS_URXVT_MOUSE);
3815# endif
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003816# ifdef FEAT_MOUSE_SGR
Bram Moolenaar24dc2302014-05-13 20:19:58 +02003817 /* There is no conflict with xterm mouse */
Bram Moolenaar2b9578f2012-08-15 16:21:32 +02003818 if (use_xterm_mouse() == 4
3819# ifdef FEAT_GUI
3820 && !gui.in_use
3821# endif
3822 )
3823 {
3824 set_mouse_termcode(KS_SGR_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3825 ? IF_EB("\233<", CSI_STR "<")
3826 : IF_EB("\033[<", ESC_STR "[<")));
3827
3828 if (*p_mouse != NUL)
3829 {
3830 mch_setmouse(FALSE);
3831 setmouse();
3832 }
3833 }
3834 else
3835 del_mouse_termcode(KS_SGR_MOUSE);
3836# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837}
3838#endif
3839
3840/*
3841 * set screen mode, always fails.
3842 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003843 int
3844mch_screenmode(arg)
Bram Moolenaar78a15312009-05-15 19:33:18 +00003845 char_u *arg UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003846{
3847 EMSG(_(e_screenmode));
3848 return FAIL;
3849}
3850
3851#ifndef VMS
3852
3853/*
3854 * Try to get the current window size:
3855 * 1. with an ioctl(), most accurate method
3856 * 2. from the environment variables LINES and COLUMNS
3857 * 3. from the termcap
3858 * 4. keep using the old values
3859 * Return OK when size could be determined, FAIL otherwise.
3860 */
3861 int
3862mch_get_shellsize()
3863{
3864 long rows = 0;
3865 long columns = 0;
3866 char_u *p;
3867
3868 /*
3869 * For OS/2 use _scrsize().
3870 */
3871# ifdef __EMX__
3872 {
3873 int s[2];
3874
3875 _scrsize(s);
3876 columns = s[0];
3877 rows = s[1];
3878 }
3879# endif
3880
3881 /*
3882 * 1. try using an ioctl. It is the most accurate method.
3883 *
3884 * Try using TIOCGWINSZ first, some systems that have it also define
3885 * TIOCGSIZE but don't have a struct ttysize.
3886 */
3887# ifdef TIOCGWINSZ
3888 {
3889 struct winsize ws;
3890 int fd = 1;
3891
3892 /* When stdout is not a tty, use stdin for the ioctl(). */
3893 if (!isatty(fd) && isatty(read_cmd_fd))
3894 fd = read_cmd_fd;
3895 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3896 {
3897 columns = ws.ws_col;
3898 rows = ws.ws_row;
3899 }
3900 }
3901# else /* TIOCGWINSZ */
3902# ifdef TIOCGSIZE
3903 {
3904 struct ttysize ts;
3905 int fd = 1;
3906
3907 /* When stdout is not a tty, use stdin for the ioctl(). */
3908 if (!isatty(fd) && isatty(read_cmd_fd))
3909 fd = read_cmd_fd;
3910 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3911 {
3912 columns = ts.ts_cols;
3913 rows = ts.ts_lines;
3914 }
3915 }
3916# endif /* TIOCGSIZE */
3917# endif /* TIOCGWINSZ */
3918
3919 /*
3920 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003921 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3922 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003923 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003924 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003925 {
3926 if ((p = (char_u *)getenv("LINES")))
3927 rows = atoi((char *)p);
3928 if ((p = (char_u *)getenv("COLUMNS")))
3929 columns = atoi((char *)p);
3930 }
3931
3932#ifdef HAVE_TGETENT
3933 /*
3934 * 3. try reading "co" and "li" entries from termcap
3935 */
3936 if (columns == 0 || rows == 0)
3937 getlinecol(&columns, &rows);
3938#endif
3939
3940 /*
3941 * 4. If everything fails, use the old values
3942 */
3943 if (columns <= 0 || rows <= 0)
3944 return FAIL;
3945
3946 Rows = rows;
3947 Columns = columns;
Bram Moolenaare057d402013-06-30 17:51:51 +02003948 limit_screen_size();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003949 return OK;
3950}
3951
3952/*
3953 * Try to set the window size to Rows and Columns.
3954 */
3955 void
3956mch_set_shellsize()
3957{
3958 if (*T_CWS)
3959 {
3960 /*
3961 * NOTE: if you get an error here that term_set_winsize() is
3962 * undefined, check the output of configure. It could probably not
3963 * find a ncurses, termcap or termlib library.
3964 */
3965 term_set_winsize((int)Rows, (int)Columns);
3966 out_flush();
3967 screen_start(); /* don't know where cursor is now */
3968 }
3969}
3970
3971#endif /* VMS */
3972
3973/*
3974 * Rows and/or Columns has changed.
3975 */
3976 void
3977mch_new_shellsize()
3978{
3979 /* Nothing to do. */
3980}
3981
Bram Moolenaar205b8862011-09-07 15:04:31 +02003982/*
3983 * Wait for process "child" to end.
3984 * Return "child" if it exited properly, <= 0 on error.
3985 */
3986 static pid_t
3987wait4pid(child, status)
3988 pid_t child;
3989 waitstatus *status;
3990{
3991 pid_t wait_pid = 0;
3992
3993 while (wait_pid != child)
3994 {
Bram Moolenaar6be120e2012-04-20 15:55:16 +02003995 /* When compiled with Python threads are probably used, in which case
3996 * wait() sometimes hangs for no obvious reason. Use waitpid()
3997 * instead and loop (like the GUI). Also needed for other interfaces,
3998 * they might call system(). */
3999# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004000 wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004001# else
Bram Moolenaar205b8862011-09-07 15:04:31 +02004002 wait_pid = waitpid(child, status, WNOHANG);
Bram Moolenaar6be120e2012-04-20 15:55:16 +02004003# endif
Bram Moolenaar205b8862011-09-07 15:04:31 +02004004 if (wait_pid == 0)
4005 {
Bram Moolenaar75676462013-01-30 14:55:42 +01004006 /* Wait for 10 msec before trying again. */
Bram Moolenaar205b8862011-09-07 15:04:31 +02004007 mch_delay(10L, TRUE);
4008 continue;
4009 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004010 if (wait_pid <= 0
4011# ifdef ECHILD
4012 && errno == ECHILD
4013# endif
4014 )
4015 break;
4016 }
4017 return wait_pid;
4018}
4019
Bram Moolenaar071d4272004-06-13 20:20:40 +00004020 int
4021mch_call_shell(cmd, options)
4022 char_u *cmd;
4023 int options; /* SHELL_*, see vim.h */
4024{
4025#ifdef VMS
4026 char *ifn = NULL;
4027 char *ofn = NULL;
4028#endif
4029 int tmode = cur_tmode;
4030#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
4031 int x;
4032# ifndef __EMX__
4033 char_u *newcmd; /* only needed for unix */
4034# else
4035 /*
4036 * Set the preferred shell in the EMXSHELL environment variable (but
4037 * only if it is different from what is already in the environment).
4038 * Emx then takes care of whether to use "/c" or "-c" in an
4039 * intelligent way. Simply pass the whole thing to emx's system() call.
4040 * Emx also starts an interactive shell if system() is passed an empty
4041 * string.
4042 */
4043 char_u *p, *old;
4044
4045 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
4046 {
4047 /* should check HAVE_SETENV, but I know we don't have it. */
4048 p = alloc(10 + strlen(p_sh));
4049 if (p)
4050 {
4051 sprintf((char *)p, "EMXSHELL=%s", p_sh);
4052 putenv((char *)p); /* don't free the pointer! */
4053 }
4054 }
4055# endif
4056
4057 out_flush();
4058
4059 if (options & SHELL_COOKED)
4060 settmode(TMODE_COOK); /* set to normal mode */
4061
Bram Moolenaar62b42182010-09-21 22:09:37 +02004062# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004063 save_clipboard();
Bram Moolenaar62b42182010-09-21 22:09:37 +02004064 loose_clipboard();
4065# endif
4066
Bram Moolenaar071d4272004-06-13 20:20:40 +00004067# ifdef __EMX__
4068 if (cmd == NULL)
4069 x = system(""); /* this starts an interactive shell in emx */
4070 else
4071 x = system((char *)cmd);
4072 /* system() returns -1 when error occurs in starting shell */
4073 if (x == -1 && !emsg_silent)
4074 {
4075 MSG_PUTS(_("\nCannot execute shell "));
4076 msg_outtrans(p_sh);
4077 msg_putchar('\n');
4078 }
4079# else /* not __EMX__ */
4080 if (cmd == NULL)
4081 x = system((char *)p_sh);
4082 else
4083 {
4084# ifdef VMS
4085 if (ofn = strchr((char *)cmd, '>'))
4086 *ofn++ = '\0';
4087 if (ifn = strchr((char *)cmd, '<'))
4088 {
4089 char *p;
4090
4091 *ifn++ = '\0';
4092 p = strchr(ifn,' '); /* chop off any trailing spaces */
4093 if (p)
4094 *p = '\0';
4095 }
4096 if (ofn)
4097 x = vms_sys((char *)cmd, ofn, ifn);
4098 else
4099 x = system((char *)cmd);
4100# else
4101 newcmd = lalloc(STRLEN(p_sh)
4102 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
4103 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
4104 if (newcmd == NULL)
4105 x = 0;
4106 else
4107 {
4108 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
4109 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
4110 (char *)p_shcf,
4111 (char *)cmd);
4112 x = system((char *)newcmd);
4113 vim_free(newcmd);
4114 }
4115# endif
4116 }
4117# ifdef VMS
4118 x = vms_sys_status(x);
4119# endif
4120 if (emsg_silent)
4121 ;
4122 else if (x == 127)
4123 MSG_PUTS(_("\nCannot execute shell sh\n"));
4124# endif /* __EMX__ */
4125 else if (x && !(options & SHELL_SILENT))
4126 {
4127 MSG_PUTS(_("\nshell returned "));
4128 msg_outnum((long)x);
4129 msg_putchar('\n');
4130 }
4131
4132 if (tmode == TMODE_RAW)
4133 settmode(TMODE_RAW); /* set to raw mode */
4134# ifdef FEAT_TITLE
4135 resettitle();
4136# endif
Bram Moolenaar1a0316c2013-03-13 17:50:25 +01004137# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4138 restore_clipboard();
4139# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140 return x;
4141
4142#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
4143
Bram Moolenaardf177f62005-02-22 08:39:57 +00004144# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
4145 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004146
4147 char_u *newcmd = NULL;
4148 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004149 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150 pid_t wait_pid = 0;
4151# ifdef HAVE_UNION_WAIT
4152 union wait status;
4153# else
4154 int status = -1;
4155# endif
4156 int retval = -1;
4157 char **argv = NULL;
4158 int argc;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004159 char_u *p_shcf_copy = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004160 int i;
4161 char_u *p;
4162 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004164# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004165 int pty_slave_fd = -1;
4166 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004167# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004168 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169 int fd_fromshell[2];
4170 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004171# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004173# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004174 static char envbuf_Rows[20];
4175 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00004176# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004177 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178
Bram Moolenaar62b42182010-09-21 22:09:37 +02004179 newcmd = vim_strsave(p_sh);
4180 if (newcmd == NULL) /* out of memory */
4181 goto error;
4182
Bram Moolenaar071d4272004-06-13 20:20:40 +00004183 out_flush();
4184 if (options & SHELL_COOKED)
4185 settmode(TMODE_COOK); /* set to normal mode */
4186
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004187 /*
4188 * Do this loop twice:
4189 * 1: find number of arguments
4190 * 2: separate them and build argv[]
4191 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004192 for (i = 0; i < 2; ++i)
4193 {
4194 p = newcmd;
4195 inquote = FALSE;
4196 argc = 0;
4197 for (;;)
4198 {
4199 if (i == 1)
4200 argv[argc] = (char *)p;
4201 ++argc;
4202 while (*p && (inquote || (*p != ' ' && *p != TAB)))
4203 {
4204 if (*p == '"')
4205 inquote = !inquote;
4206 ++p;
4207 }
4208 if (*p == NUL)
4209 break;
4210 if (i == 1)
4211 *p++ = NUL;
4212 p = skipwhite(p);
4213 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00004214 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004215 {
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004216 /*
4217 * Account for possible multiple args in p_shcf.
4218 */
4219 p = p_shcf;
4220 for (;;)
4221 {
4222 p = skiptowhite(p);
4223 if (*p == NUL)
4224 break;
4225 ++argc;
4226 p = skipwhite(p);
4227 }
4228
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
4230 if (argv == NULL) /* out of memory */
4231 goto error;
4232 }
4233 }
4234 if (cmd != NULL)
4235 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004236 char_u *s;
4237
Bram Moolenaar071d4272004-06-13 20:20:40 +00004238 if (extra_shell_arg != NULL)
4239 argv[argc++] = (char *)extra_shell_arg;
Bram Moolenaarea35ef62011-08-04 22:59:28 +02004240
4241 /* Break 'shellcmdflag' into white separated parts. This doesn't
4242 * handle quoted strings, they are very unlikely to appear. */
4243 p_shcf_copy = alloc((unsigned)STRLEN(p_shcf) + 1);
4244 if (p_shcf_copy == NULL) /* out of memory */
4245 goto error;
4246 s = p_shcf_copy;
4247 p = p_shcf;
4248 while (*p != NUL)
4249 {
4250 argv[argc++] = (char *)s;
4251 while (*p && *p != ' ' && *p != TAB)
4252 *s++ = *p++;
4253 *s++ = NUL;
4254 p = skipwhite(p);
4255 }
4256
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257 argv[argc++] = (char *)cmd;
4258 }
4259 argv[argc] = NULL;
4260
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00004262 * For the GUI, when writing the output into the buffer and when reading
4263 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
4264 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004265 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004266 if ((options & (SHELL_READ|SHELL_WRITE))
4267# ifdef FEAT_GUI
4268 || (gui.in_use && show_shell_mess)
4269# endif
4270 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004272# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004273 /*
4274 * Try to open a master pty.
4275 * If this works, open the slave pty.
4276 * If the slave can't be opened, close the master pty.
4277 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004278 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004279 {
4280 pty_master_fd = OpenPTY(&tty_name); /* open pty */
Bram Moolenaare70172e2011-08-04 19:36:52 +02004281 if (pty_master_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004282 {
Bram Moolenaare70172e2011-08-04 19:36:52 +02004283 /* Leaving out O_NOCTTY may lead to waitpid() always returning
4284 * 0 on Mac OS X 10.7 thereby causing freezes. Let's assume
4285 * adding O_NOCTTY always works when defined. */
4286#ifdef O_NOCTTY
4287 pty_slave_fd = open(tty_name, O_RDWR | O_NOCTTY | O_EXTRA, 0);
4288#else
4289 pty_slave_fd = open(tty_name, O_RDWR | O_EXTRA, 0);
4290#endif
4291 if (pty_slave_fd < 0)
4292 {
4293 close(pty_master_fd);
4294 pty_master_fd = -1;
4295 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004296 }
4297 }
4298 /*
4299 * If not opening a pty or it didn't work, try using pipes.
4300 */
4301 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004302# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303 {
4304 pipe_error = (pipe(fd_toshell) < 0);
4305 if (!pipe_error) /* pipe create OK */
4306 {
4307 pipe_error = (pipe(fd_fromshell) < 0);
4308 if (pipe_error) /* pipe create failed */
4309 {
4310 close(fd_toshell[0]);
4311 close(fd_toshell[1]);
4312 }
4313 }
4314 if (pipe_error)
4315 {
4316 MSG_PUTS(_("\nCannot create pipes\n"));
4317 out_flush();
4318 }
4319 }
4320 }
4321
4322 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004323 {
4324# ifdef __BEOS__
4325 beos_cleanup_read_thread();
4326# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004327
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328 if ((pid = fork()) == -1) /* maybe we should use vfork() */
4329 {
4330 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004331 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004332# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004333 || (gui.in_use && show_shell_mess)
4334# endif
4335 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004336 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004337# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004338 if (pty_master_fd >= 0) /* close the pseudo tty */
4339 {
4340 close(pty_master_fd);
4341 close(pty_slave_fd);
4342 }
4343 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004344# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345 {
4346 close(fd_toshell[0]);
4347 close(fd_toshell[1]);
4348 close(fd_fromshell[0]);
4349 close(fd_fromshell[1]);
4350 }
4351 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004352 }
4353 else if (pid == 0) /* child */
4354 {
4355 reset_signals(); /* handle signals normally */
4356
4357 if (!show_shell_mess || (options & SHELL_EXPAND))
4358 {
4359 int fd;
4360
4361 /*
4362 * Don't want to show any message from the shell. Can't just
4363 * close stdout and stderr though, because some systems will
4364 * break if you try to write to them after that, so we must
4365 * use dup() to replace them with something else -- webb
4366 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
4367 * waiting for input.
4368 */
4369 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
4370 fclose(stdin);
4371 fclose(stdout);
4372 fclose(stderr);
4373
4374 /*
4375 * If any of these open()'s and dup()'s fail, we just continue
4376 * anyway. It's not fatal, and on most systems it will make
4377 * no difference at all. On a few it will cause the execvp()
4378 * to exit with a non-zero status even when the completion
4379 * could be done, which is nothing too serious. If the open()
4380 * or dup() failed we'd just do the same thing ourselves
4381 * anyway -- webb
4382 */
4383 if (fd >= 0)
4384 {
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004385 ignored = dup(fd); /* To replace stdin (fd 0) */
4386 ignored = dup(fd); /* To replace stdout (fd 1) */
4387 ignored = dup(fd); /* To replace stderr (fd 2) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004388
4389 /* Don't need this now that we've duplicated it */
4390 close(fd);
4391 }
4392 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004393 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00004395 || gui.in_use
4396# endif
4397 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004398 {
4399
Bram Moolenaardf177f62005-02-22 08:39:57 +00004400# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004401 /* Create our own process group, so that the child and all its
4402 * children can be kill()ed. Don't do this when using pipes,
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004403 * because stdin is not a tty, we would lose /dev/tty. */
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004404 if (p_stmp)
Bram Moolenaar07256082009-02-04 13:19:42 +00004405 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004406 (void)setsid();
Bram Moolenaar07256082009-02-04 13:19:42 +00004407# if defined(SIGHUP)
4408 /* When doing "!xterm&" and 'shell' is bash: the shell
4409 * will exit and send SIGHUP to all processes in its
4410 * group, killing the just started process. Ignore SIGHUP
4411 * to avoid that. (suggested by Simon Schubert)
4412 */
4413 signal(SIGHUP, SIG_IGN);
4414# endif
4415 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004416# endif
4417# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004418 if (pty_slave_fd >= 0)
4419 {
4420 /* push stream discipline modules */
4421 if (options & SHELL_COOKED)
4422 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004423# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004424 /* Try to become controlling tty (probably doesn't work,
4425 * unless run by root) */
4426 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004427# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004428 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004429# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004430 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004431# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00004432 setenv("TERM", "dumb", 1);
4433 sprintf((char *)envbuf, "%ld", Rows);
4434 setenv("ROWS", (char *)envbuf, 1);
4435 sprintf((char *)envbuf, "%ld", Rows);
4436 setenv("LINES", (char *)envbuf, 1);
4437 sprintf((char *)envbuf, "%ld", Columns);
4438 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004439# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004440 /*
4441 * Putenv does not copy the string, it has to remain valid.
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004442 * Use a static array to avoid losing allocated memory.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004443 */
4444 putenv("TERM=dumb");
4445 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
4446 putenv(envbuf_Rows);
4447 sprintf(envbuf_Rows, "LINES=%ld", Rows);
4448 putenv(envbuf_Rows);
4449 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
4450 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004451# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004452
Bram Moolenaara5792f52005-11-23 21:25:05 +00004453 /*
4454 * stderr is only redirected when using the GUI, so that a
4455 * program like gpg can still access the terminal to get a
4456 * passphrase using stderr.
4457 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004458# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004459 if (pty_master_fd >= 0)
4460 {
4461 close(pty_master_fd); /* close master side of pty */
4462
4463 /* set up stdin/stdout/stderr for the child */
4464 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004465 ignored = dup(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004466 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004467 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004468 if (gui.in_use)
4469 {
4470 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004471 ignored = dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004472 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004473
4474 close(pty_slave_fd); /* has been dupped, close it now */
4475 }
4476 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004477# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004478 {
4479 /* set up stdin for the child */
4480 close(fd_toshell[1]);
4481 close(0);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004482 ignored = dup(fd_toshell[0]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004483 close(fd_toshell[0]);
4484
4485 /* set up stdout for the child */
4486 close(fd_fromshell[0]);
4487 close(1);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004488 ignored = dup(fd_fromshell[1]);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004489 close(fd_fromshell[1]);
4490
Bram Moolenaara5792f52005-11-23 21:25:05 +00004491# ifdef FEAT_GUI
4492 if (gui.in_use)
4493 {
4494 /* set up stderr for the child */
4495 close(2);
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004496 ignored = dup(1);
Bram Moolenaara5792f52005-11-23 21:25:05 +00004497 }
4498# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004499 }
4500 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004501
Bram Moolenaar071d4272004-06-13 20:20:40 +00004502 /*
4503 * There is no type cast for the argv, because the type may be
4504 * different on different machines. This may cause a warning
4505 * message with strict compilers, don't worry about it.
4506 * Call _exit() instead of exit() to avoid closing the connection
4507 * to the X server (esp. with GTK, which uses atexit()).
4508 */
4509 execvp(argv[0], argv);
4510 _exit(EXEC_FAILED); /* exec failed, return failure code */
4511 }
4512 else /* parent */
4513 {
4514 /*
4515 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004516 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004517 */
4518 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004519 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004520
4521 /*
4522 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004523 * This is also used to pipe stdin/stdout to/from the external
4524 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004526 if ((options & (SHELL_READ|SHELL_WRITE))
4527# ifdef FEAT_GUI
4528 || (gui.in_use && show_shell_mess)
4529# endif
4530 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004531 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004532# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004533 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004534# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004536# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4538 int ta_len = 0; /* valid bytes in ta_buf[] */
4539 int len;
4540 int p_more_save;
4541 int old_State;
4542 int c;
4543 int toshell_fd;
4544 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004545 garray_T ga;
4546 int noread_cnt;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004547# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4548 struct timeval start_tv;
4549# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004550
Bram Moolenaardf177f62005-02-22 08:39:57 +00004551# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004552 if (pty_master_fd >= 0)
4553 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004554 fromshell_fd = pty_master_fd;
4555 toshell_fd = dup(pty_master_fd);
4556 }
4557 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004558# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559 {
4560 close(fd_toshell[0]);
4561 close(fd_fromshell[1]);
4562 toshell_fd = fd_toshell[1];
4563 fromshell_fd = fd_fromshell[0];
4564 }
4565
4566 /*
4567 * Write to the child if there are typed characters.
4568 * Read from the child if there are characters available.
4569 * Repeat the reading a few times if more characters are
4570 * available. Need to check for typed keys now and then, but
4571 * not too often (delays when no chars are available).
4572 * This loop is quit if no characters can be read from the pty
4573 * (WaitForChar detected special condition), or there are no
4574 * characters available and the child has exited.
4575 * Only check if the child has exited when there is no more
4576 * output. The child may exit before all the output has
4577 * been printed.
4578 *
4579 * Currently this busy loops!
4580 * This can probably dead-lock when the write blocks!
4581 */
4582 p_more_save = p_more;
4583 p_more = FALSE;
4584 old_State = State;
4585 State = EXTERNCMD; /* don't redraw at window resize */
4586
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004587 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004588 {
4589 /* Fork a process that will write the lines to the
4590 * external program. */
4591 if ((wpid = fork()) == -1)
4592 {
4593 MSG_PUTS(_("\nCannot fork\n"));
4594 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004595 else if (wpid == 0) /* child */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004596 {
4597 linenr_T lnum = curbuf->b_op_start.lnum;
4598 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004599 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004600 size_t l;
4601
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004602 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004603 for (;;)
4604 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004605 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004606 if (l == 0)
4607 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004608 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004609 /* NL -> NUL translation */
4610 len = write(toshell_fd, "", (size_t)1);
4611 else
4612 {
Bram Moolenaar70b2a562012-01-10 22:26:17 +01004613 char_u *s = vim_strchr(lp + written, NL);
4614
Bram Moolenaar89d40322006-08-29 15:30:07 +00004615 len = write(toshell_fd, (char *)lp + written,
Bram Moolenaar78a15312009-05-15 19:33:18 +00004616 s == NULL ? l
4617 : (size_t)(s - (lp + written)));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004618 }
Bram Moolenaar78a15312009-05-15 19:33:18 +00004619 if (len == (int)l)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004620 {
4621 /* Finished a line, add a NL, unless this line
4622 * should not have one. */
4623 if (lnum != curbuf->b_op_end.lnum
Bram Moolenaar34d72d42015-07-17 14:18:08 +02004624 || (!curbuf->b_p_bin
4625 && curbuf->b_p_fixeol)
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004626 || (lnum != curbuf->b_no_eol_lnum
Bram Moolenaardf177f62005-02-22 08:39:57 +00004627 && (lnum !=
4628 curbuf->b_ml.ml_line_count
4629 || curbuf->b_p_eol)))
Bram Moolenaarfe86f2d2008-11-28 20:29:07 +00004630 ignored = write(toshell_fd, "\n",
4631 (size_t)1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004632 ++lnum;
4633 if (lnum > curbuf->b_op_end.lnum)
4634 {
4635 /* finished all the lines, close pipe */
4636 close(toshell_fd);
4637 toshell_fd = -1;
4638 break;
4639 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004640 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004641 written = 0;
4642 }
4643 else if (len > 0)
4644 written += len;
4645 }
4646 _exit(0);
4647 }
Bram Moolenaar205b8862011-09-07 15:04:31 +02004648 else /* parent */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004649 {
4650 close(toshell_fd);
4651 toshell_fd = -1;
4652 }
4653 }
4654
4655 if (options & SHELL_READ)
4656 ga_init2(&ga, 1, BUFLEN);
4657
4658 noread_cnt = 0;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004659# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4660 gettimeofday(&start_tv, NULL);
4661# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004662 for (;;)
4663 {
4664 /*
4665 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004666 * if there are any.
4667 * Don't do this if we are expanding wild cards (would eat
4668 * typeahead).
4669 * Don't do this when filtering and terminal is in cooked
4670 * mode, the shell command will handle the I/O. Avoids
4671 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004672 * Don't get characters when the child has already
4673 * finished (wait_pid == 0).
Bram Moolenaardf177f62005-02-22 08:39:57 +00004674 * Don't read characters unless we didn't get output for a
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004675 * while (noread_cnt > 4), avoids that ":r !ls" eats
4676 * typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004677 */
4678 len = 0;
4679 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004680 && ((options &
4681 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4682 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004683# ifdef FEAT_GUI
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004684 || gui.in_use
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004685# endif
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004686 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004687 && wait_pid == 0
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004688 && (ta_len > 0 || noread_cnt > 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004689 {
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004690 if (ta_len == 0)
4691 {
4692 /* Get extra characters when we don't have any.
4693 * Reset the counter and timer. */
4694 noread_cnt = 0;
4695# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4696 gettimeofday(&start_tv, NULL);
4697# endif
4698 len = ui_inchar(ta_buf, BUFLEN, 10L, 0);
4699 }
4700 if (ta_len > 0 || len > 0)
4701 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702 /*
4703 * For pipes:
4704 * Check for CTRL-C: send interrupt signal to child.
4705 * Check for CTRL-D: EOF, close pipe to child.
4706 */
4707 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4708 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004709# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004710 /*
4711 * Send SIGINT to the child's group or all
4712 * processes in our group.
4713 */
4714 if (ta_buf[ta_len] == Ctrl_C
4715 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004716 {
4717# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004718 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004719# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004720 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004722 if (wpid > 0)
4723 kill(wpid, SIGINT);
4724 }
4725# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004726 if (pty_master_fd < 0 && toshell_fd >= 0
4727 && ta_buf[ta_len] == Ctrl_D)
4728 {
4729 close(toshell_fd);
4730 toshell_fd = -1;
4731 }
4732 }
4733
4734 /* replace K_BS by <BS> and K_DEL by <DEL> */
4735 for (i = ta_len; i < ta_len + len; ++i)
4736 {
4737 if (ta_buf[i] == CSI && len - i > 2)
4738 {
4739 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4740 if (c == K_DEL || c == K_KDEL || c == K_BS)
4741 {
4742 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4743 (size_t)(len - i - 2));
4744 if (c == K_DEL || c == K_KDEL)
4745 ta_buf[i] = DEL;
4746 else
4747 ta_buf[i] = Ctrl_H;
4748 len -= 2;
4749 }
4750 }
4751 else if (ta_buf[i] == '\r')
4752 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004753# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004754 if (has_mbyte)
Bram Moolenaarfeba08b2009-06-16 13:12:07 +00004755 i += (*mb_ptr2len_len)(ta_buf + i,
4756 ta_len + len - i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004757# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004758 }
4759
4760 /*
4761 * For pipes: echo the typed characters.
4762 * For a pty this does not seem to work.
4763 */
4764 if (pty_master_fd < 0)
4765 {
4766 for (i = ta_len; i < ta_len + len; ++i)
4767 {
4768 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4769 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004770# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004771 else if (has_mbyte)
4772 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004773 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004774
4775 msg_outtrans_len(ta_buf + i, l);
4776 i += l - 1;
4777 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004778# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004779 else
4780 msg_outtrans_len(ta_buf + i, 1);
4781 }
4782 windgoto(msg_row, msg_col);
4783 out_flush();
4784 }
4785
4786 ta_len += len;
4787
4788 /*
4789 * Write the characters to the child, unless EOF has
4790 * been typed for pipes. Write one character at a
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004791 * time, to avoid losing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004792 * When writing buffer lines, drop the typed
4793 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004794 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004795 if (options & SHELL_WRITE)
4796 ta_len = 0;
4797 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004798 {
4799 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4800 if (len > 0)
4801 {
4802 ta_len -= len;
4803 mch_memmove(ta_buf, ta_buf + len, ta_len);
4804 }
4805 }
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004806 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004807 }
4808
Bram Moolenaardf177f62005-02-22 08:39:57 +00004809 if (got_int)
4810 {
4811 /* CTRL-C sends a signal to the child, we ignore it
4812 * ourselves */
4813# ifdef HAVE_SETSID
4814 kill(-pid, SIGINT);
4815# else
4816 kill(0, SIGINT);
4817# endif
4818 if (wpid > 0)
4819 kill(wpid, SIGINT);
4820 got_int = FALSE;
4821 }
4822
Bram Moolenaar071d4272004-06-13 20:20:40 +00004823 /*
4824 * Check if the child has any characters to be printed.
4825 * Read them and write them to our window. Repeat this as
4826 * long as there is something to do, avoid the 10ms wait
4827 * for mch_inchar(), or sending typeahead characters to
4828 * the external process.
4829 * TODO: This should handle escape sequences, compatible
4830 * to some terminal (vt52?).
4831 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004832 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004833 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4834 {
Bram Moolenaar540fc6f2010-12-17 16:27:16 +01004835 len = read_eintr(fromshell_fd, buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004836# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004837 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004838# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004839 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004840# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004841 );
4842 if (len <= 0) /* end of file or error */
4843 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004844
4845 noread_cnt = 0;
4846 if (options & SHELL_READ)
4847 {
4848 /* Do NUL -> NL translation, append NL separated
4849 * lines to the current buffer. */
4850 for (i = 0; i < len; ++i)
4851 {
4852 if (buffer[i] == NL)
4853 append_ga_line(&ga);
4854 else if (buffer[i] == NUL)
4855 ga_append(&ga, NL);
4856 else
4857 ga_append(&ga, buffer[i]);
4858 }
4859 }
4860# ifdef FEAT_MBYTE
4861 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862 {
4863 int l;
4864
Bram Moolenaardf177f62005-02-22 08:39:57 +00004865 len += buffer_off;
4866 buffer[len] = NUL;
4867
Bram Moolenaar071d4272004-06-13 20:20:40 +00004868 /* Check if the last character in buffer[] is
4869 * incomplete, keep these bytes for the next
4870 * round. */
4871 for (p = buffer; p < buffer + len; p += l)
4872 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004873 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874 if (l == 0)
4875 l = 1; /* NUL byte? */
4876 else if (MB_BYTE2LEN(*p) != l)
4877 break;
4878 }
4879 if (p == buffer) /* no complete character */
4880 {
4881 /* avoid getting stuck at an illegal byte */
4882 if (len >= 12)
4883 ++p;
4884 else
4885 {
4886 buffer_off = len;
4887 continue;
4888 }
4889 }
4890 c = *p;
4891 *p = NUL;
4892 msg_puts(buffer);
4893 if (p < buffer + len)
4894 {
4895 *p = c;
4896 buffer_off = (buffer + len) - p;
4897 mch_memmove(buffer, p, buffer_off);
4898 continue;
4899 }
4900 buffer_off = 0;
4901 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004902# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004903 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004904 {
4905 buffer[len] = NUL;
4906 msg_puts(buffer);
4907 }
4908
4909 windgoto(msg_row, msg_col);
4910 cursor_on();
4911 out_flush();
4912 if (got_int)
4913 break;
Bram Moolenaarb3dc8fd2009-02-22 01:52:59 +00004914
4915# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4916 {
4917 struct timeval now_tv;
4918 long msec;
4919
4920 /* Avoid that we keep looping here without
4921 * checking for a CTRL-C for a long time. Don't
4922 * break out too often to avoid losing typeahead. */
4923 gettimeofday(&now_tv, NULL);
4924 msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
4925 + (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
4926 if (msec > 2000)
4927 {
4928 noread_cnt = 5;
4929 break;
4930 }
4931 }
4932# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004933 }
4934
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004935 /* If we already detected the child has finished break the
4936 * loop now. */
4937 if (wait_pid == pid)
4938 break;
4939
Bram Moolenaar071d4272004-06-13 20:20:40 +00004940 /*
4941 * Check if the child still exists, before checking for
Bram Moolenaare37d50a2008-08-06 17:06:04 +00004942 * typed characters (otherwise we would lose typeahead).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004943 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004944# ifdef __NeXT__
Bram Moolenaar205b8862011-09-07 15:04:31 +02004945 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004946# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004947 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004948# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004949 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4950 || (wait_pid == pid && WIFEXITED(status)))
4951 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004952 /* Don't break the loop yet, try reading more
4953 * characters from "fromshell_fd" first. When using
4954 * pipes there might still be something to read and
4955 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004956 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004957 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004958 else
4959 wait_pid = 0;
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004960
Bram Moolenaar95a51352013-03-21 22:53:50 +01004961# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004962 /* Handle any X events, e.g. serving the clipboard. */
4963 clip_update();
4964# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004965 }
4966finished:
4967 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004968 if (options & SHELL_READ)
4969 {
4970 if (ga.ga_len > 0)
4971 {
4972 append_ga_line(&ga);
4973 /* remember that the NL was missing */
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004974 curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004975 }
4976 else
Bram Moolenaarcab35ad2011-02-15 17:39:22 +01004977 curbuf->b_no_eol_lnum = 0;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004978 ga_clear(&ga);
4979 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004980
Bram Moolenaar071d4272004-06-13 20:20:40 +00004981 /*
4982 * Give all typeahead that wasn't used back to ui_inchar().
4983 */
4984 if (ta_len)
4985 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004986 State = old_State;
4987 if (toshell_fd >= 0)
4988 close(toshell_fd);
4989 close(fromshell_fd);
4990 }
Bram Moolenaar95a51352013-03-21 22:53:50 +01004991# if defined(FEAT_XCLIPBOARD) && defined(FEAT_X11)
Bram Moolenaar090cfc12013-03-19 12:35:42 +01004992 else
4993 {
4994 /*
4995 * Similar to the loop above, but only handle X events, no
4996 * I/O.
4997 */
4998 for (;;)
4999 {
5000 if (got_int)
5001 {
5002 /* CTRL-C sends a signal to the child, we ignore it
5003 * ourselves */
5004# ifdef HAVE_SETSID
5005 kill(-pid, SIGINT);
5006# else
5007 kill(0, SIGINT);
5008# endif
5009 got_int = FALSE;
5010 }
5011# ifdef __NeXT__
5012 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
5013# else
5014 wait_pid = waitpid(pid, &status, WNOHANG);
5015# endif
5016 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
5017 || (wait_pid == pid && WIFEXITED(status)))
5018 {
5019 wait_pid = pid;
5020 break;
5021 }
5022
5023 /* Handle any X events, e.g. serving the clipboard. */
5024 clip_update();
5025
5026 mch_delay(10L, TRUE);
5027 }
5028 }
5029# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005030
5031 /*
5032 * Wait until our child has exited.
5033 * Ignore wait() returning pids of other children and returning
5034 * because of some signal like SIGWINCH.
5035 * Don't wait if wait_pid was already set above, indicating the
5036 * child already exited.
5037 */
Bram Moolenaar205b8862011-09-07 15:04:31 +02005038 if (wait_pid != pid)
5039 wait_pid = wait4pid(pid, &status);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005040
Bram Moolenaar624891f2010-10-13 16:22:09 +02005041# ifdef FEAT_GUI
5042 /* Close slave side of pty. Only do this after the child has
5043 * exited, otherwise the child may hang when it tries to write on
5044 * the pty. */
5045 if (pty_master_fd >= 0)
5046 close(pty_slave_fd);
5047# endif
5048
Bram Moolenaardf177f62005-02-22 08:39:57 +00005049 /* Make sure the child that writes to the external program is
5050 * dead. */
5051 if (wpid > 0)
Bram Moolenaar205b8862011-09-07 15:04:31 +02005052 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00005053 kill(wpid, SIGKILL);
Bram Moolenaar205b8862011-09-07 15:04:31 +02005054 wait4pid(wpid, NULL);
5055 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00005056
Bram Moolenaar071d4272004-06-13 20:20:40 +00005057 /*
5058 * Set to raw mode right now, otherwise a CTRL-C after
5059 * catch_signals() will kill Vim.
5060 */
5061 if (tmode == TMODE_RAW)
5062 settmode(TMODE_RAW);
5063 did_settmode = TRUE;
5064 set_signals();
5065
5066 if (WIFEXITED(status))
5067 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00005068 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005069 retval = WEXITSTATUS(status);
Bram Moolenaar75676462013-01-30 14:55:42 +01005070 if (retval != 0 && !emsg_silent)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005071 {
5072 if (retval == EXEC_FAILED)
5073 {
5074 MSG_PUTS(_("\nCannot execute shell "));
5075 msg_outtrans(p_sh);
5076 msg_putchar('\n');
5077 }
5078 else if (!(options & SHELL_SILENT))
5079 {
5080 MSG_PUTS(_("\nshell returned "));
5081 msg_outnum((long)retval);
5082 msg_putchar('\n');
5083 }
5084 }
5085 }
5086 else
5087 MSG_PUTS(_("\nCommand terminated\n"));
5088 }
5089 }
5090 vim_free(argv);
Bram Moolenaarea35ef62011-08-04 22:59:28 +02005091 vim_free(p_shcf_copy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005092
5093error:
5094 if (!did_settmode)
5095 if (tmode == TMODE_RAW)
5096 settmode(TMODE_RAW); /* set to raw mode */
5097# ifdef FEAT_TITLE
5098 resettitle();
5099# endif
5100 vim_free(newcmd);
5101
5102 return retval;
5103
5104#endif /* USE_SYSTEM */
5105}
5106
5107/*
5108 * Check for CTRL-C typed by reading all available characters.
5109 * In cooked mode we should get SIGINT, no need to check.
5110 */
5111 void
5112mch_breakcheck()
5113{
5114 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
5115 fill_input_buf(FALSE);
5116}
5117
5118/*
5119 * Wait "msec" msec until a character is available from the keyboard or from
5120 * inbuf[]. msec == -1 will block forever.
5121 * When a GUI is being used, this will never get called -- webb
5122 */
5123 static int
5124WaitForChar(msec)
5125 long msec;
5126{
5127#ifdef FEAT_MOUSE_GPM
5128 int gpm_process_wanted;
5129#endif
5130#ifdef FEAT_XCLIPBOARD
5131 int rest;
5132#endif
5133 int avail;
5134
5135 if (input_available()) /* something in inbuf[] */
5136 return 1;
5137
5138#if defined(FEAT_MOUSE_DEC)
5139 /* May need to query the mouse position. */
5140 if (WantQueryMouse)
5141 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00005142 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
5144 }
5145#endif
5146
5147 /*
5148 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
5149 * events. This is a bit complicated, because they might both be defined.
5150 */
5151#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
5152# ifdef FEAT_XCLIPBOARD
5153 rest = 0;
5154 if (do_xterm_trace())
5155 rest = msec;
5156# endif
5157 do
5158 {
5159# ifdef FEAT_XCLIPBOARD
5160 if (rest != 0)
5161 {
5162 msec = XT_TRACE_DELAY;
5163 if (rest >= 0 && rest < XT_TRACE_DELAY)
5164 msec = rest;
5165 if (rest >= 0)
5166 rest -= msec;
5167 }
5168# endif
5169# ifdef FEAT_MOUSE_GPM
5170 gpm_process_wanted = 0;
5171 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
5172# else
5173 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
5174# endif
5175 if (!avail)
5176 {
5177 if (input_available())
5178 return 1;
5179# ifdef FEAT_XCLIPBOARD
5180 if (rest == 0 || !do_xterm_trace())
5181# endif
5182 break;
5183 }
5184 }
5185 while (FALSE
5186# ifdef FEAT_MOUSE_GPM
5187 || (gpm_process_wanted && mch_gpm_process() == 0)
5188# endif
5189# ifdef FEAT_XCLIPBOARD
5190 || (!avail && rest != 0)
5191# endif
5192 );
5193
5194#else
5195 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
5196#endif
5197 return avail;
5198}
5199
Bram Moolenaar4ffa0702013-12-11 17:12:37 +01005200#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00005201/*
5202 * Wait "msec" msec until a character is available from file descriptor "fd".
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005203 * "msec" == 0 will check for characters once.
5204 * "msec" == -1 will block until a character is available.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005205 * When a GUI is being used, this will not be used for input -- webb
5206 * Returns also, when a request from Sniff is waiting -- toni.
5207 * Or when a Linux GPM mouse event is waiting.
Bram Moolenaar93c88e02015-09-15 14:12:05 +02005208 * Or when a clientserver message is on the queue.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005209 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005210#if defined(__BEOS__)
5211 int
5212#else
5213 static int
5214#endif
5215RealWaitForChar(fd, msec, check_for_gpm)
5216 int fd;
5217 long msec;
Bram Moolenaar78a15312009-05-15 19:33:18 +00005218 int *check_for_gpm UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005219{
5220 int ret;
Bram Moolenaar67c53842010-05-22 18:28:27 +02005221#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02005222 int nb_fd = netbeans_filedesc();
Bram Moolenaar67c53842010-05-22 18:28:27 +02005223#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005224#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005225 static int busy = FALSE;
5226
5227 /* May retry getting characters after an event was handled. */
5228# define MAY_LOOP
5229
5230# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5231 /* Remember at what time we started, so that we know how much longer we
5232 * should wait after being interrupted. */
5233# define USE_START_TV
5234 struct timeval start_tv;
5235
5236 if (msec > 0 && (
5237# ifdef FEAT_XCLIPBOARD
5238 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005239# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005240 ||
5241# endif
5242# endif
5243# ifdef USE_XSMP
5244 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005245# ifdef FEAT_MZSCHEME
5246 ||
5247# endif
5248# endif
5249# ifdef FEAT_MZSCHEME
5250 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005251# endif
5252 ))
5253 gettimeofday(&start_tv, NULL);
5254# endif
5255
5256 /* Handle being called recursively. This may happen for the session
5257 * manager stuff, it may save the file, which does a breakcheck. */
5258 if (busy)
5259 return 0;
5260#endif
5261
5262#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00005263 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005264#endif
5265 {
5266#ifdef MAY_LOOP
5267 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005268# ifdef FEAT_MZSCHEME
5269 int mzquantum_used = FALSE;
5270# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005271#endif
5272#ifndef HAVE_SELECT
Bram Moolenaar67c53842010-05-22 18:28:27 +02005273 struct pollfd fds[6];
Bram Moolenaar071d4272004-06-13 20:20:40 +00005274 int nfd;
5275# ifdef FEAT_XCLIPBOARD
5276 int xterm_idx = -1;
5277# endif
5278# ifdef FEAT_MOUSE_GPM
5279 int gpm_idx = -1;
5280# endif
5281# ifdef USE_XSMP
5282 int xsmp_idx = -1;
5283# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005284# ifdef FEAT_NETBEANS_INTG
5285 int nb_idx = -1;
5286# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005287 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005288
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005289# ifdef FEAT_MZSCHEME
5290 mzvim_check_threads();
5291 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5292 {
5293 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
5294 mzquantum_used = TRUE;
5295 }
5296# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005297 fds[0].fd = fd;
5298 fds[0].events = POLLIN;
5299 nfd = 1;
5300
5301# ifdef FEAT_SNIFF
5302# define SNIFF_IDX 1
5303 if (want_sniff_request)
5304 {
5305 fds[SNIFF_IDX].fd = fd_from_sniff;
5306 fds[SNIFF_IDX].events = POLLIN;
5307 nfd++;
5308 }
5309# endif
5310# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01005311 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005312 if (xterm_Shell != (Widget)0)
5313 {
5314 xterm_idx = nfd;
5315 fds[nfd].fd = ConnectionNumber(xterm_dpy);
5316 fds[nfd].events = POLLIN;
5317 nfd++;
5318 }
5319# endif
5320# ifdef FEAT_MOUSE_GPM
5321 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5322 {
5323 gpm_idx = nfd;
5324 fds[nfd].fd = gpm_fd;
5325 fds[nfd].events = POLLIN;
5326 nfd++;
5327 }
5328# endif
5329# ifdef USE_XSMP
5330 if (xsmp_icefd != -1)
5331 {
5332 xsmp_idx = nfd;
5333 fds[nfd].fd = xsmp_icefd;
5334 fds[nfd].events = POLLIN;
5335 nfd++;
5336 }
5337# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005338#ifdef FEAT_NETBEANS_INTG
5339 if (nb_fd != -1)
5340 {
5341 nb_idx = nfd;
5342 fds[nfd].fd = nb_fd;
5343 fds[nfd].events = POLLIN;
5344 nfd++;
5345 }
5346#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005347
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005348 ret = poll(fds, nfd, towait);
5349# ifdef FEAT_MZSCHEME
5350 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005351 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005352 finished = FALSE;
5353# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005354
5355# ifdef FEAT_SNIFF
5356 if (ret < 0)
5357 sniff_disconnect(1);
5358 else if (want_sniff_request)
5359 {
5360 if (fds[SNIFF_IDX].revents & POLLHUP)
5361 sniff_disconnect(1);
5362 if (fds[SNIFF_IDX].revents & POLLIN)
5363 sniff_request_waiting = 1;
5364 }
5365# endif
5366# ifdef FEAT_XCLIPBOARD
5367 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
5368 {
5369 xterm_update(); /* Maybe we should hand out clipboard */
5370 if (--ret == 0 && !input_available())
5371 /* Try again */
5372 finished = FALSE;
5373 }
5374# endif
5375# ifdef FEAT_MOUSE_GPM
5376 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
5377 {
5378 *check_for_gpm = 1;
5379 }
5380# endif
5381# ifdef USE_XSMP
5382 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
5383 {
5384 if (fds[xsmp_idx].revents & POLLIN)
5385 {
5386 busy = TRUE;
5387 xsmp_handle_requests();
5388 busy = FALSE;
5389 }
5390 else if (fds[xsmp_idx].revents & POLLHUP)
5391 {
5392 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005393 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005394 xsmp_close();
5395 }
5396 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005397 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005398 }
5399# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005400#ifdef FEAT_NETBEANS_INTG
5401 if (ret > 0 && nb_idx != -1 && fds[nb_idx].revents & POLLIN)
5402 {
5403 netbeans_read();
5404 --ret;
5405 }
5406#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005407
5408
5409#else /* HAVE_SELECT */
5410
5411 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005412 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005413 fd_set rfds, efds;
5414 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005415 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005416
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005417# ifdef FEAT_MZSCHEME
5418 mzvim_check_threads();
5419 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
5420 {
5421 towait = p_mzq; /* don't wait longer than 'mzquantum' */
5422 mzquantum_used = TRUE;
5423 }
5424# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005425# ifdef __EMX__
5426 /* don't check for incoming chars if not in raw mode, because select()
5427 * always returns TRUE then (in some version of emx.dll) */
5428 if (curr_tmode != TMODE_RAW)
5429 return 0;
5430# endif
5431
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005432 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005433 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005434 tv.tv_sec = towait / 1000;
5435 tv.tv_usec = (towait % 1000) * (1000000/1000);
5436 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005437 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005438 else
5439 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005440
5441 /*
5442 * Select on ready for reading and exceptional condition (end of file).
5443 */
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005444select_eintr:
5445 FD_ZERO(&rfds);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005446 FD_ZERO(&efds);
5447 FD_SET(fd, &rfds);
5448# if !defined(__QNX__) && !defined(__CYGWIN32__)
5449 /* For QNX select() always returns 1 if this is set. Why? */
5450 FD_SET(fd, &efds);
5451# endif
5452 maxfd = fd;
5453
5454# ifdef FEAT_SNIFF
5455 if (want_sniff_request)
5456 {
5457 FD_SET(fd_from_sniff, &rfds);
5458 FD_SET(fd_from_sniff, &efds);
5459 if (maxfd < fd_from_sniff)
5460 maxfd = fd_from_sniff;
5461 }
5462# endif
5463# ifdef FEAT_XCLIPBOARD
Bram Moolenaarb1e26502014-11-19 18:48:46 +01005464 may_restore_clipboard();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005465 if (xterm_Shell != (Widget)0)
5466 {
5467 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
5468 if (maxfd < ConnectionNumber(xterm_dpy))
5469 maxfd = ConnectionNumber(xterm_dpy);
Bram Moolenaardd82d692012-08-15 17:26:57 +02005470
5471 /* An event may have already been read but not handled. In
5472 * particulary, XFlush may cause this. */
5473 xterm_update();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005474 }
5475# endif
5476# ifdef FEAT_MOUSE_GPM
5477 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
5478 {
5479 FD_SET(gpm_fd, &rfds);
5480 FD_SET(gpm_fd, &efds);
5481 if (maxfd < gpm_fd)
5482 maxfd = gpm_fd;
5483 }
5484# endif
5485# ifdef USE_XSMP
5486 if (xsmp_icefd != -1)
5487 {
5488 FD_SET(xsmp_icefd, &rfds);
5489 FD_SET(xsmp_icefd, &efds);
5490 if (maxfd < xsmp_icefd)
5491 maxfd = xsmp_icefd;
5492 }
5493# endif
Bram Moolenaardd82d692012-08-15 17:26:57 +02005494# ifdef FEAT_NETBEANS_INTG
Bram Moolenaar67c53842010-05-22 18:28:27 +02005495 if (nb_fd != -1)
5496 {
5497 FD_SET(nb_fd, &rfds);
5498 if (maxfd < nb_fd)
5499 maxfd = nb_fd;
5500 }
Bram Moolenaardd82d692012-08-15 17:26:57 +02005501# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005502
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005503 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005504# ifdef EINTR
5505 if (ret == -1 && errno == EINTR)
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005506 {
5507 /* Check whether window has been resized, EINTR may be caused by
5508 * SIGWINCH. */
5509 if (do_resize)
5510 handle_resize();
5511
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005512 /* Interrupted by a signal, need to try again. We ignore msec
5513 * here, because we do want to check even after a timeout if
5514 * characters are available. Needed for reading output of an
5515 * external command after the process has finished. */
5516 goto select_eintr;
Bram Moolenaar2e7b1df2011-10-12 21:04:20 +02005517 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005518# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00005519# ifdef __TANDEM
5520 if (ret == -1 && errno == ENOTSUP)
5521 {
5522 FD_ZERO(&rfds);
5523 FD_ZERO(&efds);
5524 ret = 0;
5525 }
Bram Moolenaar493c7a82011-09-07 14:06:47 +02005526# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005527# ifdef FEAT_MZSCHEME
5528 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005529 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00005530 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005531# endif
5532
5533# ifdef FEAT_SNIFF
5534 if (ret < 0 )
5535 sniff_disconnect(1);
5536 else if (ret > 0 && want_sniff_request)
5537 {
5538 if (FD_ISSET(fd_from_sniff, &efds))
5539 sniff_disconnect(1);
5540 if (FD_ISSET(fd_from_sniff, &rfds))
5541 sniff_request_waiting = 1;
5542 }
5543# endif
5544# ifdef FEAT_XCLIPBOARD
5545 if (ret > 0 && xterm_Shell != (Widget)0
5546 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
5547 {
5548 xterm_update(); /* Maybe we should hand out clipboard */
5549 /* continue looping when we only got the X event and the input
5550 * buffer is empty */
5551 if (--ret == 0 && !input_available())
5552 {
5553 /* Try again */
5554 finished = FALSE;
5555 }
5556 }
5557# endif
5558# ifdef FEAT_MOUSE_GPM
5559 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
5560 {
5561 if (FD_ISSET(gpm_fd, &efds))
5562 gpm_close();
5563 else if (FD_ISSET(gpm_fd, &rfds))
5564 *check_for_gpm = 1;
5565 }
5566# endif
5567# ifdef USE_XSMP
5568 if (ret > 0 && xsmp_icefd != -1)
5569 {
5570 if (FD_ISSET(xsmp_icefd, &efds))
5571 {
5572 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005573 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005574 xsmp_close();
5575 if (--ret == 0)
5576 finished = FALSE; /* keep going if event was only one */
5577 }
5578 else if (FD_ISSET(xsmp_icefd, &rfds))
5579 {
5580 busy = TRUE;
5581 xsmp_handle_requests();
5582 busy = FALSE;
5583 if (--ret == 0)
5584 finished = FALSE; /* keep going if event was only one */
5585 }
5586 }
5587# endif
Bram Moolenaar67c53842010-05-22 18:28:27 +02005588#ifdef FEAT_NETBEANS_INTG
5589 if (ret > 0 && nb_fd != -1 && FD_ISSET(nb_fd, &rfds))
5590 {
5591 netbeans_read();
5592 --ret;
5593 }
5594#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005595
5596#endif /* HAVE_SELECT */
5597
5598#ifdef MAY_LOOP
5599 if (finished || msec == 0)
5600 break;
5601
Bram Moolenaar93c88e02015-09-15 14:12:05 +02005602# ifdef FEAT_CLIENTSERVER
5603 if (server_waiting())
5604 break;
5605# endif
5606
Bram Moolenaar071d4272004-06-13 20:20:40 +00005607 /* We're going to loop around again, find out for how long */
5608 if (msec > 0)
5609 {
5610# ifdef USE_START_TV
5611 struct timeval mtv;
5612
5613 /* Compute remaining wait time. */
5614 gettimeofday(&mtv, NULL);
5615 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
5616 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
5617# else
5618 /* Guess we got interrupted halfway. */
5619 msec = msec / 2;
5620# endif
5621 if (msec <= 0)
5622 break; /* waited long enough */
5623 }
5624#endif
5625 }
5626
5627 return (ret > 0);
5628}
5629
Bram Moolenaar071d4272004-06-13 20:20:40 +00005630#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00005631/*
Bram Moolenaar02743632005-07-25 20:42:36 +00005632 * Expand a path into all matching files and/or directories. Handles "*",
5633 * "?", "[a-z]", "**", etc.
5634 * "path" has backslashes before chars that are not to be expanded.
5635 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005636 */
5637 int
5638mch_expandpath(gap, path, flags)
5639 garray_T *gap;
5640 char_u *path;
5641 int flags; /* EW_* flags */
5642{
Bram Moolenaar02743632005-07-25 20:42:36 +00005643 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005644}
5645#endif
5646
5647/*
5648 * mch_expand_wildcards() - this code does wild-card pattern matching using
5649 * the shell
5650 *
5651 * return OK for success, FAIL for error (you may lose some memory) and put
5652 * an error message in *file.
5653 *
5654 * num_pat is number of input patterns
5655 * pat is array of pointers to input patterns
5656 * num_file is pointer to number of matched file names
5657 * file is pointer to array of pointers to matched file names
5658 */
5659
5660#ifndef SEEK_SET
5661# define SEEK_SET 0
5662#endif
5663#ifndef SEEK_END
5664# define SEEK_END 2
5665#endif
5666
Bram Moolenaar5555acc2006-04-07 21:33:12 +00005667#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00005668
Bram Moolenaar071d4272004-06-13 20:20:40 +00005669 int
5670mch_expand_wildcards(num_pat, pat, num_file, file, flags)
5671 int num_pat;
5672 char_u **pat;
5673 int *num_file;
5674 char_u ***file;
5675 int flags; /* EW_* flags */
5676{
5677 int i;
5678 size_t len;
5679 char_u *p;
5680 int dir;
5681#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00005682 /*
5683 * This is the OS/2 implementation.
5684 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005685# define EXPL_ALLOC_INC 16
5686 char_u **expl_files;
5687 size_t files_alloced, files_free;
5688 char_u *buf;
5689 int has_wildcard;
5690
5691 *num_file = 0; /* default: no files found */
5692 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
5693 files_free = EXPL_ALLOC_INC; /* how much space is not used */
5694 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
5695 if (*file == NULL)
5696 return FAIL;
5697
5698 for (; num_pat > 0; num_pat--, pat++)
5699 {
5700 expl_files = NULL;
5701 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
5702 /* expand environment var or home dir */
5703 buf = expand_env_save(*pat);
5704 else
5705 buf = vim_strsave(*pat);
5706 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005707 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005708 if (has_wildcard) /* yes, so expand them */
5709 expl_files = (char_u **)_fnexplode(buf);
5710
5711 /*
5712 * return value of buf if no wildcards left,
5713 * OR if no match AND EW_NOTFOUND is set.
5714 */
5715 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
5716 || (expl_files == NULL && (flags & EW_NOTFOUND)))
5717 { /* simply save the current contents of *buf */
5718 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
5719 if (expl_files != NULL)
5720 {
5721 expl_files[0] = vim_strsave(buf);
5722 expl_files[1] = NULL;
5723 }
5724 }
5725 vim_free(buf);
5726
5727 /*
5728 * Count number of names resulting from expansion,
5729 * At the same time add a backslash to the end of names that happen to
5730 * be directories, and replace slashes with backslashes.
5731 */
5732 if (expl_files)
5733 {
5734 for (i = 0; (p = expl_files[i]) != NULL; i++)
5735 {
5736 dir = mch_isdir(p);
5737 /* If we don't want dirs and this is one, skip it */
5738 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5739 continue;
5740
Bram Moolenaara2031822006-03-07 22:29:51 +00005741 /* Skip files that are not executable if we check for that. */
Bram Moolenaarb5971142015-03-21 17:32:19 +01005742 if (!dir && (flags & EW_EXEC)
5743 && !mch_can_exe(p, NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00005744 continue;
5745
Bram Moolenaar071d4272004-06-13 20:20:40 +00005746 if (--files_free == 0)
5747 {
5748 /* need more room in table of pointers */
5749 files_alloced += EXPL_ALLOC_INC;
5750 *file = (char_u **)vim_realloc(*file,
5751 sizeof(char_u **) * files_alloced);
5752 if (*file == NULL)
5753 {
5754 EMSG(_(e_outofmem));
5755 *num_file = 0;
5756 return FAIL;
5757 }
5758 files_free = EXPL_ALLOC_INC;
5759 }
5760 slash_adjust(p);
5761 if (dir)
5762 {
5763 /* For a directory we add a '/', unless it's already
5764 * there. */
5765 len = STRLEN(p);
5766 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5767 {
5768 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005769 if (!after_pathsep((*file)[*num_file],
5770 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005771 {
5772 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005773 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005774 }
5775 }
5776 }
5777 else
5778 {
5779 (*file)[*num_file] = vim_strsave(p);
5780 }
5781
5782 /*
5783 * Error message already given by either alloc or vim_strsave.
5784 * Should return FAIL, but returning OK works also.
5785 */
5786 if ((*file)[*num_file] == NULL)
5787 break;
5788 (*num_file)++;
5789 }
5790 _fnexplodefree((char **)expl_files);
5791 }
5792 }
5793 return OK;
5794
5795#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005796 /*
5797 * This is the non-OS/2 implementation (really Unix).
5798 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005799 int j;
5800 char_u *tempname;
5801 char_u *command;
5802 FILE *fd;
5803 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005804#define STYLE_ECHO 0 /* use "echo", the default */
5805#define STYLE_GLOB 1 /* use "glob", for csh */
5806#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5807#define STYLE_PRINT 3 /* use "print -N", for zsh */
5808#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5809 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005810 int shell_style = STYLE_ECHO;
5811 int check_spaces;
5812 static int did_find_nul = FALSE;
5813 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005814 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005815 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005816
5817 *num_file = 0; /* default: no files found */
5818 *file = NULL;
5819
5820 /*
5821 * If there are no wildcards, just copy the names to allocated memory.
5822 * Saves a lot of time, because we don't have to start a new shell.
5823 */
5824 if (!have_wildcard(num_pat, pat))
5825 return save_patterns(num_pat, pat, num_file, file);
5826
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005827# ifdef HAVE_SANDBOX
5828 /* Don't allow any shell command in the sandbox. */
5829 if (sandbox != 0 && check_secure())
5830 return FAIL;
5831# endif
5832
Bram Moolenaar071d4272004-06-13 20:20:40 +00005833 /*
5834 * Don't allow the use of backticks in secure and restricted mode.
5835 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005836 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005837 for (i = 0; i < num_pat; ++i)
5838 if (vim_strchr(pat[i], '`') != NULL
5839 && (check_restricted() || check_secure()))
5840 return FAIL;
5841
5842 /*
5843 * get a name for the temp file
5844 */
Bram Moolenaare5c421c2015-03-31 13:33:08 +02005845 if ((tempname = vim_tempname('o', FALSE)) == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005846 {
5847 EMSG(_(e_notmp));
5848 return FAIL;
5849 }
5850
5851 /*
5852 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005853 * file.
5854 * STYLE_BT: NL separated
5855 * If expanding `cmd` execute it directly.
5856 * STYLE_GLOB: NUL separated
5857 * If we use *csh, "glob" will work better than "echo".
5858 * STYLE_PRINT: NL or NUL separated
5859 * If we use *zsh, "print -N" will work better than "glob".
5860 * STYLE_VIMGLOB: NL separated
5861 * If we use *sh*, we define "vimglob()".
5862 * STYLE_ECHO: space separated.
5863 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005864 */
5865 if (num_pat == 1 && *pat[0] == '`'
5866 && (len = STRLEN(pat[0])) > 2
5867 && *(pat[0] + len - 1) == '`')
5868 shell_style = STYLE_BT;
5869 else if ((len = STRLEN(p_sh)) >= 3)
5870 {
5871 if (STRCMP(p_sh + len - 3, "csh") == 0)
5872 shell_style = STYLE_GLOB;
5873 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5874 shell_style = STYLE_PRINT;
5875 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005876 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5877 "sh") != NULL)
5878 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005879
Bram Moolenaarc7247912008-01-13 12:54:11 +00005880 /* Compute the length of the command. We need 2 extra bytes: for the
5881 * optional '&' and for the NUL.
5882 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005883 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005884 if (shell_style == STYLE_VIMGLOB)
5885 len += STRLEN(sh_vimglob_func);
5886
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005887 for (i = 0; i < num_pat; ++i)
5888 {
5889 /* Count the length of the patterns in the same way as they are put in
5890 * "command" below. */
5891#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005892 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005893#else
5894 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005895 for (j = 0; pat[i][j] != NUL; ++j)
5896 {
5897 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5898 ++len; /* may add a backslash */
5899 ++len;
5900 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005901#endif
5902 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005903 command = alloc(len);
5904 if (command == NULL)
5905 {
5906 /* out of memory */
5907 vim_free(tempname);
5908 return FAIL;
5909 }
5910
5911 /*
5912 * Build the shell command:
5913 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5914 * recognizes this).
5915 * - Add the shell command to print the expanded names.
5916 * - Add the temp file name.
5917 * - Add the file name patterns.
5918 */
5919 if (shell_style == STYLE_BT)
5920 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005921 /* change `command; command& ` to (command; command ) */
5922 STRCPY(command, "(");
5923 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005924 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005925 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005926 while (p > command && vim_iswhite(*p))
5927 --p;
5928 if (*p == '&') /* remove trailing '&' */
5929 {
5930 ampersent = TRUE;
5931 *p = ' ';
5932 }
5933 STRCAT(command, ">");
5934 }
5935 else
5936 {
5937 if (flags & EW_NOTFOUND)
5938 STRCPY(command, "set nonomatch; ");
5939 else
5940 STRCPY(command, "unset nonomatch; ");
5941 if (shell_style == STYLE_GLOB)
5942 STRCAT(command, "glob >");
5943 else if (shell_style == STYLE_PRINT)
5944 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005945 else if (shell_style == STYLE_VIMGLOB)
5946 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005947 else
5948 STRCAT(command, "echo >");
5949 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005950
Bram Moolenaar071d4272004-06-13 20:20:40 +00005951 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005952
Bram Moolenaar071d4272004-06-13 20:20:40 +00005953 if (shell_style != STYLE_BT)
5954 for (i = 0; i < num_pat; ++i)
5955 {
5956 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005957 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005958 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005959#ifdef USE_SYSTEM
5960 STRCAT(command, " \"");
5961 STRCAT(command, pat[i]);
5962 STRCAT(command, "\"");
5963#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005964 int intick = FALSE;
5965
Bram Moolenaar071d4272004-06-13 20:20:40 +00005966 p = command + STRLEN(command);
5967 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005968 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005969 {
5970 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005971 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005972 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5973 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005974 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005975 * backslash inside backticks, before a special character
5976 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005977 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005978 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5979 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005980 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005981 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005982 }
Bram Moolenaare4df1642014-08-29 12:58:44 +02005983 else if (!intick
5984 && ((flags & EW_KEEPDOLLAR) == 0 || pat[i][j] != '$')
5985 && vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005986 /* Put a backslash before a special character, but not
Bram Moolenaare4df1642014-08-29 12:58:44 +02005987 * when inside ``. And not for $var when EW_KEEPDOLLAR is
5988 * set. */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005989 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005990
5991 /* Copy one character. */
5992 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005993 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005994 *p = NUL;
5995#endif
5996 }
5997 if (flags & EW_SILENT)
5998 show_shell_mess = FALSE;
5999 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00006000 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006001
6002 /*
6003 * Using zsh -G: If a pattern has no matches, it is just deleted from
6004 * the argument list, otherwise zsh gives an error message and doesn't
6005 * expand any other pattern.
6006 */
6007 if (shell_style == STYLE_PRINT)
6008 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
6009
6010 /*
6011 * If we use -f then shell variables set in .cshrc won't get expanded.
6012 * vi can do it, so we will too, but it is only necessary if there is a "$"
6013 * in one of the patterns, otherwise we can still use the fast option.
6014 */
6015 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
6016 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
6017
6018 /*
6019 * execute the shell command
6020 */
6021 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
6022
6023 /* When running in the background, give it some time to create the temp
6024 * file, but don't wait for it to finish. */
6025 if (ampersent)
6026 mch_delay(10L, TRUE);
6027
6028 extra_shell_arg = NULL; /* cleanup */
6029 show_shell_mess = TRUE;
6030 vim_free(command);
6031
Bram Moolenaarc7247912008-01-13 12:54:11 +00006032 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006033 {
6034 mch_remove(tempname);
6035 vim_free(tempname);
6036 /*
6037 * With interactive completion, the error message is not printed.
6038 * However with USE_SYSTEM, I don't know how to turn off error messages
6039 * from the shell, so screen may still get messed up -- webb.
6040 */
6041#ifndef USE_SYSTEM
6042 if (!(flags & EW_SILENT))
6043#endif
6044 {
6045 redraw_later_clear(); /* probably messed up screen */
6046 msg_putchar('\n'); /* clear bottom line quickly */
6047 cmdline_row = Rows - 1; /* continue on last line */
6048#ifdef USE_SYSTEM
6049 if (!(flags & EW_SILENT))
6050#endif
6051 {
6052 MSG(_(e_wildexpand));
6053 msg_start(); /* don't overwrite this message */
6054 }
6055 }
6056 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
6057 * EW_NOTFOUND is given */
6058 if (shell_style == STYLE_BT)
6059 return FAIL;
6060 goto notfound;
6061 }
6062
6063 /*
6064 * read the names from the file into memory
6065 */
6066 fd = fopen((char *)tempname, READBIN);
6067 if (fd == NULL)
6068 {
6069 /* Something went wrong, perhaps a file name with a special char. */
6070 if (!(flags & EW_SILENT))
6071 {
6072 MSG(_(e_wildexpand));
6073 msg_start(); /* don't overwrite this message */
6074 }
6075 vim_free(tempname);
6076 goto notfound;
6077 }
6078 fseek(fd, 0L, SEEK_END);
6079 len = ftell(fd); /* get size of temp file */
6080 fseek(fd, 0L, SEEK_SET);
6081 buffer = alloc(len + 1);
6082 if (buffer == NULL)
6083 {
6084 /* out of memory */
6085 mch_remove(tempname);
6086 vim_free(tempname);
6087 fclose(fd);
6088 return FAIL;
6089 }
6090 i = fread((char *)buffer, 1, len, fd);
6091 fclose(fd);
6092 mch_remove(tempname);
Bram Moolenaar78a15312009-05-15 19:33:18 +00006093 if (i != (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006094 {
6095 /* unexpected read error */
6096 EMSG2(_(e_notread), tempname);
6097 vim_free(tempname);
6098 vim_free(buffer);
6099 return FAIL;
6100 }
6101 vim_free(tempname);
6102
Bram Moolenaarc7247912008-01-13 12:54:11 +00006103# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006104 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
6105 p = buffer;
Bram Moolenaarfe17e762013-06-29 14:17:02 +02006106 for (i = 0; i < (int)len; ++i)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006107 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
6108 *p++ = buffer[i];
6109 len = p - buffer;
6110# endif
6111
6112
6113 /* file names are separated with Space */
6114 if (shell_style == STYLE_ECHO)
6115 {
6116 buffer[len] = '\n'; /* make sure the buffer ends in NL */
6117 p = buffer;
6118 for (i = 0; *p != '\n'; ++i) /* count number of entries */
6119 {
6120 while (*p != ' ' && *p != '\n')
6121 ++p;
6122 p = skipwhite(p); /* skip to next entry */
6123 }
6124 }
6125 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006126 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006127 {
6128 buffer[len] = NUL; /* make sure the buffer ends in NUL */
6129 p = buffer;
6130 for (i = 0; *p != NUL; ++i) /* count number of entries */
6131 {
6132 while (*p != '\n' && *p != NUL)
6133 ++p;
6134 if (*p != NUL)
6135 ++p;
6136 p = skipwhite(p); /* skip leading white space */
6137 }
6138 }
6139 /* file names are separated with NUL */
6140 else
6141 {
6142 /*
6143 * Some versions of zsh use spaces instead of NULs to separate
6144 * results. Only do this when there is no NUL before the end of the
6145 * buffer, otherwise we would never be able to use file names with
6146 * embedded spaces when zsh does use NULs.
6147 * When we found a NUL once, we know zsh is OK, set did_find_nul and
6148 * don't check for spaces again.
6149 */
6150 check_spaces = FALSE;
6151 if (shell_style == STYLE_PRINT && !did_find_nul)
6152 {
6153 /* If there is a NUL, set did_find_nul, else set check_spaces */
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02006154 buffer[len] = NUL;
Bram Moolenaarb011af92013-12-11 13:21:51 +01006155 if (len && (int)STRLEN(buffer) < (int)len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006156 did_find_nul = TRUE;
6157 else
6158 check_spaces = TRUE;
6159 }
6160
6161 /*
6162 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
6163 * already is one, for STYLE_GLOB it needs to be added.
6164 */
6165 if (len && buffer[len - 1] == NUL)
6166 --len;
6167 else
6168 buffer[len] = NUL;
6169 i = 0;
6170 for (p = buffer; p < buffer + len; ++p)
6171 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
6172 {
6173 ++i;
6174 *p = NUL;
6175 }
6176 if (len)
6177 ++i; /* count last entry */
6178 }
6179 if (i == 0)
6180 {
6181 /*
6182 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
6183 * /bin/sh will happily expand it to nothing rather than returning an
6184 * error; and hey, it's good to check anyway -- webb.
6185 */
6186 vim_free(buffer);
6187 goto notfound;
6188 }
6189 *num_file = i;
6190 *file = (char_u **)alloc(sizeof(char_u *) * i);
6191 if (*file == NULL)
6192 {
6193 /* out of memory */
6194 vim_free(buffer);
6195 return FAIL;
6196 }
6197
6198 /*
6199 * Isolate the individual file names.
6200 */
6201 p = buffer;
6202 for (i = 0; i < *num_file; ++i)
6203 {
6204 (*file)[i] = p;
6205 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00006206 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
6207 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006208 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00006209 while (!(shell_style == STYLE_ECHO && *p == ' ')
6210 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006211 ++p;
6212 if (p == buffer + len) /* last entry */
6213 *p = NUL;
6214 else
6215 {
6216 *p++ = NUL;
6217 p = skipwhite(p); /* skip to next entry */
6218 }
6219 }
6220 else /* NUL separates */
6221 {
6222 while (*p && p < buffer + len) /* skip entry */
6223 ++p;
6224 ++p; /* skip NUL */
6225 }
6226 }
6227
6228 /*
6229 * Move the file names to allocated memory.
6230 */
6231 for (j = 0, i = 0; i < *num_file; ++i)
6232 {
6233 /* Require the files to exist. Helps when using /bin/sh */
6234 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
6235 continue;
6236
6237 /* check if this entry should be included */
6238 dir = (mch_isdir((*file)[i]));
6239 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
6240 continue;
6241
Bram Moolenaara2031822006-03-07 22:29:51 +00006242 /* Skip files that are not executable if we check for that. */
Bram Moolenaarb5971142015-03-21 17:32:19 +01006243 if (!dir && (flags & EW_EXEC)
6244 && !mch_can_exe((*file)[i], NULL, !(flags & EW_SHELLCMD)))
Bram Moolenaara2031822006-03-07 22:29:51 +00006245 continue;
6246
Bram Moolenaar071d4272004-06-13 20:20:40 +00006247 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
6248 if (p)
6249 {
6250 STRCPY(p, (*file)[i]);
6251 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00006252 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006253 (*file)[j++] = p;
6254 }
6255 }
6256 vim_free(buffer);
6257 *num_file = j;
6258
6259 if (*num_file == 0) /* rejected all entries */
6260 {
6261 vim_free(*file);
6262 *file = NULL;
6263 goto notfound;
6264 }
6265
6266 return OK;
6267
6268notfound:
6269 if (flags & EW_NOTFOUND)
6270 return save_patterns(num_pat, pat, num_file, file);
6271 return FAIL;
6272
6273#endif /* __EMX__ */
6274}
6275
6276#endif /* VMS */
6277
6278#ifndef __EMX__
6279 static int
6280save_patterns(num_pat, pat, num_file, file)
6281 int num_pat;
6282 char_u **pat;
6283 int *num_file;
6284 char_u ***file;
6285{
6286 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00006287 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006288
6289 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
6290 if (*file == NULL)
6291 return FAIL;
6292 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00006293 {
6294 s = vim_strsave(pat[i]);
6295 if (s != NULL)
6296 /* Be compatible with expand_filename(): halve the number of
6297 * backslashes. */
6298 backslash_halve(s);
6299 (*file)[i] = s;
6300 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006301 *num_file = num_pat;
6302 return OK;
6303}
6304#endif
6305
Bram Moolenaar071d4272004-06-13 20:20:40 +00006306/*
6307 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
6308 * expand.
6309 */
6310 int
6311mch_has_exp_wildcard(p)
6312 char_u *p;
6313{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006314 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006315 {
6316#ifndef OS2
6317 if (*p == '\\' && p[1] != NUL)
6318 ++p;
6319 else
6320#endif
6321 if (vim_strchr((char_u *)
6322#ifdef VMS
6323 "*?%"
6324#else
6325# ifdef OS2
6326 "*?"
6327# else
6328 "*?[{'"
6329# endif
6330#endif
6331 , *p) != NULL)
6332 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006333 }
6334 return FALSE;
6335}
6336
6337/*
6338 * Return TRUE if the string "p" contains a wildcard.
6339 * Don't recognize '~' at the end as a wildcard.
6340 */
6341 int
6342mch_has_wildcard(p)
6343 char_u *p;
6344{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00006345 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006346 {
6347#ifndef OS2
6348 if (*p == '\\' && p[1] != NUL)
6349 ++p;
6350 else
6351#endif
6352 if (vim_strchr((char_u *)
6353#ifdef VMS
6354 "*?%$"
6355#else
6356# ifdef OS2
6357# ifdef VIM_BACKTICK
6358 "*?$`"
6359# else
6360 "*?$"
6361# endif
6362# else
6363 "*?[{`'$"
6364# endif
6365#endif
6366 , *p) != NULL
6367 || (*p == '~' && p[1] != NUL))
6368 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006369 }
6370 return FALSE;
6371}
6372
6373#ifndef __EMX__
6374 static int
6375have_wildcard(num, file)
6376 int num;
6377 char_u **file;
6378{
6379 int i;
6380
6381 for (i = 0; i < num; i++)
6382 if (mch_has_wildcard(file[i]))
6383 return 1;
6384 return 0;
6385}
6386
6387 static int
6388have_dollars(num, file)
6389 int num;
6390 char_u **file;
6391{
6392 int i;
6393
6394 for (i = 0; i < num; i++)
6395 if (vim_strchr(file[i], '$') != NULL)
6396 return TRUE;
6397 return FALSE;
6398}
6399#endif /* ifndef __EMX__ */
6400
6401#ifndef HAVE_RENAME
6402/*
6403 * Scaled-down version of rename(), which is missing in Xenix.
6404 * This version can only move regular files and will fail if the
6405 * destination exists.
6406 */
6407 int
6408mch_rename(src, dest)
6409 const char *src, *dest;
6410{
6411 struct stat st;
6412
6413 if (stat(dest, &st) >= 0) /* fail if destination exists */
6414 return -1;
6415 if (link(src, dest) != 0) /* link file to new name */
6416 return -1;
6417 if (mch_remove(src) == 0) /* delete link to old name */
6418 return 0;
6419 return -1;
6420}
6421#endif /* !HAVE_RENAME */
6422
6423#ifdef FEAT_MOUSE_GPM
6424/*
6425 * Initializes connection with gpm (if it isn't already opened)
6426 * Return 1 if succeeded (or connection already opened), 0 if failed
6427 */
6428 static int
6429gpm_open()
6430{
6431 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
6432
6433 if (!gpm_flag)
6434 {
6435 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
6436 gpm_connect.defaultMask = ~GPM_HARD;
6437 /* Default handling for mouse move*/
6438 gpm_connect.minMod = 0; /* Handle any modifier keys */
6439 gpm_connect.maxMod = 0xffff;
6440 if (Gpm_Open(&gpm_connect, 0) > 0)
6441 {
6442 /* gpm library tries to handling TSTP causes
6443 * problems. Anyways, we close connection to Gpm whenever
6444 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00006445 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00006446 */
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006447# ifdef SIGTSTP
Bram Moolenaar071d4272004-06-13 20:20:40 +00006448 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
Bram Moolenaar76243bd2009-03-02 01:47:02 +00006449# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006450 return 1; /* succeed */
6451 }
6452 if (gpm_fd == -2)
6453 Gpm_Close(); /* We don't want to talk to xterm via gpm */
6454 return 0;
6455 }
6456 return 1; /* already open */
6457}
6458
6459/*
6460 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00006461 */
6462 static void
6463gpm_close()
6464{
6465 if (gpm_flag && gpm_fd >= 0) /* if Open */
6466 Gpm_Close();
6467}
6468
6469/* Reads gpm event and adds special keys to input buf. Returns length of
6470 * generated key sequence.
Bram Moolenaarc7f02552014-04-01 21:00:59 +02006471 * This function is styled after gui_send_mouse_event().
Bram Moolenaar071d4272004-06-13 20:20:40 +00006472 */
6473 static int
6474mch_gpm_process()
6475{
6476 int button;
6477 static Gpm_Event gpm_event;
6478 char_u string[6];
6479 int_u vim_modifiers;
6480 int row,col;
6481 unsigned char buttons_mask;
6482 unsigned char gpm_modifiers;
6483 static unsigned char old_buttons = 0;
6484
6485 Gpm_GetEvent(&gpm_event);
6486
6487#ifdef FEAT_GUI
6488 /* Don't put events in the input queue now. */
6489 if (hold_gui_events)
6490 return 0;
6491#endif
6492
6493 row = gpm_event.y - 1;
6494 col = gpm_event.x - 1;
6495
6496 string[0] = ESC; /* Our termcode */
6497 string[1] = 'M';
6498 string[2] = 'G';
6499 switch (GPM_BARE_EVENTS(gpm_event.type))
6500 {
6501 case GPM_DRAG:
6502 string[3] = MOUSE_DRAG;
6503 break;
6504 case GPM_DOWN:
6505 buttons_mask = gpm_event.buttons & ~old_buttons;
6506 old_buttons = gpm_event.buttons;
6507 switch (buttons_mask)
6508 {
6509 case GPM_B_LEFT:
6510 button = MOUSE_LEFT;
6511 break;
6512 case GPM_B_MIDDLE:
6513 button = MOUSE_MIDDLE;
6514 break;
6515 case GPM_B_RIGHT:
6516 button = MOUSE_RIGHT;
6517 break;
6518 default:
6519 return 0;
6520 /*Don't know what to do. Can more than one button be
6521 * reported in one event? */
6522 }
6523 string[3] = (char_u)(button | 0x20);
6524 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
6525 break;
6526 case GPM_UP:
6527 string[3] = MOUSE_RELEASE;
6528 old_buttons &= ~gpm_event.buttons;
6529 break;
6530 default:
6531 return 0;
6532 }
6533 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
6534 gpm_modifiers = gpm_event.modifiers;
6535 vim_modifiers = 0x0;
6536 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
6537 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
6538 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
6539 */
6540 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
6541 vim_modifiers |= MOUSE_SHIFT;
6542
6543 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
6544 vim_modifiers |= MOUSE_CTRL;
6545 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
6546 vim_modifiers |= MOUSE_ALT;
6547 string[3] |= vim_modifiers;
6548 string[4] = (char_u)(col + ' ' + 1);
6549 string[5] = (char_u)(row + ' ' + 1);
6550 add_to_input_buf(string, 6);
6551 return 6;
6552}
6553#endif /* FEAT_MOUSE_GPM */
6554
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006555#ifdef FEAT_SYSMOUSE
6556/*
6557 * Initialize connection with sysmouse.
6558 * Let virtual console inform us with SIGUSR2 for pending sysmouse
6559 * output, any sysmouse output than will be processed via sig_sysmouse().
6560 * Return OK if succeeded, FAIL if failed.
6561 */
6562 static int
6563sysmouse_open()
6564{
6565 struct mouse_info mouse;
6566
6567 mouse.operation = MOUSE_MODE;
6568 mouse.u.mode.mode = 0;
6569 mouse.u.mode.signal = SIGUSR2;
6570 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
6571 {
6572 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
6573 mouse.operation = MOUSE_SHOW;
6574 ioctl(1, CONS_MOUSECTL, &mouse);
6575 return OK;
6576 }
6577 return FAIL;
6578}
6579
6580/*
6581 * Stop processing SIGUSR2 signals, and also make sure that
6582 * virtual console do not send us any sysmouse related signal.
6583 */
6584 static void
6585sysmouse_close()
6586{
6587 struct mouse_info mouse;
6588
6589 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
6590 mouse.operation = MOUSE_MODE;
6591 mouse.u.mode.mode = 0;
6592 mouse.u.mode.signal = 0;
6593 ioctl(1, CONS_MOUSECTL, &mouse);
6594}
6595
6596/*
6597 * Gets info from sysmouse and adds special keys to input buf.
6598 */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00006599 static RETSIGTYPE
6600sig_sysmouse SIGDEFARG(sigarg)
6601{
6602 struct mouse_info mouse;
6603 struct video_info video;
6604 char_u string[6];
6605 int row, col;
6606 int button;
6607 int buttons;
6608 static int oldbuttons = 0;
6609
6610#ifdef FEAT_GUI
6611 /* Don't put events in the input queue now. */
6612 if (hold_gui_events)
6613 return;
6614#endif
6615
6616 mouse.operation = MOUSE_GETINFO;
6617 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
6618 && ioctl(1, FBIO_MODEINFO, &video) != -1
6619 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
6620 && video.vi_cheight > 0 && video.vi_cwidth > 0)
6621 {
6622 row = mouse.u.data.y / video.vi_cheight;
6623 col = mouse.u.data.x / video.vi_cwidth;
6624 buttons = mouse.u.data.buttons;
6625 string[0] = ESC; /* Our termcode */
6626 string[1] = 'M';
6627 string[2] = 'S';
6628 if (oldbuttons == buttons && buttons != 0)
6629 {
6630 button = MOUSE_DRAG;
6631 }
6632 else
6633 {
6634 switch (buttons)
6635 {
6636 case 0:
6637 button = MOUSE_RELEASE;
6638 break;
6639 case 1:
6640 button = MOUSE_LEFT;
6641 break;
6642 case 2:
6643 button = MOUSE_MIDDLE;
6644 break;
6645 case 4:
6646 button = MOUSE_RIGHT;
6647 break;
6648 default:
6649 return;
6650 }
6651 oldbuttons = buttons;
6652 }
6653 string[3] = (char_u)(button);
6654 string[4] = (char_u)(col + ' ' + 1);
6655 string[5] = (char_u)(row + ' ' + 1);
6656 add_to_input_buf(string, 6);
6657 }
6658 return;
6659}
6660#endif /* FEAT_SYSMOUSE */
6661
Bram Moolenaar071d4272004-06-13 20:20:40 +00006662#if defined(FEAT_LIBCALL) || defined(PROTO)
6663typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
6664typedef char_u * (*INTPROCSTR)__ARGS((int));
6665typedef int (*STRPROCINT)__ARGS((char_u *));
6666typedef int (*INTPROCINT)__ARGS((int));
6667
6668/*
6669 * Call a DLL routine which takes either a string or int param
6670 * and returns an allocated string.
6671 */
6672 int
6673mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
6674 char_u *libname;
6675 char_u *funcname;
6676 char_u *argstring; /* NULL when using a argint */
6677 int argint;
6678 char_u **string_result;/* NULL when using number_result */
6679 int *number_result;
6680{
6681# if defined(USE_DLOPEN)
6682 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006683 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006684# else
6685 shl_t hinstLib;
6686# endif
6687 STRPROCSTR ProcAdd;
6688 INTPROCSTR ProcAddI;
6689 char_u *retval_str = NULL;
6690 int retval_int = 0;
6691 int success = FALSE;
6692
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006693 /*
6694 * Get a handle to the DLL module.
6695 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006696# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006697 /* First clear any error, it's not cleared by the dlopen() call. */
6698 (void)dlerror();
6699
Bram Moolenaar071d4272004-06-13 20:20:40 +00006700 hinstLib = dlopen((char *)libname, RTLD_LAZY
6701# ifdef RTLD_LOCAL
6702 | RTLD_LOCAL
6703# endif
6704 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006705 if (hinstLib == NULL)
6706 {
6707 /* "dlerr" must be used before dlclose() */
6708 dlerr = (char *)dlerror();
6709 if (dlerr != NULL)
6710 EMSG2(_("dlerror = \"%s\""), dlerr);
6711 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006712# else
6713 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
6714# endif
6715
6716 /* If the handle is valid, try to get the function address. */
6717 if (hinstLib != NULL)
6718 {
6719# ifdef HAVE_SETJMP_H
6720 /*
6721 * Catch a crash when calling the library function. For example when
6722 * using a number where a string pointer is expected.
6723 */
6724 mch_startjmp();
6725 if (SETJMP(lc_jump_env) != 0)
6726 {
6727 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006728# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006729 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006730# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006731 mch_didjmp();
6732 }
6733 else
6734# endif
6735 {
6736 retval_str = NULL;
6737 retval_int = 0;
6738
6739 if (argstring != NULL)
6740 {
6741# if defined(USE_DLOPEN)
6742 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006743 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006744# else
6745 if (shl_findsym(&hinstLib, (const char *)funcname,
6746 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
6747 ProcAdd = NULL;
6748# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006749 if ((success = (ProcAdd != NULL
6750# if defined(USE_DLOPEN)
6751 && dlerr == NULL
6752# endif
6753 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006754 {
6755 if (string_result == NULL)
6756 retval_int = ((STRPROCINT)ProcAdd)(argstring);
6757 else
6758 retval_str = (ProcAdd)(argstring);
6759 }
6760 }
6761 else
6762 {
6763# if defined(USE_DLOPEN)
6764 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006765 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006766# else
6767 if (shl_findsym(&hinstLib, (const char *)funcname,
6768 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
6769 ProcAddI = NULL;
6770# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006771 if ((success = (ProcAddI != NULL
6772# if defined(USE_DLOPEN)
6773 && dlerr == NULL
6774# endif
6775 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006776 {
6777 if (string_result == NULL)
6778 retval_int = ((INTPROCINT)ProcAddI)(argint);
6779 else
6780 retval_str = (ProcAddI)(argint);
6781 }
6782 }
6783
6784 /* Save the string before we free the library. */
6785 /* Assume that a "1" or "-1" result is an illegal pointer. */
6786 if (string_result == NULL)
6787 *number_result = retval_int;
6788 else if (retval_str != NULL
6789 && retval_str != (char_u *)1
6790 && retval_str != (char_u *)-1)
6791 *string_result = vim_strsave(retval_str);
6792 }
6793
6794# ifdef HAVE_SETJMP_H
6795 mch_endjmp();
6796# ifdef SIGHASARG
6797 if (lc_signal != 0)
6798 {
6799 int i;
6800
6801 /* try to find the name of this signal */
6802 for (i = 0; signal_info[i].sig != -1; i++)
6803 if (lc_signal == signal_info[i].sig)
6804 break;
6805 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6806 }
6807# endif
6808# endif
6809
Bram Moolenaar071d4272004-06-13 20:20:40 +00006810# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006811 /* "dlerr" must be used before dlclose() */
6812 if (dlerr != NULL)
6813 EMSG2(_("dlerror = \"%s\""), dlerr);
6814
6815 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006816 (void)dlclose(hinstLib);
6817# else
6818 (void)shl_unload(hinstLib);
6819# endif
6820 }
6821
6822 if (!success)
6823 {
6824 EMSG2(_(e_libcall), funcname);
6825 return FAIL;
6826 }
6827
6828 return OK;
6829}
6830#endif
6831
6832#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6833static int xterm_trace = -1; /* default: disabled */
6834static int xterm_button;
6835
6836/*
6837 * Setup a dummy window for X selections in a terminal.
6838 */
6839 void
6840setup_term_clip()
6841{
6842 int z = 0;
6843 char *strp = "";
6844 Widget AppShell;
6845
6846 if (!x_connect_to_server())
6847 return;
6848
6849 open_app_context();
6850 if (app_context != NULL && xterm_Shell == (Widget)0)
6851 {
6852 int (*oldhandler)();
6853#if defined(HAVE_SETJMP_H)
6854 int (*oldIOhandler)();
6855#endif
6856# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6857 struct timeval start_tv;
6858
6859 if (p_verbose > 0)
6860 gettimeofday(&start_tv, NULL);
6861# endif
6862
6863 /* Ignore X errors while opening the display */
6864 oldhandler = XSetErrorHandler(x_error_check);
6865
6866#if defined(HAVE_SETJMP_H)
6867 /* Ignore X IO errors while opening the display */
6868 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6869 mch_startjmp();
6870 if (SETJMP(lc_jump_env) != 0)
6871 {
6872 mch_didjmp();
6873 xterm_dpy = NULL;
6874 }
6875 else
6876#endif
6877 {
6878 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6879 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6880#if defined(HAVE_SETJMP_H)
6881 mch_endjmp();
6882#endif
6883 }
6884
6885#if defined(HAVE_SETJMP_H)
6886 /* Now handle X IO errors normally. */
6887 (void)XSetIOErrorHandler(oldIOhandler);
6888#endif
6889 /* Now handle X errors normally. */
6890 (void)XSetErrorHandler(oldhandler);
6891
6892 if (xterm_dpy == NULL)
6893 {
6894 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006895 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006896 return;
6897 }
6898
6899 /* Catch terminating error of the X server connection. */
6900 (void)XSetIOErrorHandler(x_IOerror_handler);
6901
6902# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6903 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006904 {
6905 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006906 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006907 verbose_leave();
6908 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006909# endif
6910
6911 /* Create a Shell to make converters work. */
6912 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6913 applicationShellWidgetClass, xterm_dpy,
6914 NULL);
6915 if (AppShell == (Widget)0)
6916 return;
6917 xterm_Shell = XtVaCreatePopupShell("VIM",
6918 topLevelShellWidgetClass, AppShell,
6919 XtNmappedWhenManaged, 0,
6920 XtNwidth, 1,
6921 XtNheight, 1,
6922 NULL);
6923 if (xterm_Shell == (Widget)0)
6924 return;
6925
6926 x11_setup_atoms(xterm_dpy);
Bram Moolenaar7cfea752010-06-22 06:07:12 +02006927 x11_setup_selection(xterm_Shell);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006928 if (x11_display == NULL)
6929 x11_display = xterm_dpy;
6930
6931 XtRealizeWidget(xterm_Shell);
6932 XSync(xterm_dpy, False);
6933 xterm_update();
6934 }
6935 if (xterm_Shell != (Widget)0)
6936 {
6937 clip_init(TRUE);
6938 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6939 x11_window = (Window)atol(strp);
6940 /* Check if $WINDOWID is valid. */
6941 if (test_x11_window(xterm_dpy) == FAIL)
6942 x11_window = 0;
6943 if (x11_window != 0)
6944 xterm_trace = 0;
6945 }
6946}
6947
6948 void
6949start_xterm_trace(button)
6950 int button;
6951{
6952 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6953 return;
6954 xterm_trace = 1;
6955 xterm_button = button;
6956 do_xterm_trace();
6957}
6958
6959
6960 void
6961stop_xterm_trace()
6962{
6963 if (xterm_trace < 0)
6964 return;
6965 xterm_trace = 0;
6966}
6967
6968/*
6969 * Query the xterm pointer and generate mouse termcodes if necessary
6970 * return TRUE if dragging is active, else FALSE
6971 */
6972 static int
6973do_xterm_trace()
6974{
6975 Window root, child;
6976 int root_x, root_y;
6977 int win_x, win_y;
6978 int row, col;
6979 int_u mask_return;
6980 char_u buf[50];
6981 char_u *strp;
6982 long got_hints;
6983 static char_u *mouse_code;
6984 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6985 static int prev_row = 0, prev_col = 0;
6986 static XSizeHints xterm_hints;
6987
6988 if (xterm_trace <= 0)
6989 return FALSE;
6990
6991 if (xterm_trace == 1)
6992 {
6993 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006994 * have changed recently. */
6995 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6996 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006997 || xterm_hints.width_inc <= 1
6998 || xterm_hints.height_inc <= 1)
6999 {
7000 xterm_trace = -1; /* Not enough data -- disable tracing */
7001 return FALSE;
7002 }
7003
7004 /* Rely on the same mouse code for the duration of this */
7005 mouse_code = find_termcode(mouse_name);
7006 prev_row = mouse_row;
Bram Moolenaarcde88542015-08-11 19:14:00 +02007007 prev_col = mouse_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007008 xterm_trace = 2;
7009
7010 /* Find the offset of the chars, there might be a scrollbar on the
7011 * left of the window and/or a menu on the top (eterm etc.) */
7012 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7013 &win_x, &win_y, &mask_return);
7014 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
7015 - (xterm_hints.height_inc / 2);
7016 if (xterm_hints.y <= xterm_hints.height_inc / 2)
7017 xterm_hints.y = 2;
7018 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
7019 - (xterm_hints.width_inc / 2);
7020 if (xterm_hints.x <= xterm_hints.width_inc / 2)
7021 xterm_hints.x = 2;
7022 return TRUE;
7023 }
Bram Moolenaaref9d6aa2011-04-11 16:56:35 +02007024 if (mouse_code == NULL || STRLEN(mouse_code) > 45)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007025 {
7026 xterm_trace = 0;
7027 return FALSE;
7028 }
7029
7030 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
7031 &win_x, &win_y, &mask_return);
7032
7033 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
7034 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
7035 if (row == prev_row && col == prev_col)
7036 return TRUE;
7037
7038 STRCPY(buf, mouse_code);
7039 strp = buf + STRLEN(buf);
7040 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
7041 *strp++ = (char_u)(col + ' ' + 1);
7042 *strp++ = (char_u)(row + ' ' + 1);
7043 *strp = 0;
7044 add_to_input_buf(buf, STRLEN(buf));
7045
7046 prev_row = row;
7047 prev_col = col;
7048 return TRUE;
7049}
7050
7051# if defined(FEAT_GUI) || defined(PROTO)
7052/*
7053 * Destroy the display, window and app_context. Required for GTK.
7054 */
7055 void
7056clear_xterm_clip()
7057{
7058 if (xterm_Shell != (Widget)0)
7059 {
7060 XtDestroyWidget(xterm_Shell);
7061 xterm_Shell = (Widget)0;
7062 }
7063 if (xterm_dpy != NULL)
7064 {
Bram Moolenaare8208012008-06-20 09:59:25 +00007065# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007066 /* Lesstif and Solaris crash here, lose some memory */
7067 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00007068# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007069 if (x11_display == xterm_dpy)
7070 x11_display = NULL;
7071 xterm_dpy = NULL;
7072 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007073# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00007074 if (app_context != (XtAppContext)NULL)
7075 {
7076 /* Lesstif and Solaris crash here, lose some memory */
7077 XtDestroyApplicationContext(app_context);
7078 app_context = (XtAppContext)NULL;
7079 }
Bram Moolenaare8208012008-06-20 09:59:25 +00007080# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00007081}
7082# endif
7083
7084/*
Bram Moolenaar090cfc12013-03-19 12:35:42 +01007085 * Catch up with GUI or X events.
7086 */
7087 static void
7088clip_update()
7089{
7090# ifdef FEAT_GUI
7091 if (gui.in_use)
7092 gui_mch_update();
7093 else
7094# endif
7095 if (xterm_Shell != (Widget)0)
7096 xterm_update();
7097}
7098
7099/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00007100 * Catch up with any queued X events. This may put keyboard input into the
7101 * input buffer, call resize call-backs, trigger timers etc. If there is
7102 * nothing in the X event queue (& no timers pending), then we return
7103 * immediately.
7104 */
7105 static void
7106xterm_update()
7107{
7108 XEvent event;
7109
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007110 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00007111 {
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007112 XtInputMask mask = XtAppPending(app_context);
Bram Moolenaar071d4272004-06-13 20:20:40 +00007113
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007114 if (mask == 0 || vim_is_input_buf_full())
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007115 break;
7116
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007117 if (mask & XtIMXEvent)
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007118 {
7119 /* There is an event to process. */
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007120 XtAppNextEvent(app_context, &event);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007121#ifdef FEAT_CLIENTSERVER
7122 {
7123 XPropertyEvent *e = (XPropertyEvent *)&event;
7124
7125 if (e->type == PropertyNotify && e->window == commWindow
Bram Moolenaar071d4272004-06-13 20:20:40 +00007126 && e->atom == commProperty && e->state == PropertyNewValue)
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007127 serverEventProc(xterm_dpy, &event, 0);
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007128 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007129#endif
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007130 XtDispatchEvent(&event);
7131 }
Bram Moolenaarb1fc2bf2015-03-20 16:26:54 +01007132 else
7133 {
7134 /* There is something else than an event to process. */
Bram Moolenaar93c88e02015-09-15 14:12:05 +02007135 XtAppProcessEvent(app_context, mask);
7136 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007137 }
7138}
7139
7140 int
7141clip_xterm_own_selection(cbd)
7142 VimClipboard *cbd;
7143{
7144 if (xterm_Shell != (Widget)0)
7145 return clip_x11_own_selection(xterm_Shell, cbd);
7146 return FAIL;
7147}
7148
7149 void
7150clip_xterm_lose_selection(cbd)
7151 VimClipboard *cbd;
7152{
7153 if (xterm_Shell != (Widget)0)
7154 clip_x11_lose_selection(xterm_Shell, cbd);
7155}
7156
7157 void
7158clip_xterm_request_selection(cbd)
7159 VimClipboard *cbd;
7160{
7161 if (xterm_Shell != (Widget)0)
7162 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
7163}
7164
7165 void
7166clip_xterm_set_selection(cbd)
7167 VimClipboard *cbd;
7168{
7169 clip_x11_set_selection(cbd);
7170}
7171#endif
7172
7173
7174#if defined(USE_XSMP) || defined(PROTO)
7175/*
7176 * Code for X Session Management Protocol.
7177 */
7178static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
7179static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
7180static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
7181static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
7182static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
7183
7184
7185# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7186static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
7187
7188/*
7189 * This is our chance to ask the user if they want to save,
7190 * or abort the logout
7191 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007192 static void
7193xsmp_handle_interaction(smc_conn, client_data)
7194 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007195 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007196{
7197 cmdmod_T save_cmdmod;
7198 int cancel_shutdown = False;
7199
7200 save_cmdmod = cmdmod;
7201 cmdmod.confirm = TRUE;
7202 if (check_changed_any(FALSE))
7203 /* Mustn't logout */
7204 cancel_shutdown = True;
7205 cmdmod = save_cmdmod;
7206 setcursor(); /* position cursor */
7207 out_flush();
7208
7209 /* Done interaction */
7210 SmcInteractDone(smc_conn, cancel_shutdown);
7211
7212 /* Finish off
7213 * Only end save-yourself here if we're not cancelling shutdown;
7214 * we'll get a cancelled callback later in which we'll end it.
7215 * Hopefully get around glitchy SMs (like GNOME-1)
7216 */
7217 if (!cancel_shutdown)
7218 {
7219 xsmp.save_yourself = False;
7220 SmcSaveYourselfDone(smc_conn, True);
7221 }
7222}
7223# endif
7224
7225/*
7226 * Callback that starts save-yourself.
7227 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007228 static void
7229xsmp_handle_save_yourself(smc_conn, client_data, save_type,
7230 shutdown, interact_style, fast)
7231 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007232 SmPointer client_data UNUSED;
7233 int save_type UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007234 Bool shutdown;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007235 int interact_style UNUSED;
7236 Bool fast UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007237{
7238 /* Handle already being in saveyourself */
7239 if (xsmp.save_yourself)
7240 SmcSaveYourselfDone(smc_conn, True);
7241 xsmp.save_yourself = True;
7242 xsmp.shutdown = shutdown;
7243
7244 /* First up, preserve all files */
7245 out_flush();
7246 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
7247
7248 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007249 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007250
7251# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
7252 /* Now see if we can ask about unsaved files */
7253 if (shutdown && !fast && gui.in_use)
7254 /* Need to interact with user, but need SM's permission */
7255 SmcInteractRequest(smc_conn, SmDialogError,
7256 xsmp_handle_interaction, client_data);
7257 else
7258# endif
7259 {
7260 /* Can stop the cycle here */
7261 SmcSaveYourselfDone(smc_conn, True);
7262 xsmp.save_yourself = False;
7263 }
7264}
7265
7266
7267/*
7268 * Callback to warn us of imminent death.
7269 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007270 static void
7271xsmp_die(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007272 SmcConn smc_conn UNUSED;
7273 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007274{
7275 xsmp_close();
7276
7277 /* quit quickly leaving swapfiles for modified buffers behind */
7278 getout_preserve_modified(0);
7279}
7280
7281
7282/*
7283 * Callback to tell us that save-yourself has completed.
7284 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007285 static void
7286xsmp_save_complete(smc_conn, client_data)
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007287 SmcConn smc_conn UNUSED;
7288 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007289{
7290 xsmp.save_yourself = False;
7291}
7292
7293
7294/*
7295 * Callback to tell us that an instigated shutdown was cancelled
7296 * (maybe even by us)
7297 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007298 static void
7299xsmp_shutdown_cancelled(smc_conn, client_data)
7300 SmcConn smc_conn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007301 SmPointer client_data UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007302{
7303 if (xsmp.save_yourself)
7304 SmcSaveYourselfDone(smc_conn, True);
7305 xsmp.save_yourself = False;
7306 xsmp.shutdown = False;
7307}
7308
7309
7310/*
7311 * Callback to tell us that a new ICE connection has been established.
7312 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00007313 static void
7314xsmp_ice_connection(iceConn, clientData, opening, watchData)
7315 IceConn iceConn;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007316 IcePointer clientData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007317 Bool opening;
Bram Moolenaar2c4278f2009-05-17 11:33:22 +00007318 IcePointer *watchData UNUSED;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007319{
7320 /* Intercept creation of ICE connection fd */
7321 if (opening)
7322 {
7323 xsmp_icefd = IceConnectionNumber(iceConn);
7324 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
7325 }
7326}
7327
7328
7329/* Handle any ICE processing that's required; return FAIL if SM lost */
7330 int
7331xsmp_handle_requests()
7332{
7333 Bool rep;
7334
7335 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
7336 == IceProcessMessagesIOError)
7337 {
7338 /* Lost ICE */
7339 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007340 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007341 xsmp_close();
7342 return FAIL;
7343 }
7344 else
7345 return OK;
7346}
7347
7348static int dummy;
7349
7350/* Set up X Session Management Protocol */
7351 void
7352xsmp_init(void)
7353{
7354 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00007355 SmcCallbacks smcallbacks;
7356#if 0
7357 SmPropValue smname;
7358 SmProp smnameprop;
7359 SmProp *smprops[1];
7360#endif
7361
7362 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007363 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007364
7365 xsmp.save_yourself = xsmp.shutdown = False;
7366
7367 /* Set up SM callbacks - must have all, even if they're not used */
7368 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
7369 smcallbacks.save_yourself.client_data = NULL;
7370 smcallbacks.die.callback = xsmp_die;
7371 smcallbacks.die.client_data = NULL;
7372 smcallbacks.save_complete.callback = xsmp_save_complete;
7373 smcallbacks.save_complete.client_data = NULL;
7374 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
7375 smcallbacks.shutdown_cancelled.client_data = NULL;
7376
7377 /* Set up a watch on ICE connection creations. The "dummy" argument is
7378 * apparently required for FreeBSD (we get a BUS error when using NULL). */
7379 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
7380 {
7381 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007382 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00007383 return;
7384 }
7385
7386 /* Create an SM connection */
7387 xsmp.smcconn = SmcOpenConnection(
7388 NULL,
7389 NULL,
7390 SmProtoMajor,
7391 SmProtoMinor,
7392 SmcSaveYourselfProcMask | SmcDieProcMask
7393 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
7394 &smcallbacks,
7395 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00007396 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00007397 sizeof(errorstring),
7398 errorstring);
7399 if (xsmp.smcconn == NULL)
7400 {
7401 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00007402
Bram Moolenaar071d4272004-06-13 20:20:40 +00007403 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00007404 {
7405 vim_snprintf(errorreport, sizeof(errorreport),
7406 _("XSMP SmcOpenConnection failed: %s"), errorstring);
7407 verb_msg((char_u *)errorreport);
7408 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00007409 return;
7410 }
7411 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
7412
7413#if 0
7414 /* ID ourselves */
7415 smname.value = "vim";
7416 smname.length = 3;
7417 smnameprop.name = "SmProgram";
7418 smnameprop.type = "SmARRAY8";
7419 smnameprop.num_vals = 1;
7420 smnameprop.vals = &smname;
7421
7422 smprops[0] = &smnameprop;
7423 SmcSetProperties(xsmp.smcconn, 1, smprops);
7424#endif
7425}
7426
7427
7428/* Shut down XSMP comms. */
7429 void
7430xsmp_close()
7431{
7432 if (xsmp_icefd != -1)
7433 {
7434 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaar5a221812008-11-12 12:08:45 +00007435 if (xsmp.clientid != NULL)
7436 free(xsmp.clientid);
Bram Moolenaare8208012008-06-20 09:59:25 +00007437 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00007438 xsmp_icefd = -1;
7439 }
7440}
7441#endif /* USE_XSMP */
7442
7443
7444#ifdef EBCDIC
7445/* Translate character to its CTRL- value */
7446char CtrlTable[] =
7447{
7448/* 00 - 5E */
7449 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7450 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7451 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7452 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7453 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7454 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7455/* ^ */ 0x1E,
7456/* - */ 0x1F,
7457/* 61 - 6C */
7458 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7459/* _ */ 0x1F,
7460/* 6E - 80 */
7461 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7462/* a */ 0x01,
7463/* b */ 0x02,
7464/* c */ 0x03,
7465/* d */ 0x37,
7466/* e */ 0x2D,
7467/* f */ 0x2E,
7468/* g */ 0x2F,
7469/* h */ 0x16,
7470/* i */ 0x05,
7471/* 8A - 90 */
7472 0, 0, 0, 0, 0, 0, 0,
7473/* j */ 0x15,
7474/* k */ 0x0B,
7475/* l */ 0x0C,
7476/* m */ 0x0D,
7477/* n */ 0x0E,
7478/* o */ 0x0F,
7479/* p */ 0x10,
7480/* q */ 0x11,
7481/* r */ 0x12,
7482/* 9A - A1 */
7483 0, 0, 0, 0, 0, 0, 0, 0,
7484/* s */ 0x13,
7485/* t */ 0x3C,
7486/* u */ 0x3D,
7487/* v */ 0x32,
7488/* w */ 0x26,
7489/* x */ 0x18,
7490/* y */ 0x19,
7491/* z */ 0x3F,
7492/* AA - AC */
7493 0, 0, 0,
7494/* [ */ 0x27,
7495/* AE - BC */
7496 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7497/* ] */ 0x1D,
7498/* BE - C0 */ 0, 0, 0,
7499/* A */ 0x01,
7500/* B */ 0x02,
7501/* C */ 0x03,
7502/* D */ 0x37,
7503/* E */ 0x2D,
7504/* F */ 0x2E,
7505/* G */ 0x2F,
7506/* H */ 0x16,
7507/* I */ 0x05,
7508/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
7509/* J */ 0x15,
7510/* K */ 0x0B,
7511/* L */ 0x0C,
7512/* M */ 0x0D,
7513/* N */ 0x0E,
7514/* O */ 0x0F,
7515/* P */ 0x10,
7516/* Q */ 0x11,
7517/* R */ 0x12,
7518/* DA - DF */ 0, 0, 0, 0, 0, 0,
7519/* \ */ 0x1C,
7520/* E1 */ 0,
7521/* S */ 0x13,
7522/* T */ 0x3C,
7523/* U */ 0x3D,
7524/* V */ 0x32,
7525/* W */ 0x26,
7526/* X */ 0x18,
7527/* Y */ 0x19,
7528/* Z */ 0x3F,
7529/* EA - FF*/ 0, 0, 0, 0, 0, 0,
7530 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7531};
7532
7533char MetaCharTable[]=
7534{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7535 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
7536 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
7537 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
7538 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
7539};
7540
7541
7542/* TODO: Use characters NOT numbers!!! */
7543char CtrlCharTable[]=
7544{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
7545 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
7546 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
7547 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
7548 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
7549};
7550
7551
7552#endif