blob: b9bab94785447cc346eebd1e8fcdb2478162e948 [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#ifdef HAVE_FCNTL_H
39# include <fcntl.h>
40#endif
41
42#include "os_unixx.h" /* unix includes for os_unix.c only */
43
44#ifdef USE_XSMP
45# include <X11/SM/SMlib.h>
46#endif
47
Bram Moolenaar588ebeb2008-05-07 17:09:24 +000048#ifdef HAVE_SELINUX
49# include <selinux/selinux.h>
50static int selinux_enabled = -1;
51#endif
52
Bram Moolenaar071d4272004-06-13 20:20:40 +000053/*
54 * Use this prototype for select, some include files have a wrong prototype
55 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000056#ifndef __TANDEM
57# undef select
58# ifdef __BEOS__
59# define select beos_select
60# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000061#endif
62
Bram Moolenaara2442432007-04-26 14:26:37 +000063#ifdef __CYGWIN__
64# ifndef WIN32
65# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() */
66# endif
67#endif
68
Bram Moolenaar071d4272004-06-13 20:20:40 +000069#if defined(HAVE_SELECT)
70extern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
71#endif
72
73#ifdef FEAT_MOUSE_GPM
74# include <gpm.h>
75/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
76 * I just copied relevant defines here. A cleaner solution would be to put gpm
77 * code into separate file and include there linux/keyboard.h
78 */
79/* #include <linux/keyboard.h> */
80# define KG_SHIFT 0
81# define KG_CTRL 2
82# define KG_ALT 3
83# define KG_ALTGR 1
84# define KG_SHIFTL 4
85# define KG_SHIFTR 5
86# define KG_CTRLL 6
87# define KG_CTRLR 7
88# define KG_CAPSSHIFT 8
89
90static void gpm_close __ARGS((void));
91static int gpm_open __ARGS((void));
92static int mch_gpm_process __ARGS((void));
93#endif
94
95/*
96 * end of autoconf section. To be extended...
97 */
98
99/* Are the following #ifdefs still required? And why? Is that for X11? */
100
101#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
102# ifdef SIGWINCH
103# undef SIGWINCH
104# endif
105# ifdef TIOCGWINSZ
106# undef TIOCGWINSZ
107# endif
108#endif
109
110#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
111# define SIGWINCH SIGWINDOW
112#endif
113
114#ifdef FEAT_X11
115# include <X11/Xlib.h>
116# include <X11/Xutil.h>
117# include <X11/Xatom.h>
118# ifdef FEAT_XCLIPBOARD
119# include <X11/Intrinsic.h>
120# include <X11/Shell.h>
121# include <X11/StringDefs.h>
122static Widget xterm_Shell = (Widget)0;
123static void xterm_update __ARGS((void));
124# endif
125
126# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
127Window x11_window = 0;
128# endif
129Display *x11_display = NULL;
130
131# ifdef FEAT_TITLE
132static int get_x11_windis __ARGS((void));
133static void set_x11_title __ARGS((char_u *));
134static void set_x11_icon __ARGS((char_u *));
135# endif
136#endif
137
138#ifdef FEAT_TITLE
139static int get_x11_title __ARGS((int));
140static int get_x11_icon __ARGS((int));
141
142static char_u *oldtitle = NULL;
143static int did_set_title = FALSE;
144static char_u *oldicon = NULL;
145static int did_set_icon = FALSE;
146#endif
147
148static void may_core_dump __ARGS((void));
149
150static int WaitForChar __ARGS((long));
151#if defined(__BEOS__)
152int RealWaitForChar __ARGS((int, long, int *));
153#else
154static int RealWaitForChar __ARGS((int, long, int *));
155#endif
156
157#ifdef FEAT_XCLIPBOARD
158static int do_xterm_trace __ARGS((void));
Bram Moolenaarcf851ce2005-06-16 21:52:47 +0000159# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160#endif
161
162static void handle_resize __ARGS((void));
163
164#if defined(SIGWINCH)
165static RETSIGTYPE sig_winch __ARGS(SIGPROTOARG);
166#endif
167#if defined(SIGINT)
168static RETSIGTYPE catch_sigint __ARGS(SIGPROTOARG);
169#endif
170#if defined(SIGPWR)
171static RETSIGTYPE catch_sigpwr __ARGS(SIGPROTOARG);
172#endif
173#if defined(SIGALRM) && defined(FEAT_X11) \
174 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
175# define SET_SIG_ALARM
176static RETSIGTYPE sig_alarm __ARGS(SIGPROTOARG);
177static int sig_alarm_called;
178#endif
179static RETSIGTYPE deathtrap __ARGS(SIGPROTOARG);
180
Bram Moolenaardf177f62005-02-22 08:39:57 +0000181static void catch_int_signal __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000182static void set_signals __ARGS((void));
183static void catch_signals __ARGS((RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)()));
184#ifndef __EMX__
185static int have_wildcard __ARGS((int, char_u **));
186static int have_dollars __ARGS((int, char_u **));
187#endif
188
Bram Moolenaar071d4272004-06-13 20:20:40 +0000189#ifndef __EMX__
190static int save_patterns __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file));
191#endif
192
193#ifndef SIG_ERR
194# define SIG_ERR ((RETSIGTYPE (*)())-1)
195#endif
196
197static int do_resize = FALSE;
198#ifndef __EMX__
199static char_u *extra_shell_arg = NULL;
200static int show_shell_mess = TRUE;
201#endif
202static int deadly_signal = 0; /* The signal we caught */
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000203static int in_mch_delay = FALSE; /* sleeping in mch_delay() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000204
205static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
206
207#ifdef USE_XSMP
208typedef struct
209{
210 SmcConn smcconn; /* The SM connection ID */
211 IceConn iceconn; /* The ICE connection ID */
212 Bool save_yourself; /* If we're in the middle of a save_yourself */
213 Bool shutdown; /* If we're in shutdown mode */
214} xsmp_config_T;
215
216static xsmp_config_T xsmp;
217#endif
218
219#ifdef SYS_SIGLIST_DECLARED
220/*
221 * I have seen
222 * extern char *_sys_siglist[NSIG];
223 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
224 * that describe the signals. That is nearly what we want here. But
225 * autoconf does only check for sys_siglist (without the underscore), I
226 * do not want to change everything today.... jw.
227 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.in
228 */
229#endif
230
231static struct signalinfo
232{
233 int sig; /* Signal number, eg. SIGSEGV etc */
234 char *name; /* Signal name (not char_u!). */
235 char deadly; /* Catch as a deadly signal? */
236} signal_info[] =
237{
238#ifdef SIGHUP
239 {SIGHUP, "HUP", TRUE},
240#endif
241#ifdef SIGQUIT
242 {SIGQUIT, "QUIT", TRUE},
243#endif
244#ifdef SIGILL
245 {SIGILL, "ILL", TRUE},
246#endif
247#ifdef SIGTRAP
248 {SIGTRAP, "TRAP", TRUE},
249#endif
250#ifdef SIGABRT
251 {SIGABRT, "ABRT", TRUE},
252#endif
253#ifdef SIGEMT
254 {SIGEMT, "EMT", TRUE},
255#endif
256#ifdef SIGFPE
257 {SIGFPE, "FPE", TRUE},
258#endif
259#ifdef SIGBUS
260 {SIGBUS, "BUS", TRUE},
261#endif
262#ifdef SIGSEGV
263 {SIGSEGV, "SEGV", TRUE},
264#endif
265#ifdef SIGSYS
266 {SIGSYS, "SYS", TRUE},
267#endif
268#ifdef SIGALRM
269 {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
270#endif
271#ifdef SIGTERM
272 {SIGTERM, "TERM", TRUE},
273#endif
274#ifdef SIGVTALRM
275 {SIGVTALRM, "VTALRM", TRUE},
276#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000277#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
278 /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
279 * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280 {SIGPROF, "PROF", TRUE},
281#endif
282#ifdef SIGXCPU
283 {SIGXCPU, "XCPU", TRUE},
284#endif
285#ifdef SIGXFSZ
286 {SIGXFSZ, "XFSZ", TRUE},
287#endif
288#ifdef SIGUSR1
289 {SIGUSR1, "USR1", TRUE},
290#endif
291#ifdef SIGUSR2
292 {SIGUSR2, "USR2", TRUE},
293#endif
294#ifdef SIGINT
295 {SIGINT, "INT", FALSE},
296#endif
297#ifdef SIGWINCH
298 {SIGWINCH, "WINCH", FALSE},
299#endif
300#ifdef SIGTSTP
301 {SIGTSTP, "TSTP", FALSE},
302#endif
303#ifdef SIGPIPE
304 {SIGPIPE, "PIPE", FALSE},
305#endif
306 {-1, "Unknown!", FALSE}
307};
308
309 void
310mch_write(s, len)
311 char_u *s;
312 int len;
313{
314 write(1, (char *)s, len);
315 if (p_wd) /* Unix is too fast, slow down a bit more */
316 RealWaitForChar(read_cmd_fd, p_wd, NULL);
317}
318
319/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000320 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000321 * Get a characters from the keyboard.
322 * Return the number of characters that are available.
323 * If wtime == 0 do not wait for characters.
324 * If wtime == n wait a short time for characters.
325 * If wtime == -1 wait forever for characters.
326 */
327 int
328mch_inchar(buf, maxlen, wtime, tb_change_cnt)
329 char_u *buf;
330 int maxlen;
331 long wtime; /* don't use "time", MIPS cannot handle it */
332 int tb_change_cnt;
333{
334 int len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000335
336 /* Check if window changed size while we were busy, perhaps the ":set
337 * columns=99" command was used. */
338 while (do_resize)
339 handle_resize();
340
341 if (wtime >= 0)
342 {
343 while (WaitForChar(wtime) == 0) /* no character available */
344 {
345 if (!do_resize) /* return if not interrupted by resize */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000346 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347 handle_resize();
348 }
349 }
350 else /* wtime == -1 */
351 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352 /*
353 * If there is no character available within 'updatetime' seconds
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000354 * flush all the swap files to disk.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000355 * Also done when interrupted by SIGWINCH.
356 */
357 if (WaitForChar(p_ut) == 0)
358 {
359#ifdef FEAT_AUTOCMD
Bram Moolenaard35f9712005-12-18 22:02:33 +0000360 if (trigger_cursorhold() && maxlen >= 3
361 && !typebuf_changed(tb_change_cnt))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000362 {
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000363 buf[0] = K_SPECIAL;
364 buf[1] = KS_EXTRA;
365 buf[2] = (int)KE_CURSORHOLD;
366 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000367 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368#endif
Bram Moolenaard4098f52005-06-27 22:37:13 +0000369 before_blocking();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000370 }
371 }
372
373 for (;;) /* repeat until we got a character */
374 {
375 while (do_resize) /* window changed size */
376 handle_resize();
377 /*
378 * we want to be interrupted by the winch signal
379 */
380 WaitForChar(-1L);
381 if (do_resize) /* interrupted by SIGWINCH signal */
382 continue;
383
384 /* If input was put directly in typeahead buffer bail out here. */
385 if (typebuf_changed(tb_change_cnt))
386 return 0;
387
388 /*
389 * For some terminals we only get one character at a time.
390 * We want the get all available characters, so we could keep on
391 * trying until none is available
392 * For some other terminals this is quite slow, that's why we don't do
393 * it.
394 */
395 len = read_from_input_buf(buf, (long)maxlen);
396 if (len > 0)
397 {
398#ifdef OS2
399 int i;
400
401 for (i = 0; i < len; i++)
402 if (buf[i] == 0)
403 buf[i] = K_NUL;
404#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000405 return len;
406 }
407 }
408}
409
410 static void
411handle_resize()
412{
413 do_resize = FALSE;
414 shell_resized();
415}
416
417/*
418 * return non-zero if a character is available
419 */
420 int
421mch_char_avail()
422{
423 return WaitForChar(0L);
424}
425
426#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
427# ifdef HAVE_SYS_RESOURCE_H
428# include <sys/resource.h>
429# endif
430# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
431# include <sys/sysctl.h>
432# endif
433# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
434# include <sys/sysinfo.h>
435# endif
436
437/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000438 * Return total amount of memory available in Kbyte.
439 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000440 */
441/* ARGSUSED */
442 long_u
443mch_total_mem(special)
444 int special;
445{
446# ifdef __EMX__
Bram Moolenaar914572a2007-05-01 11:37:47 +0000447 return ulimit(3, 0L) >> 10; /* always 32MB? */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000448# else
449 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000450 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000451
452# ifdef HAVE_SYSCTL
453 int mib[2], physmem;
454 size_t len;
455
456 /* BSD way of getting the amount of RAM available. */
457 mib[0] = CTL_HW;
458 mib[1] = HW_USERMEM;
459 len = sizeof(physmem);
460 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
461 mem = (long_u)physmem;
462# endif
463
464# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
465 if (mem == 0)
466 {
467 struct sysinfo sinfo;
468
469 /* Linux way of getting amount of RAM available */
470 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000471 {
472# ifdef HAVE_SYSINFO_MEM_UNIT
473 /* avoid overflow as much as possible */
474 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
475 {
476 sinfo.mem_unit = sinfo.mem_unit >> 1;
477 --shiftright;
478 }
479 mem = sinfo.totalram * sinfo.mem_unit;
480# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000481 mem = sinfo.totalram;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000482# endif
483 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000484 }
485# endif
486
487# ifdef HAVE_SYSCONF
488 if (mem == 0)
489 {
490 long pagesize, pagecount;
491
492 /* Solaris way of getting amount of RAM available */
493 pagesize = sysconf(_SC_PAGESIZE);
494 pagecount = sysconf(_SC_PHYS_PAGES);
495 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000496 {
497 /* avoid overflow as much as possible */
498 while (shiftright > 0 && (pagesize & 1) == 0)
499 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000500 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000501 --shiftright;
502 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000504 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000505 }
506# endif
507
508 /* Return the minimum of the physical memory and the user limit, because
509 * using more than the user limit may cause Vim to be terminated. */
510# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
511 {
512 struct rlimit rlp;
513
514 if (getrlimit(RLIMIT_DATA, &rlp) == 0
515 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
516# ifdef RLIM_INFINITY
517 && rlp.rlim_cur != RLIM_INFINITY
518# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000519 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000520 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000521 {
522 mem = (long_u)rlp.rlim_cur;
523 shiftright = 10;
524 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000525 }
526# endif
527
528 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000529 return mem >> shiftright;
530 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000531# endif
532}
533#endif
534
535 void
536mch_delay(msec, ignoreinput)
537 long msec;
538 int ignoreinput;
539{
540 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000541#ifdef FEAT_MZSCHEME
542 long total = msec; /* remember original value */
543#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544
545 if (ignoreinput)
546 {
547 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000548 * here. But we don't want QUIT to kill us (CTRL-\ used in a
549 * shell may produce SIGQUIT). */
550 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551 old_tmode = curr_tmode;
552 if (curr_tmode == TMODE_RAW)
553 settmode(TMODE_SLEEP);
554
555 /*
556 * Everybody sleeps in a different way...
557 * Prefer nanosleep(), some versions of usleep() can only sleep up to
558 * one second.
559 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000560#ifdef FEAT_MZSCHEME
561 do
562 {
563 /* if total is large enough, wait by portions in p_mzq */
564 if (total > p_mzq)
565 msec = p_mzq;
566 else
567 msec = total;
568 total -= msec;
569#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000570#ifdef HAVE_NANOSLEEP
571 {
572 struct timespec ts;
573
574 ts.tv_sec = msec / 1000;
575 ts.tv_nsec = (msec % 1000) * 1000000;
576 (void)nanosleep(&ts, NULL);
577 }
578#else
579# ifdef HAVE_USLEEP
580 while (msec >= 1000)
581 {
582 usleep((unsigned int)(999 * 1000));
583 msec -= 999;
584 }
585 usleep((unsigned int)(msec * 1000));
586# else
587# ifndef HAVE_SELECT
588 poll(NULL, 0, (int)msec);
589# else
590# ifdef __EMX__
591 _sleep2(msec);
592# else
593 {
594 struct timeval tv;
595
596 tv.tv_sec = msec / 1000;
597 tv.tv_usec = (msec % 1000) * 1000;
598 /*
599 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
600 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
601 */
602 select(0, NULL, NULL, NULL, &tv);
603 }
604# endif /* __EMX__ */
605# endif /* HAVE_SELECT */
606# endif /* HAVE_NANOSLEEP */
607#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000608#ifdef FEAT_MZSCHEME
609 }
610 while (total > 0);
611#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000612
613 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000614 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 }
616 else
617 WaitForChar(msec);
618}
619
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000620#if 0 /* disabled, no longer needed now that regmatch() is not recursive */
621# if defined(HAVE_GETRLIMIT)
622# define HAVE_STACK_LIMIT
623# endif
624#endif
625
626#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000627 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
628# define HAVE_CHECK_STACK_GROWTH
629/*
630 * Support for checking for an almost-out-of-stack-space situation.
631 */
632
633/*
634 * Return a pointer to an item on the stack. Used to find out if the stack
635 * grows up or down.
636 */
637static void check_stack_growth __ARGS((char *p));
638static int stack_grows_downwards;
639
640/*
641 * Find out if the stack grows upwards or downwards.
642 * "p" points to a variable on the stack of the caller.
643 */
644 static void
645check_stack_growth(p)
646 char *p;
647{
648 int i;
649
650 stack_grows_downwards = (p > (char *)&i);
651}
652#endif
653
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000654#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000655static char *stack_limit = NULL;
656
657#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
658# include <pthread.h>
659# include <pthread_np.h>
660#endif
661
662/*
663 * Find out until how var the stack can grow without getting into trouble.
664 * Called when starting up and when switching to the signal stack in
665 * deathtrap().
666 */
667 static void
668get_stack_limit()
669{
670 struct rlimit rlp;
671 int i;
672 long lim;
673
674 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
675 * limit doesn't fit in a long (rlim_cur might be "long long"). */
676 if (getrlimit(RLIMIT_STACK, &rlp) == 0
677 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
678# ifdef RLIM_INFINITY
679 && rlp.rlim_cur != RLIM_INFINITY
680# endif
681 )
682 {
683 lim = (long)rlp.rlim_cur;
684#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
685 {
686 pthread_attr_t attr;
687 size_t size;
688
689 /* On FreeBSD the initial thread always has a fixed stack size, no
690 * matter what the limits are set to. Normally it's 1 Mbyte. */
691 pthread_attr_init(&attr);
692 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
693 {
694 pthread_attr_getstacksize(&attr, &size);
695 if (lim > (long)size)
696 lim = (long)size;
697 }
698 pthread_attr_destroy(&attr);
699 }
700#endif
701 if (stack_grows_downwards)
702 {
703 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
704 if (stack_limit >= (char *)&i)
705 /* overflow, set to 1/16 of current stack position */
706 stack_limit = (char *)((long)&i / 16L);
707 }
708 else
709 {
710 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
711 if (stack_limit <= (char *)&i)
712 stack_limit = NULL; /* overflow */
713 }
714 }
715}
716
717/*
718 * Return FAIL when running out of stack space.
719 * "p" must point to any variable local to the caller that's on the stack.
720 */
721 int
722mch_stackcheck(p)
723 char *p;
724{
725 if (stack_limit != NULL)
726 {
727 if (stack_grows_downwards)
728 {
729 if (p < stack_limit)
730 return FAIL;
731 }
732 else if (p > stack_limit)
733 return FAIL;
734 }
735 return OK;
736}
737#endif
738
739#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
740/*
741 * Support for using the signal stack.
742 * This helps when we run out of stack space, which causes a SIGSEGV. The
743 * signal handler then must run on another stack, since the normal stack is
744 * completely full.
745 */
746
747#ifndef SIGSTKSZ
748# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
749#endif
750
751# ifdef HAVE_SIGALTSTACK
752static stack_t sigstk; /* for sigaltstack() */
753# else
754static struct sigstack sigstk; /* for sigstack() */
755# endif
756
757static void init_signal_stack __ARGS((void));
758static char *signal_stack;
759
760 static void
761init_signal_stack()
762{
763 if (signal_stack != NULL)
764 {
765# ifdef HAVE_SIGALTSTACK
Bram Moolenaar1a3d0862007-08-30 09:47:38 +0000766# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
767 || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
769 * "struct sigaltstack" needs to be declared. */
770 extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
771# endif
772
773# ifdef HAVE_SS_BASE
774 sigstk.ss_base = signal_stack;
775# else
776 sigstk.ss_sp = signal_stack;
777# endif
778 sigstk.ss_size = SIGSTKSZ;
779 sigstk.ss_flags = 0;
780 (void)sigaltstack(&sigstk, NULL);
781# else
782 sigstk.ss_sp = signal_stack;
783 if (stack_grows_downwards)
784 sigstk.ss_sp += SIGSTKSZ - 1;
785 sigstk.ss_onstack = 0;
786 (void)sigstack(&sigstk, NULL);
787# endif
788 }
789}
790#endif
791
792/*
793 * We need correct potatotypes for a signal function, otherwise mean compilers
794 * will barf when the second argument to signal() is ``wrong''.
795 * Let me try it with a few tricky defines from my own osdef.h (jw).
796 */
797#if defined(SIGWINCH)
798/* ARGSUSED */
799 static RETSIGTYPE
800sig_winch SIGDEFARG(sigarg)
801{
802 /* this is not required on all systems, but it doesn't hurt anybody */
803 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
804 do_resize = TRUE;
805 SIGRETURN;
806}
807#endif
808
809#if defined(SIGINT)
810/* ARGSUSED */
811 static RETSIGTYPE
812catch_sigint SIGDEFARG(sigarg)
813{
814 /* this is not required on all systems, but it doesn't hurt anybody */
815 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
816 got_int = TRUE;
817 SIGRETURN;
818}
819#endif
820
821#if defined(SIGPWR)
822/* ARGSUSED */
823 static RETSIGTYPE
824catch_sigpwr SIGDEFARG(sigarg)
825{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000826 /* this is not required on all systems, but it doesn't hurt anybody */
827 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000828 /*
829 * I'm not sure we get the SIGPWR signal when the system is really going
830 * down or when the batteries are almost empty. Just preserve the swap
831 * files and don't exit, that can't do any harm.
832 */
833 ml_sync_all(FALSE, FALSE);
834 SIGRETURN;
835}
836#endif
837
838#ifdef SET_SIG_ALARM
839/*
840 * signal function for alarm().
841 */
842/* ARGSUSED */
843 static RETSIGTYPE
844sig_alarm SIGDEFARG(sigarg)
845{
846 /* doesn't do anything, just to break a system call */
847 sig_alarm_called = TRUE;
848 SIGRETURN;
849}
850#endif
851
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000852#if (defined(HAVE_SETJMP_H) \
853 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
854 || defined(FEAT_LIBCALL))) \
855 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856/*
857 * A simplistic version of setjmp() that only allows one level of using.
858 * Don't call twice before calling mch_endjmp()!.
859 * Usage:
860 * mch_startjmp();
861 * if (SETJMP(lc_jump_env) != 0)
862 * {
863 * mch_didjmp();
864 * EMSG("crash!");
865 * }
866 * else
867 * {
868 * do_the_work;
869 * mch_endjmp();
870 * }
871 * Note: Can't move SETJMP() here, because a function calling setjmp() must
872 * not return before the saved environment is used.
873 * Returns OK for normal return, FAIL when the protected code caused a
874 * problem and LONGJMP() was used.
875 */
876 void
877mch_startjmp()
878{
879#ifdef SIGHASARG
880 lc_signal = 0;
881#endif
882 lc_active = TRUE;
883}
884
885 void
886mch_endjmp()
887{
888 lc_active = FALSE;
889}
890
891 void
892mch_didjmp()
893{
894# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
895 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
896 * otherwise catching the signal only works once. */
897 init_signal_stack();
898# endif
899}
900#endif
901
902/*
903 * This function handles deadly signals.
904 * It tries to preserve any swap file and exit properly.
905 * (partly from Elvis).
906 */
907 static RETSIGTYPE
908deathtrap SIGDEFARG(sigarg)
909{
910 static int entered = 0; /* count the number of times we got here.
911 Note: when memory has been corrupted
912 this may get an arbitrary value! */
913#ifdef SIGHASARG
914 int i;
915#endif
916
917#if defined(HAVE_SETJMP_H)
918 /*
919 * Catch a crash in protected code.
920 * Restores the environment saved in lc_jump_env, which looks like
921 * SETJMP() returns 1.
922 */
923 if (lc_active)
924 {
925# if defined(SIGHASARG)
926 lc_signal = sigarg;
927# endif
928 lc_active = FALSE; /* don't jump again */
929 LONGJMP(lc_jump_env, 1);
930 /* NOTREACHED */
931 }
932#endif
933
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000934#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000935# ifdef SIGQUIT
936 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
937 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
938 * pressing CTRL-\, but we don't want Vim to exit then. */
939 if (in_mch_delay && sigarg == SIGQUIT)
940 SIGRETURN;
941# endif
942
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000943 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
944 * here. This avoids that a non-reentrant function is interrupted, e.g.,
945 * free(). Calling free() again may then cause a crash. */
946 if (entered == 0
947 && (0
948# ifdef SIGHUP
949 || sigarg == SIGHUP
950# endif
951# ifdef SIGQUIT
952 || sigarg == SIGQUIT
953# endif
954# ifdef SIGTERM
955 || sigarg == SIGTERM
956# endif
957# ifdef SIGPWR
958 || sigarg == SIGPWR
959# endif
960# ifdef SIGUSR1
961 || sigarg == SIGUSR1
962# endif
963# ifdef SIGUSR2
964 || sigarg == SIGUSR2
965# endif
966 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +0000967 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000968 SIGRETURN;
969#endif
970
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971 /* Remember how often we have been called. */
972 ++entered;
973
974#ifdef FEAT_EVAL
975 /* Set the v:dying variable. */
976 set_vim_var_nr(VV_DYING, (long)entered);
977#endif
978
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000979#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +0000980 /* Since we are now using the signal stack, need to reset the stack
981 * limit. Otherwise using a regexp will fail. */
982 get_stack_limit();
983#endif
984
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +0000985#if 0
986 /* This is for opening gdb the moment Vim crashes.
987 * You need to manually adjust the file name and Vim executable name.
988 * Suggested by SungHyun Nam. */
989 {
990# define VI_GDB_FILE "/tmp/vimgdb"
991# define VIM_NAME "/usr/bin/vim"
992 FILE *fp = fopen(VI_GDB_FILE, "w");
993 if (fp)
994 {
995 fprintf(fp,
996 "file %s\n"
997 "attach %d\n"
998 "set height 1000\n"
999 "bt full\n"
1000 , VIM_NAME, getpid());
1001 fclose(fp);
1002 system("xterm -e gdb -x "VI_GDB_FILE);
1003 unlink(VI_GDB_FILE);
1004 }
1005 }
1006#endif
1007
Bram Moolenaar071d4272004-06-13 20:20:40 +00001008#ifdef SIGHASARG
1009 /* try to find the name of this signal */
1010 for (i = 0; signal_info[i].sig != -1; i++)
1011 if (sigarg == signal_info[i].sig)
1012 break;
1013 deadly_signal = sigarg;
1014#endif
1015
1016 full_screen = FALSE; /* don't write message to the GUI, it might be
1017 * part of the problem... */
1018 /*
1019 * If something goes wrong after entering here, we may get here again.
1020 * When this happens, give a message and try to exit nicely (resetting the
1021 * terminal mode, etc.)
1022 * When this happens twice, just exit, don't even try to give a message,
1023 * stack may be corrupt or something weird.
1024 * When this still happens again (or memory was corrupted in such a way
1025 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1026 */
1027 if (entered >= 3)
1028 {
1029 reset_signals(); /* don't catch any signals anymore */
1030 may_core_dump();
1031 if (entered >= 4)
1032 _exit(8);
1033 exit(7);
1034 }
1035 if (entered == 2)
1036 {
1037 OUT_STR(_("Vim: Double signal, exiting\n"));
1038 out_flush();
1039 getout(1);
1040 }
1041
1042#ifdef SIGHASARG
1043 sprintf((char *)IObuff, _("Vim: Caught deadly signal %s\n"),
1044 signal_info[i].name);
1045#else
1046 sprintf((char *)IObuff, _("Vim: Caught deadly signal\n"));
1047#endif
1048 preserve_exit(); /* preserve files and exit */
1049
Bram Moolenaar009b2592004-10-24 19:18:58 +00001050#ifdef NBDEBUG
1051 reset_signals();
1052 may_core_dump();
1053 abort();
1054#endif
1055
Bram Moolenaar071d4272004-06-13 20:20:40 +00001056 SIGRETURN;
1057}
1058
1059#ifdef _REENTRANT
1060/*
1061 * On Solaris with multi-threading, suspending might not work immediately.
1062 * Catch the SIGCONT signal, which will be used as an indication whether the
1063 * suspending has been done or not.
1064 */
1065static int sigcont_received;
1066static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1067
1068/*
1069 * signal handler for SIGCONT
1070 */
1071/* ARGSUSED */
1072 static RETSIGTYPE
1073sigcont_handler SIGDEFARG(sigarg)
1074{
1075 sigcont_received = TRUE;
1076 SIGRETURN;
1077}
1078#endif
1079
1080/*
1081 * If the machine has job control, use it to suspend the program,
1082 * otherwise fake it by starting a new shell.
1083 */
1084 void
1085mch_suspend()
1086{
1087 /* BeOS does have SIGTSTP, but it doesn't work. */
1088#if defined(SIGTSTP) && !defined(__BEOS__)
1089 out_flush(); /* needed to make cursor visible on some systems */
1090 settmode(TMODE_COOK);
1091 out_flush(); /* needed to disable mouse on some systems */
1092
1093# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1094 /* Since we are going to sleep, we can't respond to requests for the X
1095 * selections. Lose them, otherwise other applications will hang. But
1096 * first copy the text to cut buffer 0. */
1097 if (clip_star.owned || clip_plus.owned)
1098 {
1099 x11_export_final_selection();
1100 if (clip_star.owned)
1101 clip_lose_selection(&clip_star);
1102 if (clip_plus.owned)
1103 clip_lose_selection(&clip_plus);
1104 if (x11_display != NULL)
1105 XFlush(x11_display);
1106 }
1107# endif
1108
1109# ifdef _REENTRANT
1110 sigcont_received = FALSE;
1111# endif
1112 kill(0, SIGTSTP); /* send ourselves a STOP signal */
1113# ifdef _REENTRANT
1114 /* When we didn't suspend immediately in the kill(), do it now. Happens
1115 * on multi-threaded Solaris. */
1116 if (!sigcont_received)
1117 pause();
1118# endif
1119
1120# ifdef FEAT_TITLE
1121 /*
1122 * Set oldtitle to NULL, so the current title is obtained again.
1123 */
1124 vim_free(oldtitle);
1125 oldtitle = NULL;
1126# endif
1127 settmode(TMODE_RAW);
1128 need_check_timestamps = TRUE;
1129 did_check_timestamps = FALSE;
1130#else
1131 suspend_shell();
1132#endif
1133}
1134
1135 void
1136mch_init()
1137{
1138 Columns = 80;
1139 Rows = 24;
1140
1141 out_flush();
1142 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001143
Bram Moolenaar56718732006-03-15 22:53:57 +00001144#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001145 mac_conv_init();
1146#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001147}
1148
1149 static void
1150set_signals()
1151{
1152#if defined(SIGWINCH)
1153 /*
1154 * WINDOW CHANGE signal is handled with sig_winch().
1155 */
1156 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1157#endif
1158
1159 /*
1160 * We want the STOP signal to work, to make mch_suspend() work.
1161 * For "rvim" the STOP signal is ignored.
1162 */
1163#ifdef SIGTSTP
1164 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1165#endif
1166#ifdef _REENTRANT
1167 signal(SIGCONT, sigcont_handler);
1168#endif
1169
1170 /*
1171 * We want to ignore breaking of PIPEs.
1172 */
1173#ifdef SIGPIPE
1174 signal(SIGPIPE, SIG_IGN);
1175#endif
1176
Bram Moolenaar071d4272004-06-13 20:20:40 +00001177#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001178 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001179#endif
1180
1181 /*
1182 * Ignore alarm signals (Perl's alarm() generates it).
1183 */
1184#ifdef SIGALRM
1185 signal(SIGALRM, SIG_IGN);
1186#endif
1187
1188 /*
1189 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1190 * work will be lost.
1191 */
1192#ifdef SIGPWR
1193 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1194#endif
1195
1196 /*
1197 * Arrange for other signals to gracefully shutdown Vim.
1198 */
1199 catch_signals(deathtrap, SIG_ERR);
1200
1201#if defined(FEAT_GUI) && defined(SIGHUP)
1202 /*
1203 * When the GUI is running, ignore the hangup signal.
1204 */
1205 if (gui.in_use)
1206 signal(SIGHUP, SIG_IGN);
1207#endif
1208}
1209
Bram Moolenaardf177f62005-02-22 08:39:57 +00001210#if defined(SIGINT) || defined(PROTO)
1211/*
1212 * Catch CTRL-C (only works while in Cooked mode).
1213 */
1214 static void
1215catch_int_signal()
1216{
1217 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1218}
1219#endif
1220
Bram Moolenaar071d4272004-06-13 20:20:40 +00001221 void
1222reset_signals()
1223{
1224 catch_signals(SIG_DFL, SIG_DFL);
1225#ifdef _REENTRANT
1226 /* SIGCONT isn't in the list, because its default action is ignore */
1227 signal(SIGCONT, SIG_DFL);
1228#endif
1229}
1230
1231 static void
1232catch_signals(func_deadly, func_other)
1233 RETSIGTYPE (*func_deadly)();
1234 RETSIGTYPE (*func_other)();
1235{
1236 int i;
1237
1238 for (i = 0; signal_info[i].sig != -1; i++)
1239 if (signal_info[i].deadly)
1240 {
1241#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1242 struct sigaction sa;
1243
1244 /* Setup to use the alternate stack for the signal function. */
1245 sa.sa_handler = func_deadly;
1246 sigemptyset(&sa.sa_mask);
1247# if defined(__linux__) && defined(_REENTRANT)
1248 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1249 * thread handling in combination with using the alternate stack:
1250 * pthread library functions try to use the stack pointer to
1251 * identify the current thread, causing a SEGV signal, which
1252 * recursively calls deathtrap() and hangs. */
1253 sa.sa_flags = 0;
1254# else
1255 sa.sa_flags = SA_ONSTACK;
1256# endif
1257 sigaction(signal_info[i].sig, &sa, NULL);
1258#else
1259# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1260 struct sigvec sv;
1261
1262 /* Setup to use the alternate stack for the signal function. */
1263 sv.sv_handler = func_deadly;
1264 sv.sv_mask = 0;
1265 sv.sv_flags = SV_ONSTACK;
1266 sigvec(signal_info[i].sig, &sv, NULL);
1267# else
1268 signal(signal_info[i].sig, func_deadly);
1269# endif
1270#endif
1271 }
1272 else if (func_other != SIG_ERR)
1273 signal(signal_info[i].sig, func_other);
1274}
1275
1276/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001277 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001278 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1279 * return TRUE
1280 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1281 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
1282 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001283 * Returns TRUE when Vim should exit.
1284 */
1285 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001286vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001287 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001288{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001289 static int got_signal = 0;
1290 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001291
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001292 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001293 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001294 case SIGNAL_BLOCK: blocked = TRUE;
1295 break;
1296
1297 case SIGNAL_UNBLOCK: blocked = FALSE;
1298 if (got_signal != 0)
1299 {
1300 kill(getpid(), got_signal);
1301 got_signal = 0;
1302 }
1303 break;
1304
1305 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001306 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001307 got_signal = sig;
1308#ifdef SIGPWR
1309 if (sig != SIGPWR)
1310#endif
1311 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001312 break;
1313 }
1314 return FALSE;
1315}
1316
1317/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001318 * Check_win checks whether we have an interactive stdout.
1319 */
1320/* ARGSUSED */
1321 int
1322mch_check_win(argc, argv)
1323 int argc;
1324 char **argv;
1325{
1326#ifdef OS2
1327 /*
1328 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1329 * name, mostly it's just "vim" and found in the path, which is unusable.
1330 */
1331 if (mch_isFullName(argv[0]))
1332 exe_name = vim_strsave((char_u *)argv[0]);
1333#endif
1334 if (isatty(1))
1335 return OK;
1336 return FAIL;
1337}
1338
1339/*
1340 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1341 */
1342 int
1343mch_input_isatty()
1344{
1345 if (isatty(read_cmd_fd))
1346 return TRUE;
1347 return FALSE;
1348}
1349
1350#ifdef FEAT_X11
1351
1352# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1353 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1354
1355static void xopen_message __ARGS((struct timeval *tvp));
1356
1357/*
1358 * Give a message about the elapsed time for opening the X window.
1359 */
1360 static void
1361xopen_message(tvp)
1362 struct timeval *tvp; /* must contain start time */
1363{
1364 struct timeval end_tv;
1365
1366 /* Compute elapsed time. */
1367 gettimeofday(&end_tv, NULL);
1368 smsg((char_u *)_("Opening the X display took %ld msec"),
1369 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001370 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001371}
1372# endif
1373#endif
1374
1375#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1376/*
1377 * A few functions shared by X11 title and clipboard code.
1378 */
1379static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1380static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1381static int x_connect_to_server __ARGS((void));
1382static int test_x11_window __ARGS((Display *dpy));
1383
1384static int got_x_error = FALSE;
1385
1386/*
1387 * X Error handler, otherwise X just exits! (very rude) -- webb
1388 */
1389 static int
1390x_error_handler(dpy, error_event)
1391 Display *dpy;
1392 XErrorEvent *error_event;
1393{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001394 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001395 STRCAT(IObuff, _("\nVim: Got X error\n"));
1396
1397 /* We cannot print a message and continue, because no X calls are allowed
1398 * here (causes my system to hang). Silently continuing might be an
1399 * alternative... */
1400 preserve_exit(); /* preserve files and exit */
1401
1402 return 0; /* NOTREACHED */
1403}
1404
1405/*
1406 * Another X Error handler, just used to check for errors.
1407 */
1408/* ARGSUSED */
1409 static int
1410x_error_check(dpy, error_event)
1411 Display *dpy;
1412 XErrorEvent *error_event;
1413{
1414 got_x_error = TRUE;
1415 return 0;
1416}
1417
1418#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1419# if defined(HAVE_SETJMP_H)
1420/*
1421 * An X IO Error handler, used to catch error while opening the display.
1422 */
1423static int x_IOerror_check __ARGS((Display *dpy));
1424
1425/* ARGSUSED */
1426 static int
1427x_IOerror_check(dpy)
1428 Display *dpy;
1429{
1430 /* This function should not return, it causes exit(). Longjump instead. */
1431 LONGJMP(lc_jump_env, 1);
1432 /*NOTREACHED*/
1433 return 0;
1434}
1435# endif
1436
1437/*
1438 * An X IO Error handler, used to catch terminal errors.
1439 */
1440static int x_IOerror_handler __ARGS((Display *dpy));
1441
1442/* ARGSUSED */
1443 static int
1444x_IOerror_handler(dpy)
1445 Display *dpy;
1446{
1447 xterm_dpy = NULL;
1448 x11_window = 0;
1449 x11_display = NULL;
1450 xterm_Shell = (Widget)0;
1451
1452 /* This function should not return, it causes exit(). Longjump instead. */
1453 LONGJMP(x_jump_env, 1);
1454 /*NOTREACHED*/
1455 return 0;
1456}
1457#endif
1458
1459/*
1460 * Return TRUE when connection to the X server is desired.
1461 */
1462 static int
1463x_connect_to_server()
1464{
1465 regmatch_T regmatch;
1466
1467#if defined(FEAT_CLIENTSERVER)
1468 if (x_force_connect)
1469 return TRUE;
1470#endif
1471 if (x_no_connect)
1472 return FALSE;
1473
1474 /* Check for a match with "exclude:" from 'clipboard'. */
1475 if (clip_exclude_prog != NULL)
1476 {
1477 regmatch.rm_ic = FALSE; /* Don't ignore case */
1478 regmatch.regprog = clip_exclude_prog;
1479 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1480 return FALSE;
1481 }
1482 return TRUE;
1483}
1484
1485/*
1486 * Test if "dpy" and x11_window are valid by getting the window title.
1487 * I don't actually want it yet, so there may be a simpler call to use, but
1488 * this will cause the error handler x_error_check() to be called if anything
1489 * is wrong, such as the window pointer being invalid (as can happen when the
1490 * user changes his DISPLAY, but not his WINDOWID) -- webb
1491 */
1492 static int
1493test_x11_window(dpy)
1494 Display *dpy;
1495{
1496 int (*old_handler)();
1497 XTextProperty text_prop;
1498
1499 old_handler = XSetErrorHandler(x_error_check);
1500 got_x_error = FALSE;
1501 if (XGetWMName(dpy, x11_window, &text_prop))
1502 XFree((void *)text_prop.value);
1503 XSync(dpy, False);
1504 (void)XSetErrorHandler(old_handler);
1505
1506 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001507 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001508
1509 return (got_x_error ? FAIL : OK);
1510}
1511#endif
1512
1513#ifdef FEAT_TITLE
1514
1515#ifdef FEAT_X11
1516
1517static int get_x11_thing __ARGS((int get_title, int test_only));
1518
1519/*
1520 * try to get x11 window and display
1521 *
1522 * return FAIL for failure, OK otherwise
1523 */
1524 static int
1525get_x11_windis()
1526{
1527 char *winid;
1528 static int result = -1;
1529#define XD_NONE 0 /* x11_display not set here */
1530#define XD_HERE 1 /* x11_display opened here */
1531#define XD_GUI 2 /* x11_display used from gui.dpy */
1532#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1533 static int x11_display_from = XD_NONE;
1534 static int did_set_error_handler = FALSE;
1535
1536 if (!did_set_error_handler)
1537 {
1538 /* X just exits if it finds an error otherwise! */
1539 (void)XSetErrorHandler(x_error_handler);
1540 did_set_error_handler = TRUE;
1541 }
1542
Bram Moolenaar9372a112005-12-06 19:59:18 +00001543#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001544 if (gui.in_use)
1545 {
1546 /*
1547 * If the X11 display was opened here before, for the window where Vim
1548 * was started, close that one now to avoid a memory leak.
1549 */
1550 if (x11_display_from == XD_HERE && x11_display != NULL)
1551 {
1552 XCloseDisplay(x11_display);
1553 x11_display_from = XD_NONE;
1554 }
1555 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1556 {
1557 x11_display_from = XD_GUI;
1558 return OK;
1559 }
1560 x11_display = NULL;
1561 return FAIL;
1562 }
1563 else if (x11_display_from == XD_GUI)
1564 {
1565 /* GUI must have stopped somehow, clear x11_display */
1566 x11_window = 0;
1567 x11_display = NULL;
1568 x11_display_from = XD_NONE;
1569 }
1570#endif
1571
1572 /* When started with the "-X" argument, don't try connecting. */
1573 if (!x_connect_to_server())
1574 return FAIL;
1575
1576 /*
1577 * If WINDOWID not set, should try another method to find out
1578 * what the current window number is. The only code I know for
1579 * this is very complicated.
1580 * We assume that zero is invalid for WINDOWID.
1581 */
1582 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1583 x11_window = (Window)atol(winid);
1584
1585#ifdef FEAT_XCLIPBOARD
1586 if (xterm_dpy != NULL && x11_window != 0)
1587 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001588 /* We may have checked it already, but Gnome terminal can move us to
1589 * another window, so we need to check every time. */
1590 if (x11_display_from != XD_XTERM)
1591 {
1592 /*
1593 * If the X11 display was opened here before, for the window where
1594 * Vim was started, close that one now to avoid a memory leak.
1595 */
1596 if (x11_display_from == XD_HERE && x11_display != NULL)
1597 XCloseDisplay(x11_display);
1598 x11_display = xterm_dpy;
1599 x11_display_from = XD_XTERM;
1600 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001601 if (test_x11_window(x11_display) == FAIL)
1602 {
1603 /* probably bad $WINDOWID */
1604 x11_window = 0;
1605 x11_display = NULL;
1606 x11_display_from = XD_NONE;
1607 return FAIL;
1608 }
1609 return OK;
1610 }
1611#endif
1612
1613 if (x11_window == 0 || x11_display == NULL)
1614 result = -1;
1615
1616 if (result != -1) /* Have already been here and set this */
1617 return result; /* Don't do all these X calls again */
1618
1619 if (x11_window != 0 && x11_display == NULL)
1620 {
1621#ifdef SET_SIG_ALARM
1622 RETSIGTYPE (*sig_save)();
1623#endif
1624#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1625 struct timeval start_tv;
1626
1627 if (p_verbose > 0)
1628 gettimeofday(&start_tv, NULL);
1629#endif
1630
1631#ifdef SET_SIG_ALARM
1632 /*
1633 * Opening the Display may hang if the DISPLAY setting is wrong, or
1634 * the network connection is bad. Set an alarm timer to get out.
1635 */
1636 sig_alarm_called = FALSE;
1637 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1638 (RETSIGTYPE (*)())sig_alarm);
1639 alarm(2);
1640#endif
1641 x11_display = XOpenDisplay(NULL);
1642
1643#ifdef SET_SIG_ALARM
1644 alarm(0);
1645 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1646 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001647 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001648#endif
1649 if (x11_display != NULL)
1650 {
1651# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1652 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001653 {
1654 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001655 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001656 verbose_leave();
1657 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001658# endif
1659 if (test_x11_window(x11_display) == FAIL)
1660 {
1661 /* Maybe window id is bad */
1662 x11_window = 0;
1663 XCloseDisplay(x11_display);
1664 x11_display = NULL;
1665 }
1666 else
1667 x11_display_from = XD_HERE;
1668 }
1669 }
1670 if (x11_window == 0 || x11_display == NULL)
1671 return (result = FAIL);
1672 return (result = OK);
1673}
1674
1675/*
1676 * Determine original x11 Window Title
1677 */
1678 static int
1679get_x11_title(test_only)
1680 int test_only;
1681{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001682 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001683}
1684
1685/*
1686 * Determine original x11 Window icon
1687 */
1688 static int
1689get_x11_icon(test_only)
1690 int test_only;
1691{
1692 int retval = FALSE;
1693
1694 retval = get_x11_thing(FALSE, test_only);
1695
1696 /* could not get old icon, use terminal name */
1697 if (oldicon == NULL && !test_only)
1698 {
1699 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1700 oldicon = T_NAME + 8;
1701 else
1702 oldicon = T_NAME;
1703 }
1704
1705 return retval;
1706}
1707
1708 static int
1709get_x11_thing(get_title, test_only)
1710 int get_title; /* get title string */
1711 int test_only;
1712{
1713 XTextProperty text_prop;
1714 int retval = FALSE;
1715 Status status;
1716
1717 if (get_x11_windis() == OK)
1718 {
1719 /* Get window/icon name if any */
1720 if (get_title)
1721 status = XGetWMName(x11_display, x11_window, &text_prop);
1722 else
1723 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1724
1725 /*
1726 * If terminal is xterm, then x11_window may be a child window of the
1727 * outer xterm window that actually contains the window/icon name, so
1728 * keep traversing up the tree until a window with a title/icon is
1729 * found.
1730 */
1731 /* Previously this was only done for xterm and alikes. I don't see a
1732 * reason why it would fail for other terminal emulators.
1733 * if (term_is_xterm) */
1734 {
1735 Window root;
1736 Window parent;
1737 Window win = x11_window;
1738 Window *children;
1739 unsigned int num_children;
1740
1741 while (!status || text_prop.value == NULL)
1742 {
1743 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1744 &num_children))
1745 break;
1746 if (children)
1747 XFree((void *)children);
1748 if (parent == root || parent == 0)
1749 break;
1750
1751 win = parent;
1752 if (get_title)
1753 status = XGetWMName(x11_display, win, &text_prop);
1754 else
1755 status = XGetWMIconName(x11_display, win, &text_prop);
1756 }
1757 }
1758 if (status && text_prop.value != NULL)
1759 {
1760 retval = TRUE;
1761 if (!test_only)
1762 {
1763#ifdef FEAT_XFONTSET
1764 if (text_prop.encoding == XA_STRING)
1765 {
1766#endif
1767 if (get_title)
1768 oldtitle = vim_strsave((char_u *)text_prop.value);
1769 else
1770 oldicon = vim_strsave((char_u *)text_prop.value);
1771#ifdef FEAT_XFONTSET
1772 }
1773 else
1774 {
1775 char **cl;
1776 Status transform_status;
1777 int n = 0;
1778
1779 transform_status = XmbTextPropertyToTextList(x11_display,
1780 &text_prop,
1781 &cl, &n);
1782 if (transform_status >= Success && n > 0 && cl[0])
1783 {
1784 if (get_title)
1785 oldtitle = vim_strsave((char_u *) cl[0]);
1786 else
1787 oldicon = vim_strsave((char_u *) cl[0]);
1788 XFreeStringList(cl);
1789 }
1790 else
1791 {
1792 if (get_title)
1793 oldtitle = vim_strsave((char_u *)text_prop.value);
1794 else
1795 oldicon = vim_strsave((char_u *)text_prop.value);
1796 }
1797 }
1798#endif
1799 }
1800 XFree((void *)text_prop.value);
1801 }
1802 }
1803 return retval;
1804}
1805
1806/* Are Xutf8 functions available? Avoid error from old compilers. */
1807#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1808# if X_HAVE_UTF8_STRING
1809# define USE_UTF8_STRING
1810# endif
1811#endif
1812
1813/*
1814 * Set x11 Window Title
1815 *
1816 * get_x11_windis() must be called before this and have returned OK
1817 */
1818 static void
1819set_x11_title(title)
1820 char_u *title;
1821{
1822 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1823 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1824 * supported everywhere and STRING doesn't work for multi-byte titles.
1825 */
1826#ifdef USE_UTF8_STRING
1827 if (enc_utf8)
1828 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1829 NULL, NULL, 0, NULL, NULL, NULL);
1830 else
1831#endif
1832 {
1833#if XtSpecificationRelease >= 4
1834# ifdef FEAT_XFONTSET
1835 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1836 NULL, NULL, 0, NULL, NULL, NULL);
1837# else
1838 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001839 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001840
1841 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001842 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001843 XSetWMProperties(x11_display, x11_window, &text_prop,
1844 NULL, NULL, 0, NULL, NULL, NULL);
1845# endif
1846#else
1847 XStoreName(x11_display, x11_window, (char *)title);
1848#endif
1849 }
1850 XFlush(x11_display);
1851}
1852
1853/*
1854 * Set x11 Window icon
1855 *
1856 * get_x11_windis() must be called before this and have returned OK
1857 */
1858 static void
1859set_x11_icon(icon)
1860 char_u *icon;
1861{
1862 /* See above for comments about using X*SetWMProperties(). */
1863#ifdef USE_UTF8_STRING
1864 if (enc_utf8)
1865 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1866 NULL, 0, NULL, NULL, NULL);
1867 else
1868#endif
1869 {
1870#if XtSpecificationRelease >= 4
1871# ifdef FEAT_XFONTSET
1872 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1873 NULL, 0, NULL, NULL, NULL);
1874# else
1875 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001876 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001877
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001878 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001879 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
1880 NULL, 0, NULL, NULL, NULL);
1881# endif
1882#else
1883 XSetIconName(x11_display, x11_window, (char *)icon);
1884#endif
1885 }
1886 XFlush(x11_display);
1887}
1888
1889#else /* FEAT_X11 */
1890
1891/*ARGSUSED*/
1892 static int
1893get_x11_title(test_only)
1894 int test_only;
1895{
1896 return FALSE;
1897}
1898
1899 static int
1900get_x11_icon(test_only)
1901 int test_only;
1902{
1903 if (!test_only)
1904 {
1905 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1906 oldicon = T_NAME + 8;
1907 else
1908 oldicon = T_NAME;
1909 }
1910 return FALSE;
1911}
1912
1913#endif /* FEAT_X11 */
1914
1915 int
1916mch_can_restore_title()
1917{
1918 return get_x11_title(TRUE);
1919}
1920
1921 int
1922mch_can_restore_icon()
1923{
1924 return get_x11_icon(TRUE);
1925}
1926
1927/*
1928 * Set the window title and icon.
1929 */
1930 void
1931mch_settitle(title, icon)
1932 char_u *title;
1933 char_u *icon;
1934{
1935 int type = 0;
1936 static int recursive = 0;
1937
1938 if (T_NAME == NULL) /* no terminal name (yet) */
1939 return;
1940 if (title == NULL && icon == NULL) /* nothing to do */
1941 return;
1942
1943 /* When one of the X11 functions causes a deadly signal, we get here again
1944 * recursively. Avoid hanging then (something is probably locked). */
1945 if (recursive)
1946 return;
1947 ++recursive;
1948
1949 /*
1950 * if the window ID and the display is known, we may use X11 calls
1951 */
1952#ifdef FEAT_X11
1953 if (get_x11_windis() == OK)
1954 type = 1;
1955#else
1956# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
1957 if (gui.in_use)
1958 type = 1;
1959# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001960#endif
1961
1962 /*
1963 * Note: if "t_TS" is set, title is set with escape sequence rather
1964 * than x11 calls, because the x11 calls don't always work
1965 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966 if ((type || *T_TS != NUL) && title != NULL)
1967 {
1968 if (oldtitle == NULL
1969#ifdef FEAT_GUI
1970 && !gui.in_use
1971#endif
1972 ) /* first call but not in GUI, save title */
1973 (void)get_x11_title(FALSE);
1974
1975 if (*T_TS != NUL) /* it's OK if t_fs is empty */
1976 term_settitle(title);
1977#ifdef FEAT_X11
1978 else
1979# ifdef FEAT_GUI_GTK
1980 if (!gui.in_use) /* don't do this if GTK+ is running */
1981# endif
1982 set_x11_title(title); /* x11 */
1983#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00001984#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001985 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
1986 else
1987 gui_mch_settitle(title, icon);
1988#endif
1989 did_set_title = TRUE;
1990 }
1991
1992 if ((type || *T_CIS != NUL) && icon != NULL)
1993 {
1994 if (oldicon == NULL
1995#ifdef FEAT_GUI
1996 && !gui.in_use
1997#endif
1998 ) /* first call, save icon */
1999 get_x11_icon(FALSE);
2000
2001 if (*T_CIS != NUL)
2002 {
2003 out_str(T_CIS); /* set icon start */
2004 out_str_nf(icon);
2005 out_str(T_CIE); /* set icon end */
2006 out_flush();
2007 }
2008#ifdef FEAT_X11
2009 else
2010# ifdef FEAT_GUI_GTK
2011 if (!gui.in_use) /* don't do this if GTK+ is running */
2012# endif
2013 set_x11_icon(icon); /* x11 */
2014#endif
2015 did_set_icon = TRUE;
2016 }
2017 --recursive;
2018}
2019
2020/*
2021 * Restore the window/icon title.
2022 * "which" is one of:
2023 * 1 only restore title
2024 * 2 only restore icon
2025 * 3 restore title and icon
2026 */
2027 void
2028mch_restore_title(which)
2029 int which;
2030{
2031 /* only restore the title or icon when it has been set */
2032 mch_settitle(((which & 1) && did_set_title) ?
2033 (oldtitle ? oldtitle : p_titleold) : NULL,
2034 ((which & 2) && did_set_icon) ? oldicon : NULL);
2035}
2036
2037#endif /* FEAT_TITLE */
2038
2039/*
2040 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002041 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002042 */
2043 int
2044vim_is_xterm(name)
2045 char_u *name;
2046{
2047 if (name == NULL)
2048 return FALSE;
2049 return (STRNICMP(name, "xterm", 5) == 0
2050 || STRNICMP(name, "nxterm", 6) == 0
2051 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002052 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002053 || STRNICMP(name, "rxvt", 4) == 0
2054 || STRCMP(name, "builtin_xterm") == 0);
2055}
2056
2057#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2058/*
2059 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2060 * Return 1 for "xterm".
2061 * Return 2 for "xterm2".
2062 */
2063 int
2064use_xterm_mouse()
2065{
2066 if (ttym_flags == TTYM_XTERM2)
2067 return 2;
2068 if (ttym_flags == TTYM_XTERM)
2069 return 1;
2070 return 0;
2071}
2072#endif
2073
2074 int
2075vim_is_iris(name)
2076 char_u *name;
2077{
2078 if (name == NULL)
2079 return FALSE;
2080 return (STRNICMP(name, "iris-ansi", 9) == 0
2081 || STRCMP(name, "builtin_iris-ansi") == 0);
2082}
2083
2084 int
2085vim_is_vt300(name)
2086 char_u *name;
2087{
2088 if (name == NULL)
2089 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002090 /* catch VT100 - VT5xx */
2091 return ((STRNICMP(name, "vt", 2) == 0
2092 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093 || STRCMP(name, "builtin_vt320") == 0);
2094}
2095
2096/*
2097 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2098 * This should include all windowed terminal emulators.
2099 */
2100 int
2101vim_is_fastterm(name)
2102 char_u *name;
2103{
2104 if (name == NULL)
2105 return FALSE;
2106 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2107 return TRUE;
2108 return ( STRNICMP(name, "hpterm", 6) == 0
2109 || STRNICMP(name, "sun-cmd", 7) == 0
2110 || STRNICMP(name, "screen", 6) == 0
2111 || STRNICMP(name, "dtterm", 6) == 0);
2112}
2113
2114/*
2115 * Insert user name in s[len].
2116 * Return OK if a name found.
2117 */
2118 int
2119mch_get_user_name(s, len)
2120 char_u *s;
2121 int len;
2122{
2123#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002124 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002125 return OK;
2126#else
2127 return mch_get_uname(getuid(), s, len);
2128#endif
2129}
2130
2131/*
2132 * Insert user name for "uid" in s[len].
2133 * Return OK if a name found.
2134 */
2135 int
2136mch_get_uname(uid, s, len)
2137 uid_t uid;
2138 char_u *s;
2139 int len;
2140{
2141#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2142 struct passwd *pw;
2143
2144 if ((pw = getpwuid(uid)) != NULL
2145 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2146 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002147 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002148 return OK;
2149 }
2150#endif
2151 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2152 return FAIL; /* a number is not a name */
2153}
2154
2155/*
2156 * Insert host name is s[len].
2157 */
2158
2159#ifdef HAVE_SYS_UTSNAME_H
2160 void
2161mch_get_host_name(s, len)
2162 char_u *s;
2163 int len;
2164{
2165 struct utsname vutsname;
2166
2167 if (uname(&vutsname) < 0)
2168 *s = NUL;
2169 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002170 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002171}
2172#else /* HAVE_SYS_UTSNAME_H */
2173
2174# ifdef HAVE_SYS_SYSTEMINFO_H
2175# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2176# endif
2177
2178 void
2179mch_get_host_name(s, len)
2180 char_u *s;
2181 int len;
2182{
2183# ifdef VAXC
2184 vaxc$gethostname((char *)s, len);
2185# else
2186 gethostname((char *)s, len);
2187# endif
2188 s[len - 1] = NUL; /* make sure it's terminated */
2189}
2190#endif /* HAVE_SYS_UTSNAME_H */
2191
2192/*
2193 * return process ID
2194 */
2195 long
2196mch_get_pid()
2197{
2198 return (long)getpid();
2199}
2200
2201#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2202static char *strerror __ARGS((int));
2203
2204 static char *
2205strerror(err)
2206 int err;
2207{
2208 extern int sys_nerr;
2209 extern char *sys_errlist[];
2210 static char er[20];
2211
2212 if (err > 0 && err < sys_nerr)
2213 return (sys_errlist[err]);
2214 sprintf(er, "Error %d", err);
2215 return er;
2216}
2217#endif
2218
2219/*
2220 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2221 * Return OK for success, FAIL for failure.
2222 */
2223 int
2224mch_dirname(buf, len)
2225 char_u *buf;
2226 int len;
2227{
2228#if defined(USE_GETCWD)
2229 if (getcwd((char *)buf, len) == NULL)
2230 {
2231 STRCPY(buf, strerror(errno));
2232 return FAIL;
2233 }
2234 return OK;
2235#else
2236 return (getwd((char *)buf) != NULL ? OK : FAIL);
2237#endif
2238}
2239
2240#if defined(OS2) || defined(PROTO)
2241/*
2242 * Replace all slashes by backslashes.
2243 * When 'shellslash' set do it the other way around.
2244 */
2245 void
2246slash_adjust(p)
2247 char_u *p;
2248{
2249 while (*p)
2250 {
2251 if (*p == psepcN)
2252 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002253 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254 }
2255}
2256#endif
2257
2258/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002259 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002260 *
2261 * return FAIL for failure, OK for success
2262 */
2263 int
2264mch_FullName(fname, buf, len, force)
2265 char_u *fname, *buf;
2266 int len;
2267 int force; /* also expand when already absolute path */
2268{
2269 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002270#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002271 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002272#endif
2273#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274 int fd = -1;
2275 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002276#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002277 char_u olddir[MAXPATHL];
2278 char_u *p;
2279 int retval = OK;
2280
Bram Moolenaar38323e42007-03-06 19:22:53 +00002281#ifdef VMS
2282 fname = vms_fixfilename(fname);
2283#endif
2284
Bram Moolenaara2442432007-04-26 14:26:37 +00002285#ifdef __CYGWIN__
2286 /*
2287 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2288 */
2289 cygwin_conv_to_posix_path(fname, fname);
2290#endif
2291
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292 /* expand it if forced or not an absolute path */
2293 if (force || !mch_isFullName(fname))
2294 {
2295 /*
2296 * If the file name has a path, change to that directory for a moment,
2297 * and then do the getwd() (and get back to where we were).
2298 * This will get the correct path name with "../" things.
2299 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002300#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002301 only_drive = 0;
2302 if (((p = vim_strrchr(fname, '/')) != NULL)
2303 || ((p = vim_strrchr(fname, '\\')) != NULL)
2304 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002305#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002307#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002309#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002310 /*
2311 * Use fchdir() if possible, it's said to be faster and more
2312 * reliable. But on SunOS 4 it might not work. Check this by
2313 * doing a fchdir() right now.
2314 */
2315 if (!dont_fchdir)
2316 {
2317 fd = open(".", O_RDONLY | O_EXTRA, 0);
2318 if (fd >= 0 && fchdir(fd) < 0)
2319 {
2320 close(fd);
2321 fd = -1;
2322 dont_fchdir = TRUE; /* don't try again */
2323 }
2324 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002325#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002326
2327 /* Only change directory when we are sure we can return to where
2328 * we are now. After doing "su" chdir(".") might not work. */
2329 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002330#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002332#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333 (mch_dirname(olddir, MAXPATHL) == FAIL
2334 || mch_chdir((char *)olddir) != 0))
2335 {
2336 p = NULL; /* can't get current dir: don't chdir */
2337 retval = FAIL;
2338 }
2339 else
2340 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002341#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002342 /*
2343 * compensate for case where ':' from "D:" was the only
2344 * path separator detected in the file name; the _next_
2345 * character has to be removed, and then restored later.
2346 */
2347 if (only_drive)
2348 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002349#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350 /* The directory is copied into buf[], to be able to remove
2351 * the file name without changing it (could be a string in
2352 * read-only memory) */
2353 if (p - fname >= len)
2354 retval = FAIL;
2355 else
2356 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002357 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358 if (mch_chdir((char *)buf))
2359 retval = FAIL;
2360 else
2361 fname = p + 1;
2362 *buf = NUL;
2363 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002364#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002365 if (only_drive)
2366 {
2367 p--;
2368 if (retval != FAIL)
2369 fname--;
2370 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002371#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372 }
2373 }
2374 if (mch_dirname(buf, len) == FAIL)
2375 {
2376 retval = FAIL;
2377 *buf = NUL;
2378 }
2379 if (p != NULL)
2380 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002381#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002382 if (fd >= 0)
2383 {
2384 l = fchdir(fd);
2385 close(fd);
2386 }
2387 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002388#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002389 l = mch_chdir((char *)olddir);
2390 if (l != 0)
2391 EMSG(_(e_prev_dir));
2392 }
2393
2394 l = STRLEN(buf);
2395 if (l >= len)
2396 retval = FAIL;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002397#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398 else
2399 {
2400 if (l > 0 && buf[l - 1] != '/' && *fname != NUL
2401 && STRCMP(fname, ".") != 0)
2402 STRCAT(buf, "/");
2403 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002404#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002406
Bram Moolenaar071d4272004-06-13 20:20:40 +00002407 /* Catch file names which are too long. */
2408 if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len)
2409 return FAIL;
2410
2411 /* Do not append ".", "/dir/." is equal to "/dir". */
2412 if (STRCMP(fname, ".") != 0)
2413 STRCAT(buf, fname);
2414
2415 return OK;
2416}
2417
2418/*
2419 * Return TRUE if "fname" does not depend on the current directory.
2420 */
2421 int
2422mch_isFullName(fname)
2423 char_u *fname;
2424{
2425#ifdef __EMX__
2426 return _fnisabs(fname);
2427#else
2428# ifdef VMS
2429 return ( fname[0] == '/' || fname[0] == '.' ||
2430 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2431 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2432 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2433# else
2434 return (*fname == '/' || *fname == '~');
2435# endif
2436#endif
2437}
2438
Bram Moolenaar24552be2005-12-10 20:17:30 +00002439#if defined(USE_FNAME_CASE) || defined(PROTO)
2440/*
2441 * Set the case of the file name, if it already exists. This will cause the
2442 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002443 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002444 */
2445/*ARGSUSED*/
2446 void
2447fname_case(name, len)
2448 char_u *name;
2449 int len; /* buffer size, only used when name gets longer */
2450{
2451 struct stat st;
2452 char_u *slash, *tail;
2453 DIR *dirp;
2454 struct dirent *dp;
2455
2456 if (lstat((char *)name, &st) >= 0)
2457 {
2458 /* Open the directory where the file is located. */
2459 slash = vim_strrchr(name, '/');
2460 if (slash == NULL)
2461 {
2462 dirp = opendir(".");
2463 tail = name;
2464 }
2465 else
2466 {
2467 *slash = NUL;
2468 dirp = opendir((char *)name);
2469 *slash = '/';
2470 tail = slash + 1;
2471 }
2472
2473 if (dirp != NULL)
2474 {
2475 while ((dp = readdir(dirp)) != NULL)
2476 {
2477 /* Only accept names that differ in case and are the same byte
2478 * length. TODO: accept different length name. */
2479 if (STRICMP(tail, dp->d_name) == 0
2480 && STRLEN(tail) == STRLEN(dp->d_name))
2481 {
2482 char_u newname[MAXPATHL + 1];
2483 struct stat st2;
2484
2485 /* Verify the inode is equal. */
2486 vim_strncpy(newname, name, MAXPATHL);
2487 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2488 MAXPATHL - (tail - name));
2489 if (lstat((char *)newname, &st2) >= 0
2490 && st.st_ino == st2.st_ino
2491 && st.st_dev == st2.st_dev)
2492 {
2493 STRCPY(tail, dp->d_name);
2494 break;
2495 }
2496 }
2497 }
2498
2499 closedir(dirp);
2500 }
2501 }
2502}
2503#endif
2504
Bram Moolenaar071d4272004-06-13 20:20:40 +00002505/*
2506 * Get file permissions for 'name'.
2507 * Returns -1 when it doesn't exist.
2508 */
2509 long
2510mch_getperm(name)
2511 char_u *name;
2512{
2513 struct stat statb;
2514
2515 /* Keep the #ifdef outside of stat(), it may be a macro. */
2516#ifdef VMS
2517 if (stat((char *)vms_fixfilename(name), &statb))
2518#else
2519 if (stat((char *)name, &statb))
2520#endif
2521 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002522#ifdef __INTERIX
2523 /* The top bit makes the value negative, which means the file doesn't
2524 * exist. Remove the bit, we don't use it. */
2525 return statb.st_mode & ~S_ADDACE;
2526#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002527 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002528#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002529}
2530
2531/*
2532 * set file permission for 'name' to 'perm'
2533 *
2534 * return FAIL for failure, OK otherwise
2535 */
2536 int
2537mch_setperm(name, perm)
2538 char_u *name;
2539 long perm;
2540{
2541 return (chmod((char *)
2542#ifdef VMS
2543 vms_fixfilename(name),
2544#else
2545 name,
2546#endif
2547 (mode_t)perm) == 0 ? OK : FAIL);
2548}
2549
2550#if defined(HAVE_ACL) || defined(PROTO)
2551# ifdef HAVE_SYS_ACL_H
2552# include <sys/acl.h>
2553# endif
2554# ifdef HAVE_SYS_ACCESS_H
2555# include <sys/access.h>
2556# endif
2557
2558# ifdef HAVE_SOLARIS_ACL
2559typedef struct vim_acl_solaris_T {
2560 int acl_cnt;
2561 aclent_t *acl_entry;
2562} vim_acl_solaris_T;
2563# endif
2564
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002565#if defined(HAVE_SELINUX) || defined(PROTO)
2566/*
2567 * Copy security info from "from_file" to "to_file".
2568 */
2569 void
2570mch_copy_sec(from_file, to_file)
2571 char_u *from_file;
2572 char_u *to_file;
2573{
2574 if (from_file == NULL)
2575 return;
2576
2577 if (selinux_enabled == -1)
2578 selinux_enabled = is_selinux_enabled();
2579
2580 if (selinux_enabled > 0)
2581 {
2582 security_context_t from_context = NULL;
2583 security_context_t to_context = NULL;
2584
2585 if (getfilecon((char *)from_file, &from_context) < 0)
2586 {
2587 /* If the filesystem doesn't support extended attributes,
2588 the original had no special security context and the
2589 target cannot have one either. */
2590 if (errno == EOPNOTSUPP)
2591 return;
2592
2593 MSG_PUTS(_("\nCould not get security context for "));
2594 msg_outtrans(from_file);
2595 msg_putchar('\n');
2596 return;
2597 }
2598 if (getfilecon((char *)to_file, &to_context) < 0)
2599 {
2600 MSG_PUTS(_("\nCould not get security context for "));
2601 msg_outtrans(to_file);
2602 msg_putchar('\n');
2603 freecon (from_context);
2604 return ;
2605 }
2606 if (strcmp(from_context, to_context) != 0)
2607 {
2608 if (setfilecon((char *)to_file, from_context) < 0)
2609 {
2610 MSG_PUTS(_("\nCould not set security context for "));
2611 msg_outtrans(to_file);
2612 msg_putchar('\n');
2613 }
2614 }
2615 freecon(to_context);
2616 freecon(from_context);
2617 }
2618}
2619#endif /* HAVE_SELINUX */
2620
Bram Moolenaar071d4272004-06-13 20:20:40 +00002621/*
2622 * Return a pointer to the ACL of file "fname" in allocated memory.
2623 * Return NULL if the ACL is not available for whatever reason.
2624 */
2625 vim_acl_T
2626mch_get_acl(fname)
2627 char_u *fname;
2628{
2629 vim_acl_T ret = NULL;
2630#ifdef HAVE_POSIX_ACL
2631 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2632#else
2633#ifdef HAVE_SOLARIS_ACL
2634 vim_acl_solaris_T *aclent;
2635
2636 aclent = malloc(sizeof(vim_acl_solaris_T));
2637 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2638 {
2639 free(aclent);
2640 return NULL;
2641 }
2642 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2643 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2644 {
2645 free(aclent->acl_entry);
2646 free(aclent);
2647 return NULL;
2648 }
2649 ret = (vim_acl_T)aclent;
2650#else
2651#if defined(HAVE_AIX_ACL)
2652 int aclsize;
2653 struct acl *aclent;
2654
2655 aclsize = sizeof(struct acl);
2656 aclent = malloc(aclsize);
2657 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2658 {
2659 if (errno == ENOSPC)
2660 {
2661 aclsize = aclent->acl_len;
2662 aclent = realloc(aclent, aclsize);
2663 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2664 {
2665 free(aclent);
2666 return NULL;
2667 }
2668 }
2669 else
2670 {
2671 free(aclent);
2672 return NULL;
2673 }
2674 }
2675 ret = (vim_acl_T)aclent;
2676#endif /* HAVE_AIX_ACL */
2677#endif /* HAVE_SOLARIS_ACL */
2678#endif /* HAVE_POSIX_ACL */
2679 return ret;
2680}
2681
2682/*
2683 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2684 */
2685 void
2686mch_set_acl(fname, aclent)
2687 char_u *fname;
2688 vim_acl_T aclent;
2689{
2690 if (aclent == NULL)
2691 return;
2692#ifdef HAVE_POSIX_ACL
2693 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2694#else
2695#ifdef HAVE_SOLARIS_ACL
2696 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2697 ((vim_acl_solaris_T *)aclent)->acl_entry);
2698#else
2699#ifdef HAVE_AIX_ACL
2700 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2701#endif /* HAVE_AIX_ACL */
2702#endif /* HAVE_SOLARIS_ACL */
2703#endif /* HAVE_POSIX_ACL */
2704}
2705
2706 void
2707mch_free_acl(aclent)
2708 vim_acl_T aclent;
2709{
2710 if (aclent == NULL)
2711 return;
2712#ifdef HAVE_POSIX_ACL
2713 acl_free((acl_t)aclent);
2714#else
2715#ifdef HAVE_SOLARIS_ACL
2716 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2717 free(aclent);
2718#else
2719#ifdef HAVE_AIX_ACL
2720 free(aclent);
2721#endif /* HAVE_AIX_ACL */
2722#endif /* HAVE_SOLARIS_ACL */
2723#endif /* HAVE_POSIX_ACL */
2724}
2725#endif
2726
2727/*
2728 * Set hidden flag for "name".
2729 */
2730/* ARGSUSED */
2731 void
2732mch_hide(name)
2733 char_u *name;
2734{
2735 /* can't hide a file */
2736}
2737
2738/*
2739 * return TRUE if "name" is a directory
2740 * return FALSE if "name" is not a directory
2741 * return FALSE for error
2742 */
2743 int
2744mch_isdir(name)
2745 char_u *name;
2746{
2747 struct stat statb;
2748
2749 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2750 return FALSE;
2751 if (stat((char *)name, &statb))
2752 return FALSE;
2753#ifdef _POSIX_SOURCE
2754 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2755#else
2756 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2757#endif
2758}
2759
Bram Moolenaar071d4272004-06-13 20:20:40 +00002760static int executable_file __ARGS((char_u *name));
2761
2762/*
2763 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2764 */
2765 static int
2766executable_file(name)
2767 char_u *name;
2768{
2769 struct stat st;
2770
2771 if (stat((char *)name, &st))
2772 return 0;
2773 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2774}
2775
2776/*
2777 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2778 * Return -1 if unknown.
2779 */
2780 int
2781mch_can_exe(name)
2782 char_u *name;
2783{
2784 char_u *buf;
2785 char_u *p, *e;
2786 int retval;
2787
2788 /* If it's an absolute or relative path don't need to use $PATH. */
2789 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2790 || (name[1] == '.' && name[2] == '/'))))
2791 return executable_file(name);
2792
2793 p = (char_u *)getenv("PATH");
2794 if (p == NULL || *p == NUL)
2795 return -1;
2796 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2797 if (buf == NULL)
2798 return -1;
2799
2800 /*
2801 * Walk through all entries in $PATH to check if "name" exists there and
2802 * is an executable file.
2803 */
2804 for (;;)
2805 {
2806 e = (char_u *)strchr((char *)p, ':');
2807 if (e == NULL)
2808 e = p + STRLEN(p);
2809 if (e - p <= 1) /* empty entry means current dir */
2810 STRCPY(buf, "./");
2811 else
2812 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002813 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814 add_pathsep(buf);
2815 }
2816 STRCAT(buf, name);
2817 retval = executable_file(buf);
2818 if (retval == 1)
2819 break;
2820
2821 if (*e != ':')
2822 break;
2823 p = e + 1;
2824 }
2825
2826 vim_free(buf);
2827 return retval;
2828}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002829
2830/*
2831 * Check what "name" is:
2832 * NODE_NORMAL: file or directory (or doesn't exist)
2833 * NODE_WRITABLE: writable device, socket, fifo, etc.
2834 * NODE_OTHER: non-writable things
2835 */
2836 int
2837mch_nodetype(name)
2838 char_u *name;
2839{
2840 struct stat st;
2841
2842 if (stat((char *)name, &st))
2843 return NODE_NORMAL;
2844 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2845 return NODE_NORMAL;
2846#ifndef OS2
2847 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2848 return NODE_OTHER;
2849#endif
2850 /* Everything else is writable? */
2851 return NODE_WRITABLE;
2852}
2853
2854 void
2855mch_early_init()
2856{
2857#ifdef HAVE_CHECK_STACK_GROWTH
2858 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002859
Bram Moolenaar071d4272004-06-13 20:20:40 +00002860 check_stack_growth((char *)&i);
2861
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002862# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002863 get_stack_limit();
2864# endif
2865
2866#endif
2867
2868 /*
2869 * Setup an alternative stack for signals. Helps to catch signals when
2870 * running out of stack space.
2871 * Use of sigaltstack() is preferred, it's more portable.
2872 * Ignore any errors.
2873 */
2874#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2875 signal_stack = malloc(SIGSTKSZ);
2876 init_signal_stack();
2877#endif
2878}
2879
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002880#if defined(EXITFREE) || defined(PROTO)
2881 void
2882mch_free_mem()
2883{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002884# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2885 if (clip_star.owned)
2886 clip_lose_selection(&clip_star);
2887 if (clip_plus.owned)
2888 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002889# endif
2890# if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
2891 if (xterm_Shell != (Widget)0)
2892 XtDestroyWidget(xterm_Shell);
2893 if (xterm_dpy != NULL)
2894 XtCloseDisplay(xterm_dpy);
2895 if (app_context != (XtAppContext)NULL)
2896 XtDestroyApplicationContext(app_context);
2897# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002898# ifdef FEAT_X11
2899 if (x11_display != NULL && x11_display != xterm_dpy)
2900 XCloseDisplay(x11_display);
2901# endif
2902# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2903 vim_free(signal_stack);
2904 signal_stack = NULL;
2905# endif
2906# ifdef FEAT_TITLE
2907 vim_free(oldtitle);
2908 vim_free(oldicon);
2909# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002910}
2911#endif
2912
Bram Moolenaar071d4272004-06-13 20:20:40 +00002913static void exit_scroll __ARGS((void));
2914
2915/*
2916 * Output a newline when exiting.
2917 * Make sure the newline goes to the same stream as the text.
2918 */
2919 static void
2920exit_scroll()
2921{
Bram Moolenaardf177f62005-02-22 08:39:57 +00002922 if (silent_mode)
2923 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924 if (newline_on_exit || msg_didout)
2925 {
2926 if (msg_use_printf())
2927 {
2928 if (info_message)
2929 mch_msg("\n");
2930 else
2931 mch_errmsg("\r\n");
2932 }
2933 else
2934 out_char('\n');
2935 }
2936 else
2937 {
2938 restore_cterm_colors(); /* get original colors back */
2939 msg_clr_eos_force(); /* clear the rest of the display */
2940 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
2941 }
2942}
2943
2944 void
2945mch_exit(r)
2946 int r;
2947{
2948 exiting = TRUE;
2949
2950#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
2951 x11_export_final_selection();
2952#endif
2953
2954#ifdef FEAT_GUI
2955 if (!gui.in_use)
2956#endif
2957 {
2958 settmode(TMODE_COOK);
2959#ifdef FEAT_TITLE
2960 mch_restore_title(3); /* restore xterm title and icon name */
2961#endif
2962 /*
2963 * When t_ti is not empty but it doesn't cause swapping terminal
2964 * pages, need to output a newline when msg_didout is set. But when
2965 * t_ti does swap pages it should not go to the shell page. Do this
2966 * before stoptermcap().
2967 */
2968 if (swapping_screen() && !newline_on_exit)
2969 exit_scroll();
2970
2971 /* Stop termcap: May need to check for T_CRV response, which
2972 * requires RAW mode. */
2973 stoptermcap();
2974
2975 /*
2976 * A newline is only required after a message in the alternate screen.
2977 * This is set to TRUE by wait_return().
2978 */
2979 if (!swapping_screen() || newline_on_exit)
2980 exit_scroll();
2981
2982 /* Cursor may have been switched off without calling starttermcap()
2983 * when doing "vim -u vimrc" and vimrc contains ":q". */
2984 if (full_screen)
2985 cursor_on();
2986 }
2987 out_flush();
2988 ml_close_all(TRUE); /* remove all memfiles */
2989 may_core_dump();
2990#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002991 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002992 gui_exit(r);
2993#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00002994
Bram Moolenaar56718732006-03-15 22:53:57 +00002995#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00002996 mac_conv_cleanup();
2997#endif
2998
Bram Moolenaar071d4272004-06-13 20:20:40 +00002999#ifdef __QNX__
3000 /* A core dump won't be created if the signal handler
3001 * doesn't return, so we can't call exit() */
3002 if (deadly_signal != 0)
3003 return;
3004#endif
3005
Bram Moolenaar009b2592004-10-24 19:18:58 +00003006#ifdef FEAT_NETBEANS_INTG
3007 if (usingNetbeans)
3008 netbeans_send_disconnect();
3009#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003010
3011#ifdef EXITFREE
3012 free_all_mem();
3013#endif
3014
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015 exit(r);
3016}
3017
3018 static void
3019may_core_dump()
3020{
3021 if (deadly_signal != 0)
3022 {
3023 signal(deadly_signal, SIG_DFL);
3024 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3025 }
3026}
3027
3028#ifndef VMS
3029
3030 void
3031mch_settmode(tmode)
3032 int tmode;
3033{
3034 static int first = TRUE;
3035
3036 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3037#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3038 /*
3039 * for "new" tty systems
3040 */
3041# ifdef HAVE_TERMIOS_H
3042 static struct termios told;
3043 struct termios tnew;
3044# else
3045 static struct termio told;
3046 struct termio tnew;
3047# endif
3048
3049 if (first)
3050 {
3051 first = FALSE;
3052# if defined(HAVE_TERMIOS_H)
3053 tcgetattr(read_cmd_fd, &told);
3054# else
3055 ioctl(read_cmd_fd, TCGETA, &told);
3056# endif
3057 }
3058
3059 tnew = told;
3060 if (tmode == TMODE_RAW)
3061 {
3062 /*
3063 * ~ICRNL enables typing ^V^M
3064 */
3065 tnew.c_iflag &= ~ICRNL;
3066 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3067# if defined(IEXTEN) && !defined(__MINT__)
3068 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3069 /* but it breaks function keys on MINT */
3070# endif
3071 );
3072# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3073 tnew.c_oflag &= ~ONLCR;
3074# endif
3075 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3076 tnew.c_cc[VTIME] = 0; /* don't wait */
3077 }
3078 else if (tmode == TMODE_SLEEP)
3079 tnew.c_lflag &= ~(ECHO);
3080
3081# if defined(HAVE_TERMIOS_H)
3082 {
3083 int n = 10;
3084
3085 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3086 * few times. */
3087 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3088 && errno == EINTR && n > 0)
3089 --n;
3090 }
3091# else
3092 ioctl(read_cmd_fd, TCSETA, &tnew);
3093# endif
3094
3095#else
3096
3097 /*
3098 * for "old" tty systems
3099 */
3100# ifndef TIOCSETN
3101# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3102# endif
3103 static struct sgttyb ttybold;
3104 struct sgttyb ttybnew;
3105
3106 if (first)
3107 {
3108 first = FALSE;
3109 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3110 }
3111
3112 ttybnew = ttybold;
3113 if (tmode == TMODE_RAW)
3114 {
3115 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3116 ttybnew.sg_flags |= RAW;
3117 }
3118 else if (tmode == TMODE_SLEEP)
3119 ttybnew.sg_flags &= ~(ECHO);
3120 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3121#endif
3122 curr_tmode = tmode;
3123}
3124
3125/*
3126 * Try to get the code for "t_kb" from the stty setting
3127 *
3128 * Even if termcap claims a backspace key, the user's setting *should*
3129 * prevail. stty knows more about reality than termcap does, and if
3130 * somebody's usual erase key is DEL (which, for most BSD users, it will
3131 * be), they're going to get really annoyed if their erase key starts
3132 * doing forward deletes for no reason. (Eric Fischer)
3133 */
3134 void
3135get_stty()
3136{
3137 char_u buf[2];
3138 char_u *p;
3139
3140 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3141#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3142 /* for "new" tty systems */
3143# ifdef HAVE_TERMIOS_H
3144 struct termios keys;
3145# else
3146 struct termio keys;
3147# endif
3148
3149# if defined(HAVE_TERMIOS_H)
3150 if (tcgetattr(read_cmd_fd, &keys) != -1)
3151# else
3152 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3153# endif
3154 {
3155 buf[0] = keys.c_cc[VERASE];
3156 intr_char = keys.c_cc[VINTR];
3157#else
3158 /* for "old" tty systems */
3159 struct sgttyb keys;
3160
3161 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3162 {
3163 buf[0] = keys.sg_erase;
3164 intr_char = keys.sg_kill;
3165#endif
3166 buf[1] = NUL;
3167 add_termcode((char_u *)"kb", buf, FALSE);
3168
3169 /*
3170 * If <BS> and <DEL> are now the same, redefine <DEL>.
3171 */
3172 p = find_termcode((char_u *)"kD");
3173 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3174 do_fixdel(NULL);
3175 }
3176#if 0
3177 } /* to keep cindent happy */
3178#endif
3179}
3180
3181#endif /* VMS */
3182
3183#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3184/*
3185 * Set mouse clicks on or off.
3186 */
3187 void
3188mch_setmouse(on)
3189 int on;
3190{
3191 static int ison = FALSE;
3192 int xterm_mouse_vers;
3193
3194 if (on == ison) /* return quickly if nothing to do */
3195 return;
3196
3197 xterm_mouse_vers = use_xterm_mouse();
3198 if (xterm_mouse_vers > 0)
3199 {
3200 if (on) /* enable mouse events, use mouse tracking if available */
3201 out_str_nf((char_u *)
3202 (xterm_mouse_vers > 1
3203 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3204 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3205 else /* disable mouse events, could probably always send the same */
3206 out_str_nf((char_u *)
3207 (xterm_mouse_vers > 1
3208 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3209 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3210 ison = on;
3211 }
3212
3213# ifdef FEAT_MOUSE_DEC
3214 else if (ttym_flags == TTYM_DEC)
3215 {
3216 if (on) /* enable mouse events */
3217 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3218 else /* disable mouse events */
3219 out_str_nf((char_u *)"\033['z");
3220 ison = on;
3221 }
3222# endif
3223
3224# ifdef FEAT_MOUSE_GPM
3225 else
3226 {
3227 if (on)
3228 {
3229 if (gpm_open())
3230 ison = TRUE;
3231 }
3232 else
3233 {
3234 gpm_close();
3235 ison = FALSE;
3236 }
3237 }
3238# endif
3239
3240# ifdef FEAT_MOUSE_JSB
3241 else
3242 {
3243 if (on)
3244 {
3245 /* D - Enable Mouse up/down messages
3246 * L - Enable Left Button Reporting
3247 * M - Enable Middle Button Reporting
3248 * R - Enable Right Button Reporting
3249 * K - Enable SHIFT and CTRL key Reporting
3250 * + - Enable Advanced messaging of mouse moves and up/down messages
3251 * Q - Quiet No Ack
3252 * # - Numeric value of mouse pointer required
3253 * 0 = Multiview 2000 cursor, used as standard
3254 * 1 = Windows Arrow
3255 * 2 = Windows I Beam
3256 * 3 = Windows Hour Glass
3257 * 4 = Windows Cross Hair
3258 * 5 = Windows UP Arrow
3259 */
3260#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3261 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3262 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3263#else
3264 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3265 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3266#endif
3267 ison = TRUE;
3268 }
3269 else
3270 {
3271 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3272 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3273 ison = FALSE;
3274 }
3275 }
3276# endif
3277# ifdef FEAT_MOUSE_PTERM
3278 else
3279 {
3280 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3281 if (on)
3282 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3283 else
3284 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3285 ison = on;
3286 }
3287# endif
3288}
3289
3290/*
3291 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3292 */
3293 void
3294check_mouse_termcode()
3295{
3296# ifdef FEAT_MOUSE_XTERM
3297 if (use_xterm_mouse()
3298# ifdef FEAT_GUI
3299 && !gui.in_use
3300# endif
3301 )
3302 {
3303 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003304 ? IF_EB("\233M", CSI_STR "M")
3305 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003306 if (*p_mouse != NUL)
3307 {
3308 /* force mouse off and maybe on to send possibly new mouse
3309 * activation sequence to the xterm, with(out) drag tracing. */
3310 mch_setmouse(FALSE);
3311 setmouse();
3312 }
3313 }
3314 else
3315 del_mouse_termcode(KS_MOUSE);
3316# endif
3317
3318# ifdef FEAT_MOUSE_GPM
3319 if (!use_xterm_mouse()
3320# ifdef FEAT_GUI
3321 && !gui.in_use
3322# endif
3323 )
3324 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3325# endif
3326
3327# ifdef FEAT_MOUSE_JSB
3328 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3329 if (!use_xterm_mouse()
3330# ifdef FEAT_GUI
3331 && !gui.in_use
3332# endif
3333 )
3334 set_mouse_termcode(KS_JSBTERM_MOUSE,
3335 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3336 else
3337 del_mouse_termcode(KS_JSBTERM_MOUSE);
3338# endif
3339
3340# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003341 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 * define it in the GUI or when using an xterm. */
3343 if (!use_xterm_mouse()
3344# ifdef FEAT_GUI
3345 && !gui.in_use
3346# endif
3347 )
3348 set_mouse_termcode(KS_NETTERM_MOUSE,
3349 (char_u *)IF_EB("\033}", ESC_STR "}"));
3350 else
3351 del_mouse_termcode(KS_NETTERM_MOUSE);
3352# endif
3353
3354# ifdef FEAT_MOUSE_DEC
3355 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3356 if (!use_xterm_mouse()
3357# ifdef FEAT_GUI
3358 && !gui.in_use
3359# endif
3360 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003361 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3362 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003363 else
3364 del_mouse_termcode(KS_DEC_MOUSE);
3365# endif
3366# ifdef FEAT_MOUSE_PTERM
3367 /* same as the dec mouse */
3368 if (!use_xterm_mouse()
3369# ifdef FEAT_GUI
3370 && !gui.in_use
3371# endif
3372 )
3373 set_mouse_termcode(KS_PTERM_MOUSE,
3374 (char_u *) IF_EB("\033[", ESC_STR "["));
3375 else
3376 del_mouse_termcode(KS_PTERM_MOUSE);
3377# endif
3378}
3379#endif
3380
3381/*
3382 * set screen mode, always fails.
3383 */
3384/* ARGSUSED */
3385 int
3386mch_screenmode(arg)
3387 char_u *arg;
3388{
3389 EMSG(_(e_screenmode));
3390 return FAIL;
3391}
3392
3393#ifndef VMS
3394
3395/*
3396 * Try to get the current window size:
3397 * 1. with an ioctl(), most accurate method
3398 * 2. from the environment variables LINES and COLUMNS
3399 * 3. from the termcap
3400 * 4. keep using the old values
3401 * Return OK when size could be determined, FAIL otherwise.
3402 */
3403 int
3404mch_get_shellsize()
3405{
3406 long rows = 0;
3407 long columns = 0;
3408 char_u *p;
3409
3410 /*
3411 * For OS/2 use _scrsize().
3412 */
3413# ifdef __EMX__
3414 {
3415 int s[2];
3416
3417 _scrsize(s);
3418 columns = s[0];
3419 rows = s[1];
3420 }
3421# endif
3422
3423 /*
3424 * 1. try using an ioctl. It is the most accurate method.
3425 *
3426 * Try using TIOCGWINSZ first, some systems that have it also define
3427 * TIOCGSIZE but don't have a struct ttysize.
3428 */
3429# ifdef TIOCGWINSZ
3430 {
3431 struct winsize ws;
3432 int fd = 1;
3433
3434 /* When stdout is not a tty, use stdin for the ioctl(). */
3435 if (!isatty(fd) && isatty(read_cmd_fd))
3436 fd = read_cmd_fd;
3437 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3438 {
3439 columns = ws.ws_col;
3440 rows = ws.ws_row;
3441 }
3442 }
3443# else /* TIOCGWINSZ */
3444# ifdef TIOCGSIZE
3445 {
3446 struct ttysize ts;
3447 int fd = 1;
3448
3449 /* When stdout is not a tty, use stdin for the ioctl(). */
3450 if (!isatty(fd) && isatty(read_cmd_fd))
3451 fd = read_cmd_fd;
3452 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3453 {
3454 columns = ts.ts_cols;
3455 rows = ts.ts_lines;
3456 }
3457 }
3458# endif /* TIOCGSIZE */
3459# endif /* TIOCGWINSZ */
3460
3461 /*
3462 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003463 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3464 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003465 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003466 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003467 {
3468 if ((p = (char_u *)getenv("LINES")))
3469 rows = atoi((char *)p);
3470 if ((p = (char_u *)getenv("COLUMNS")))
3471 columns = atoi((char *)p);
3472 }
3473
3474#ifdef HAVE_TGETENT
3475 /*
3476 * 3. try reading "co" and "li" entries from termcap
3477 */
3478 if (columns == 0 || rows == 0)
3479 getlinecol(&columns, &rows);
3480#endif
3481
3482 /*
3483 * 4. If everything fails, use the old values
3484 */
3485 if (columns <= 0 || rows <= 0)
3486 return FAIL;
3487
3488 Rows = rows;
3489 Columns = columns;
3490 return OK;
3491}
3492
3493/*
3494 * Try to set the window size to Rows and Columns.
3495 */
3496 void
3497mch_set_shellsize()
3498{
3499 if (*T_CWS)
3500 {
3501 /*
3502 * NOTE: if you get an error here that term_set_winsize() is
3503 * undefined, check the output of configure. It could probably not
3504 * find a ncurses, termcap or termlib library.
3505 */
3506 term_set_winsize((int)Rows, (int)Columns);
3507 out_flush();
3508 screen_start(); /* don't know where cursor is now */
3509 }
3510}
3511
3512#endif /* VMS */
3513
3514/*
3515 * Rows and/or Columns has changed.
3516 */
3517 void
3518mch_new_shellsize()
3519{
3520 /* Nothing to do. */
3521}
3522
Bram Moolenaardf177f62005-02-22 08:39:57 +00003523#ifndef USE_SYSTEM
3524static void append_ga_line __ARGS((garray_T *gap));
3525
3526/*
3527 * Append the text in "gap" below the cursor line and clear "gap".
3528 */
3529 static void
3530append_ga_line(gap)
3531 garray_T *gap;
3532{
3533 /* Remove trailing CR. */
3534 if (gap->ga_len > 0
3535 && !curbuf->b_p_bin
3536 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3537 --gap->ga_len;
3538 ga_append(gap, NUL);
3539 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3540 gap->ga_len = 0;
3541}
3542#endif
3543
Bram Moolenaar071d4272004-06-13 20:20:40 +00003544 int
3545mch_call_shell(cmd, options)
3546 char_u *cmd;
3547 int options; /* SHELL_*, see vim.h */
3548{
3549#ifdef VMS
3550 char *ifn = NULL;
3551 char *ofn = NULL;
3552#endif
3553 int tmode = cur_tmode;
3554#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3555 int x;
3556# ifndef __EMX__
3557 char_u *newcmd; /* only needed for unix */
3558# else
3559 /*
3560 * Set the preferred shell in the EMXSHELL environment variable (but
3561 * only if it is different from what is already in the environment).
3562 * Emx then takes care of whether to use "/c" or "-c" in an
3563 * intelligent way. Simply pass the whole thing to emx's system() call.
3564 * Emx also starts an interactive shell if system() is passed an empty
3565 * string.
3566 */
3567 char_u *p, *old;
3568
3569 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3570 {
3571 /* should check HAVE_SETENV, but I know we don't have it. */
3572 p = alloc(10 + strlen(p_sh));
3573 if (p)
3574 {
3575 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3576 putenv((char *)p); /* don't free the pointer! */
3577 }
3578 }
3579# endif
3580
3581 out_flush();
3582
3583 if (options & SHELL_COOKED)
3584 settmode(TMODE_COOK); /* set to normal mode */
3585
3586# ifdef __EMX__
3587 if (cmd == NULL)
3588 x = system(""); /* this starts an interactive shell in emx */
3589 else
3590 x = system((char *)cmd);
3591 /* system() returns -1 when error occurs in starting shell */
3592 if (x == -1 && !emsg_silent)
3593 {
3594 MSG_PUTS(_("\nCannot execute shell "));
3595 msg_outtrans(p_sh);
3596 msg_putchar('\n');
3597 }
3598# else /* not __EMX__ */
3599 if (cmd == NULL)
3600 x = system((char *)p_sh);
3601 else
3602 {
3603# ifdef VMS
3604 if (ofn = strchr((char *)cmd, '>'))
3605 *ofn++ = '\0';
3606 if (ifn = strchr((char *)cmd, '<'))
3607 {
3608 char *p;
3609
3610 *ifn++ = '\0';
3611 p = strchr(ifn,' '); /* chop off any trailing spaces */
3612 if (p)
3613 *p = '\0';
3614 }
3615 if (ofn)
3616 x = vms_sys((char *)cmd, ofn, ifn);
3617 else
3618 x = system((char *)cmd);
3619# else
3620 newcmd = lalloc(STRLEN(p_sh)
3621 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3622 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3623 if (newcmd == NULL)
3624 x = 0;
3625 else
3626 {
3627 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3628 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3629 (char *)p_shcf,
3630 (char *)cmd);
3631 x = system((char *)newcmd);
3632 vim_free(newcmd);
3633 }
3634# endif
3635 }
3636# ifdef VMS
3637 x = vms_sys_status(x);
3638# endif
3639 if (emsg_silent)
3640 ;
3641 else if (x == 127)
3642 MSG_PUTS(_("\nCannot execute shell sh\n"));
3643# endif /* __EMX__ */
3644 else if (x && !(options & SHELL_SILENT))
3645 {
3646 MSG_PUTS(_("\nshell returned "));
3647 msg_outnum((long)x);
3648 msg_putchar('\n');
3649 }
3650
3651 if (tmode == TMODE_RAW)
3652 settmode(TMODE_RAW); /* set to raw mode */
3653# ifdef FEAT_TITLE
3654 resettitle();
3655# endif
3656 return x;
3657
3658#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3659
Bram Moolenaardf177f62005-02-22 08:39:57 +00003660# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3661 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003662
3663 char_u *newcmd = NULL;
3664 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003665 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003666 pid_t wait_pid = 0;
3667# ifdef HAVE_UNION_WAIT
3668 union wait status;
3669# else
3670 int status = -1;
3671# endif
3672 int retval = -1;
3673 char **argv = NULL;
3674 int argc;
3675 int i;
3676 char_u *p;
3677 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003678 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003679# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680 int pty_slave_fd = -1;
3681 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003682# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003683 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003684 int fd_fromshell[2];
3685 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003686# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003687 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003688# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 static char envbuf_Rows[20];
3690 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003691# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003692 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693
3694 out_flush();
3695 if (options & SHELL_COOKED)
3696 settmode(TMODE_COOK); /* set to normal mode */
3697
Bram Moolenaar071d4272004-06-13 20:20:40 +00003698 newcmd = vim_strsave(p_sh);
3699 if (newcmd == NULL) /* out of memory */
3700 goto error;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003701
3702 /*
3703 * Do this loop twice:
3704 * 1: find number of arguments
3705 * 2: separate them and build argv[]
3706 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003707 for (i = 0; i < 2; ++i)
3708 {
3709 p = newcmd;
3710 inquote = FALSE;
3711 argc = 0;
3712 for (;;)
3713 {
3714 if (i == 1)
3715 argv[argc] = (char *)p;
3716 ++argc;
3717 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3718 {
3719 if (*p == '"')
3720 inquote = !inquote;
3721 ++p;
3722 }
3723 if (*p == NUL)
3724 break;
3725 if (i == 1)
3726 *p++ = NUL;
3727 p = skipwhite(p);
3728 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003729 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003730 {
3731 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3732 if (argv == NULL) /* out of memory */
3733 goto error;
3734 }
3735 }
3736 if (cmd != NULL)
3737 {
3738 if (extra_shell_arg != NULL)
3739 argv[argc++] = (char *)extra_shell_arg;
3740 argv[argc++] = (char *)p_shcf;
3741 argv[argc++] = (char *)cmd;
3742 }
3743 argv[argc] = NULL;
3744
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003746 * For the GUI, when writing the output into the buffer and when reading
3747 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3748 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003749 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003750 if ((options & (SHELL_READ|SHELL_WRITE))
3751# ifdef FEAT_GUI
3752 || (gui.in_use && show_shell_mess)
3753# endif
3754 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003756# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003757 /*
3758 * Try to open a master pty.
3759 * If this works, open the slave pty.
3760 * If the slave can't be opened, close the master pty.
3761 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003762 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003763 {
3764 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3765 if (pty_master_fd >= 0 && ((pty_slave_fd =
3766 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3767 {
3768 close(pty_master_fd);
3769 pty_master_fd = -1;
3770 }
3771 }
3772 /*
3773 * If not opening a pty or it didn't work, try using pipes.
3774 */
3775 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003776# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777 {
3778 pipe_error = (pipe(fd_toshell) < 0);
3779 if (!pipe_error) /* pipe create OK */
3780 {
3781 pipe_error = (pipe(fd_fromshell) < 0);
3782 if (pipe_error) /* pipe create failed */
3783 {
3784 close(fd_toshell[0]);
3785 close(fd_toshell[1]);
3786 }
3787 }
3788 if (pipe_error)
3789 {
3790 MSG_PUTS(_("\nCannot create pipes\n"));
3791 out_flush();
3792 }
3793 }
3794 }
3795
3796 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003797 {
3798# ifdef __BEOS__
3799 beos_cleanup_read_thread();
3800# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003801
Bram Moolenaar071d4272004-06-13 20:20:40 +00003802 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3803 {
3804 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003805 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003806# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003807 || (gui.in_use && show_shell_mess)
3808# endif
3809 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003810 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003811# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812 if (pty_master_fd >= 0) /* close the pseudo tty */
3813 {
3814 close(pty_master_fd);
3815 close(pty_slave_fd);
3816 }
3817 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003818# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819 {
3820 close(fd_toshell[0]);
3821 close(fd_toshell[1]);
3822 close(fd_fromshell[0]);
3823 close(fd_fromshell[1]);
3824 }
3825 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826 }
3827 else if (pid == 0) /* child */
3828 {
3829 reset_signals(); /* handle signals normally */
3830
3831 if (!show_shell_mess || (options & SHELL_EXPAND))
3832 {
3833 int fd;
3834
3835 /*
3836 * Don't want to show any message from the shell. Can't just
3837 * close stdout and stderr though, because some systems will
3838 * break if you try to write to them after that, so we must
3839 * use dup() to replace them with something else -- webb
3840 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3841 * waiting for input.
3842 */
3843 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3844 fclose(stdin);
3845 fclose(stdout);
3846 fclose(stderr);
3847
3848 /*
3849 * If any of these open()'s and dup()'s fail, we just continue
3850 * anyway. It's not fatal, and on most systems it will make
3851 * no difference at all. On a few it will cause the execvp()
3852 * to exit with a non-zero status even when the completion
3853 * could be done, which is nothing too serious. If the open()
3854 * or dup() failed we'd just do the same thing ourselves
3855 * anyway -- webb
3856 */
3857 if (fd >= 0)
3858 {
3859 dup(fd); /* To replace stdin (file descriptor 0) */
3860 dup(fd); /* To replace stdout (file descriptor 1) */
3861 dup(fd); /* To replace stderr (file descriptor 2) */
3862
3863 /* Don't need this now that we've duplicated it */
3864 close(fd);
3865 }
3866 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003867 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003868# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003869 || gui.in_use
3870# endif
3871 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003872 {
3873
Bram Moolenaardf177f62005-02-22 08:39:57 +00003874# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003875 /* Create our own process group, so that the child and all its
3876 * children can be kill()ed. Don't do this when using pipes,
3877 * because stdin is not a tty, we would loose /dev/tty. */
3878 if (p_stmp)
3879 (void)setsid();
Bram Moolenaardf177f62005-02-22 08:39:57 +00003880# endif
3881# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003882 if (pty_slave_fd >= 0)
3883 {
3884 /* push stream discipline modules */
3885 if (options & SHELL_COOKED)
3886 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003887# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003888 /* Try to become controlling tty (probably doesn't work,
3889 * unless run by root) */
3890 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003891# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003892 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003893# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003894 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003895# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003896 setenv("TERM", "dumb", 1);
3897 sprintf((char *)envbuf, "%ld", Rows);
3898 setenv("ROWS", (char *)envbuf, 1);
3899 sprintf((char *)envbuf, "%ld", Rows);
3900 setenv("LINES", (char *)envbuf, 1);
3901 sprintf((char *)envbuf, "%ld", Columns);
3902 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003903# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003904 /*
3905 * Putenv does not copy the string, it has to remain valid.
3906 * Use a static array to avoid loosing allocated memory.
3907 */
3908 putenv("TERM=dumb");
3909 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
3910 putenv(envbuf_Rows);
3911 sprintf(envbuf_Rows, "LINES=%ld", Rows);
3912 putenv(envbuf_Rows);
3913 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
3914 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003915# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003916
Bram Moolenaara5792f52005-11-23 21:25:05 +00003917 /*
3918 * stderr is only redirected when using the GUI, so that a
3919 * program like gpg can still access the terminal to get a
3920 * passphrase using stderr.
3921 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003922# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003923 if (pty_master_fd >= 0)
3924 {
3925 close(pty_master_fd); /* close master side of pty */
3926
3927 /* set up stdin/stdout/stderr for the child */
3928 close(0);
3929 dup(pty_slave_fd);
3930 close(1);
3931 dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003932 if (gui.in_use)
3933 {
3934 close(2);
3935 dup(pty_slave_fd);
3936 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003937
3938 close(pty_slave_fd); /* has been dupped, close it now */
3939 }
3940 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003941# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003942 {
3943 /* set up stdin for the child */
3944 close(fd_toshell[1]);
3945 close(0);
3946 dup(fd_toshell[0]);
3947 close(fd_toshell[0]);
3948
3949 /* set up stdout for the child */
3950 close(fd_fromshell[0]);
3951 close(1);
3952 dup(fd_fromshell[1]);
3953 close(fd_fromshell[1]);
3954
Bram Moolenaara5792f52005-11-23 21:25:05 +00003955# ifdef FEAT_GUI
3956 if (gui.in_use)
3957 {
3958 /* set up stderr for the child */
3959 close(2);
3960 dup(1);
3961 }
3962# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003963 }
3964 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003965
Bram Moolenaar071d4272004-06-13 20:20:40 +00003966 /*
3967 * There is no type cast for the argv, because the type may be
3968 * different on different machines. This may cause a warning
3969 * message with strict compilers, don't worry about it.
3970 * Call _exit() instead of exit() to avoid closing the connection
3971 * to the X server (esp. with GTK, which uses atexit()).
3972 */
3973 execvp(argv[0], argv);
3974 _exit(EXEC_FAILED); /* exec failed, return failure code */
3975 }
3976 else /* parent */
3977 {
3978 /*
3979 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003980 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003981 */
3982 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003983 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003984
3985 /*
3986 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003987 * This is also used to pipe stdin/stdout to/from the external
3988 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003989 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003990 if ((options & (SHELL_READ|SHELL_WRITE))
3991# ifdef FEAT_GUI
3992 || (gui.in_use && show_shell_mess)
3993# endif
3994 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003996# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003997 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003998# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003999 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004000# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004001 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4002 int ta_len = 0; /* valid bytes in ta_buf[] */
4003 int len;
4004 int p_more_save;
4005 int old_State;
4006 int c;
4007 int toshell_fd;
4008 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004009 garray_T ga;
4010 int noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004011
Bram Moolenaardf177f62005-02-22 08:39:57 +00004012# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013 if (pty_master_fd >= 0)
4014 {
4015 close(pty_slave_fd); /* close slave side of pty */
4016 fromshell_fd = pty_master_fd;
4017 toshell_fd = dup(pty_master_fd);
4018 }
4019 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004020# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004021 {
4022 close(fd_toshell[0]);
4023 close(fd_fromshell[1]);
4024 toshell_fd = fd_toshell[1];
4025 fromshell_fd = fd_fromshell[0];
4026 }
4027
4028 /*
4029 * Write to the child if there are typed characters.
4030 * Read from the child if there are characters available.
4031 * Repeat the reading a few times if more characters are
4032 * available. Need to check for typed keys now and then, but
4033 * not too often (delays when no chars are available).
4034 * This loop is quit if no characters can be read from the pty
4035 * (WaitForChar detected special condition), or there are no
4036 * characters available and the child has exited.
4037 * Only check if the child has exited when there is no more
4038 * output. The child may exit before all the output has
4039 * been printed.
4040 *
4041 * Currently this busy loops!
4042 * This can probably dead-lock when the write blocks!
4043 */
4044 p_more_save = p_more;
4045 p_more = FALSE;
4046 old_State = State;
4047 State = EXTERNCMD; /* don't redraw at window resize */
4048
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004049 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004050 {
4051 /* Fork a process that will write the lines to the
4052 * external program. */
4053 if ((wpid = fork()) == -1)
4054 {
4055 MSG_PUTS(_("\nCannot fork\n"));
4056 }
4057 else if (wpid == 0)
4058 {
4059 linenr_T lnum = curbuf->b_op_start.lnum;
4060 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004061 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004062 char_u *s;
4063 size_t l;
4064
4065 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004066 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004067 for (;;)
4068 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004069 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004070 if (l == 0)
4071 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004072 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004073 /* NL -> NUL translation */
4074 len = write(toshell_fd, "", (size_t)1);
4075 else
4076 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004077 s = vim_strchr(lp + written, NL);
4078 len = write(toshell_fd, (char *)lp + written,
4079 s == NULL ? l : s - (lp + written));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004080 }
4081 if (len == l)
4082 {
4083 /* Finished a line, add a NL, unless this line
4084 * should not have one. */
4085 if (lnum != curbuf->b_op_end.lnum
4086 || !curbuf->b_p_bin
4087 || (lnum != write_no_eol_lnum
4088 && (lnum !=
4089 curbuf->b_ml.ml_line_count
4090 || curbuf->b_p_eol)))
4091 write(toshell_fd, "\n", (size_t)1);
4092 ++lnum;
4093 if (lnum > curbuf->b_op_end.lnum)
4094 {
4095 /* finished all the lines, close pipe */
4096 close(toshell_fd);
4097 toshell_fd = -1;
4098 break;
4099 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004100 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004101 written = 0;
4102 }
4103 else if (len > 0)
4104 written += len;
4105 }
4106 _exit(0);
4107 }
4108 else
4109 {
4110 close(toshell_fd);
4111 toshell_fd = -1;
4112 }
4113 }
4114
4115 if (options & SHELL_READ)
4116 ga_init2(&ga, 1, BUFLEN);
4117
4118 noread_cnt = 0;
4119
Bram Moolenaar071d4272004-06-13 20:20:40 +00004120 for (;;)
4121 {
4122 /*
4123 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004124 * if there are any.
4125 * Don't do this if we are expanding wild cards (would eat
4126 * typeahead).
4127 * Don't do this when filtering and terminal is in cooked
4128 * mode, the shell command will handle the I/O. Avoids
4129 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004130 * Don't get characters when the child has already
4131 * finished (wait_pid == 0).
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004132 * Don't get extra characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004133 * Don't read characters unless we didn't get output for a
4134 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135 */
4136 len = 0;
4137 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004138 && ((options &
4139 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4140 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
4141#ifdef FEAT_GUI
4142 || gui.in_use
4143#endif
4144 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004145 && wait_pid == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004146 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00004147 || (noread_cnt > 4
4148 && (len = ui_inchar(ta_buf,
4149 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150 {
4151 /*
4152 * For pipes:
4153 * Check for CTRL-C: send interrupt signal to child.
4154 * Check for CTRL-D: EOF, close pipe to child.
4155 */
4156 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4157 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004158# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159 /*
4160 * Send SIGINT to the child's group or all
4161 * processes in our group.
4162 */
4163 if (ta_buf[ta_len] == Ctrl_C
4164 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004165 {
4166# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004168# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004170# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004171 if (wpid > 0)
4172 kill(wpid, SIGINT);
4173 }
4174# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175 if (pty_master_fd < 0 && toshell_fd >= 0
4176 && ta_buf[ta_len] == Ctrl_D)
4177 {
4178 close(toshell_fd);
4179 toshell_fd = -1;
4180 }
4181 }
4182
4183 /* replace K_BS by <BS> and K_DEL by <DEL> */
4184 for (i = ta_len; i < ta_len + len; ++i)
4185 {
4186 if (ta_buf[i] == CSI && len - i > 2)
4187 {
4188 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4189 if (c == K_DEL || c == K_KDEL || c == K_BS)
4190 {
4191 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4192 (size_t)(len - i - 2));
4193 if (c == K_DEL || c == K_KDEL)
4194 ta_buf[i] = DEL;
4195 else
4196 ta_buf[i] = Ctrl_H;
4197 len -= 2;
4198 }
4199 }
4200 else if (ta_buf[i] == '\r')
4201 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004202# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004203 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004204 i += (*mb_ptr2len)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004205# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004206 }
4207
4208 /*
4209 * For pipes: echo the typed characters.
4210 * For a pty this does not seem to work.
4211 */
4212 if (pty_master_fd < 0)
4213 {
4214 for (i = ta_len; i < ta_len + len; ++i)
4215 {
4216 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4217 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004218# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219 else if (has_mbyte)
4220 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004221 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004222
4223 msg_outtrans_len(ta_buf + i, l);
4224 i += l - 1;
4225 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004226# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004227 else
4228 msg_outtrans_len(ta_buf + i, 1);
4229 }
4230 windgoto(msg_row, msg_col);
4231 out_flush();
4232 }
4233
4234 ta_len += len;
4235
4236 /*
4237 * Write the characters to the child, unless EOF has
4238 * been typed for pipes. Write one character at a
4239 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004240 * When writing buffer lines, drop the typed
4241 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004242 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004243 if (options & SHELL_WRITE)
4244 ta_len = 0;
4245 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004246 {
4247 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4248 if (len > 0)
4249 {
4250 ta_len -= len;
4251 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004252 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004253 }
4254 }
4255 }
4256
Bram Moolenaardf177f62005-02-22 08:39:57 +00004257 if (got_int)
4258 {
4259 /* CTRL-C sends a signal to the child, we ignore it
4260 * ourselves */
4261# ifdef HAVE_SETSID
4262 kill(-pid, SIGINT);
4263# else
4264 kill(0, SIGINT);
4265# endif
4266 if (wpid > 0)
4267 kill(wpid, SIGINT);
4268 got_int = FALSE;
4269 }
4270
Bram Moolenaar071d4272004-06-13 20:20:40 +00004271 /*
4272 * Check if the child has any characters to be printed.
4273 * Read them and write them to our window. Repeat this as
4274 * long as there is something to do, avoid the 10ms wait
4275 * for mch_inchar(), or sending typeahead characters to
4276 * the external process.
4277 * TODO: This should handle escape sequences, compatible
4278 * to some terminal (vt52?).
4279 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004280 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004281 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4282 {
4283 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004284# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004285 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004286# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004287 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004288# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289 );
4290 if (len <= 0) /* end of file or error */
4291 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004292
4293 noread_cnt = 0;
4294 if (options & SHELL_READ)
4295 {
4296 /* Do NUL -> NL translation, append NL separated
4297 * lines to the current buffer. */
4298 for (i = 0; i < len; ++i)
4299 {
4300 if (buffer[i] == NL)
4301 append_ga_line(&ga);
4302 else if (buffer[i] == NUL)
4303 ga_append(&ga, NL);
4304 else
4305 ga_append(&ga, buffer[i]);
4306 }
4307 }
4308# ifdef FEAT_MBYTE
4309 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004310 {
4311 int l;
4312
Bram Moolenaardf177f62005-02-22 08:39:57 +00004313 len += buffer_off;
4314 buffer[len] = NUL;
4315
Bram Moolenaar071d4272004-06-13 20:20:40 +00004316 /* Check if the last character in buffer[] is
4317 * incomplete, keep these bytes for the next
4318 * round. */
4319 for (p = buffer; p < buffer + len; p += l)
4320 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004321 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004322 if (l == 0)
4323 l = 1; /* NUL byte? */
4324 else if (MB_BYTE2LEN(*p) != l)
4325 break;
4326 }
4327 if (p == buffer) /* no complete character */
4328 {
4329 /* avoid getting stuck at an illegal byte */
4330 if (len >= 12)
4331 ++p;
4332 else
4333 {
4334 buffer_off = len;
4335 continue;
4336 }
4337 }
4338 c = *p;
4339 *p = NUL;
4340 msg_puts(buffer);
4341 if (p < buffer + len)
4342 {
4343 *p = c;
4344 buffer_off = (buffer + len) - p;
4345 mch_memmove(buffer, p, buffer_off);
4346 continue;
4347 }
4348 buffer_off = 0;
4349 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004350# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004351 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004352 {
4353 buffer[len] = NUL;
4354 msg_puts(buffer);
4355 }
4356
4357 windgoto(msg_row, msg_col);
4358 cursor_on();
4359 out_flush();
4360 if (got_int)
4361 break;
4362 }
4363
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004364 /* If we already detected the child has finished break the
4365 * loop now. */
4366 if (wait_pid == pid)
4367 break;
4368
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 /*
4370 * Check if the child still exists, before checking for
4371 * typed characters (otherwise we would loose typeahead).
4372 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004373# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004375# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004376 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004377# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004378 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4379 || (wait_pid == pid && WIFEXITED(status)))
4380 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004381 /* Don't break the loop yet, try reading more
4382 * characters from "fromshell_fd" first. When using
4383 * pipes there might still be something to read and
4384 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004385 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004386 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004387 else
4388 wait_pid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004389 }
4390finished:
4391 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004392 if (options & SHELL_READ)
4393 {
4394 if (ga.ga_len > 0)
4395 {
4396 append_ga_line(&ga);
4397 /* remember that the NL was missing */
4398 write_no_eol_lnum = curwin->w_cursor.lnum;
4399 }
4400 else
4401 write_no_eol_lnum = 0;
4402 ga_clear(&ga);
4403 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004404
Bram Moolenaar071d4272004-06-13 20:20:40 +00004405 /*
4406 * Give all typeahead that wasn't used back to ui_inchar().
4407 */
4408 if (ta_len)
4409 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004410 State = old_State;
4411 if (toshell_fd >= 0)
4412 close(toshell_fd);
4413 close(fromshell_fd);
4414 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004415
4416 /*
4417 * Wait until our child has exited.
4418 * Ignore wait() returning pids of other children and returning
4419 * because of some signal like SIGWINCH.
4420 * Don't wait if wait_pid was already set above, indicating the
4421 * child already exited.
4422 */
4423 while (wait_pid != pid)
4424 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004425# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004426 /* Ugly hack: when compiled with Python threads are probably
4427 * used, in which case wait() sometimes hangs for no obvious
4428 * reason. Use waitpid() instead and loop (like the GUI). */
4429# ifdef __NeXT__
4430 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4431# else
4432 wait_pid = waitpid(pid, &status, WNOHANG);
4433# endif
4434 if (wait_pid == 0)
4435 {
4436 /* Wait for 1/100 sec before trying again. */
4437 mch_delay(10L, TRUE);
4438 continue;
4439 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004440# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004441 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004442# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004443 if (wait_pid <= 0
4444# ifdef ECHILD
4445 && errno == ECHILD
4446# endif
4447 )
4448 break;
4449 }
4450
Bram Moolenaardf177f62005-02-22 08:39:57 +00004451 /* Make sure the child that writes to the external program is
4452 * dead. */
4453 if (wpid > 0)
4454 kill(wpid, SIGKILL);
4455
Bram Moolenaar071d4272004-06-13 20:20:40 +00004456 /*
4457 * Set to raw mode right now, otherwise a CTRL-C after
4458 * catch_signals() will kill Vim.
4459 */
4460 if (tmode == TMODE_RAW)
4461 settmode(TMODE_RAW);
4462 did_settmode = TRUE;
4463 set_signals();
4464
4465 if (WIFEXITED(status))
4466 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004467 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004468 retval = WEXITSTATUS(status);
4469 if (retval && !emsg_silent)
4470 {
4471 if (retval == EXEC_FAILED)
4472 {
4473 MSG_PUTS(_("\nCannot execute shell "));
4474 msg_outtrans(p_sh);
4475 msg_putchar('\n');
4476 }
4477 else if (!(options & SHELL_SILENT))
4478 {
4479 MSG_PUTS(_("\nshell returned "));
4480 msg_outnum((long)retval);
4481 msg_putchar('\n');
4482 }
4483 }
4484 }
4485 else
4486 MSG_PUTS(_("\nCommand terminated\n"));
4487 }
4488 }
4489 vim_free(argv);
4490
4491error:
4492 if (!did_settmode)
4493 if (tmode == TMODE_RAW)
4494 settmode(TMODE_RAW); /* set to raw mode */
4495# ifdef FEAT_TITLE
4496 resettitle();
4497# endif
4498 vim_free(newcmd);
4499
4500 return retval;
4501
4502#endif /* USE_SYSTEM */
4503}
4504
4505/*
4506 * Check for CTRL-C typed by reading all available characters.
4507 * In cooked mode we should get SIGINT, no need to check.
4508 */
4509 void
4510mch_breakcheck()
4511{
4512 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4513 fill_input_buf(FALSE);
4514}
4515
4516/*
4517 * Wait "msec" msec until a character is available from the keyboard or from
4518 * inbuf[]. msec == -1 will block forever.
4519 * When a GUI is being used, this will never get called -- webb
4520 */
4521 static int
4522WaitForChar(msec)
4523 long msec;
4524{
4525#ifdef FEAT_MOUSE_GPM
4526 int gpm_process_wanted;
4527#endif
4528#ifdef FEAT_XCLIPBOARD
4529 int rest;
4530#endif
4531 int avail;
4532
4533 if (input_available()) /* something in inbuf[] */
4534 return 1;
4535
4536#if defined(FEAT_MOUSE_DEC)
4537 /* May need to query the mouse position. */
4538 if (WantQueryMouse)
4539 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004540 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004541 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4542 }
4543#endif
4544
4545 /*
4546 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4547 * events. This is a bit complicated, because they might both be defined.
4548 */
4549#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4550# ifdef FEAT_XCLIPBOARD
4551 rest = 0;
4552 if (do_xterm_trace())
4553 rest = msec;
4554# endif
4555 do
4556 {
4557# ifdef FEAT_XCLIPBOARD
4558 if (rest != 0)
4559 {
4560 msec = XT_TRACE_DELAY;
4561 if (rest >= 0 && rest < XT_TRACE_DELAY)
4562 msec = rest;
4563 if (rest >= 0)
4564 rest -= msec;
4565 }
4566# endif
4567# ifdef FEAT_MOUSE_GPM
4568 gpm_process_wanted = 0;
4569 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4570# else
4571 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4572# endif
4573 if (!avail)
4574 {
4575 if (input_available())
4576 return 1;
4577# ifdef FEAT_XCLIPBOARD
4578 if (rest == 0 || !do_xterm_trace())
4579# endif
4580 break;
4581 }
4582 }
4583 while (FALSE
4584# ifdef FEAT_MOUSE_GPM
4585 || (gpm_process_wanted && mch_gpm_process() == 0)
4586# endif
4587# ifdef FEAT_XCLIPBOARD
4588 || (!avail && rest != 0)
4589# endif
4590 );
4591
4592#else
4593 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4594#endif
4595 return avail;
4596}
4597
4598/*
4599 * Wait "msec" msec until a character is available from file descriptor "fd".
4600 * Time == -1 will block forever.
4601 * When a GUI is being used, this will not be used for input -- webb
4602 * Returns also, when a request from Sniff is waiting -- toni.
4603 * Or when a Linux GPM mouse event is waiting.
4604 */
4605/* ARGSUSED */
4606#if defined(__BEOS__)
4607 int
4608#else
4609 static int
4610#endif
4611RealWaitForChar(fd, msec, check_for_gpm)
4612 int fd;
4613 long msec;
4614 int *check_for_gpm;
4615{
4616 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004617#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004618 static int busy = FALSE;
4619
4620 /* May retry getting characters after an event was handled. */
4621# define MAY_LOOP
4622
4623# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4624 /* Remember at what time we started, so that we know how much longer we
4625 * should wait after being interrupted. */
4626# define USE_START_TV
4627 struct timeval start_tv;
4628
4629 if (msec > 0 && (
4630# ifdef FEAT_XCLIPBOARD
4631 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004632# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004633 ||
4634# endif
4635# endif
4636# ifdef USE_XSMP
4637 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004638# ifdef FEAT_MZSCHEME
4639 ||
4640# endif
4641# endif
4642# ifdef FEAT_MZSCHEME
4643 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004644# endif
4645 ))
4646 gettimeofday(&start_tv, NULL);
4647# endif
4648
4649 /* Handle being called recursively. This may happen for the session
4650 * manager stuff, it may save the file, which does a breakcheck. */
4651 if (busy)
4652 return 0;
4653#endif
4654
4655#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00004656 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657#endif
4658 {
4659#ifdef MAY_LOOP
4660 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004661# ifdef FEAT_MZSCHEME
4662 int mzquantum_used = FALSE;
4663# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004664#endif
4665#ifndef HAVE_SELECT
4666 struct pollfd fds[5];
4667 int nfd;
4668# ifdef FEAT_XCLIPBOARD
4669 int xterm_idx = -1;
4670# endif
4671# ifdef FEAT_MOUSE_GPM
4672 int gpm_idx = -1;
4673# endif
4674# ifdef USE_XSMP
4675 int xsmp_idx = -1;
4676# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004677 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004678
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004679# ifdef FEAT_MZSCHEME
4680 mzvim_check_threads();
4681 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4682 {
4683 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4684 mzquantum_used = TRUE;
4685 }
4686# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004687 fds[0].fd = fd;
4688 fds[0].events = POLLIN;
4689 nfd = 1;
4690
4691# ifdef FEAT_SNIFF
4692# define SNIFF_IDX 1
4693 if (want_sniff_request)
4694 {
4695 fds[SNIFF_IDX].fd = fd_from_sniff;
4696 fds[SNIFF_IDX].events = POLLIN;
4697 nfd++;
4698 }
4699# endif
4700# ifdef FEAT_XCLIPBOARD
4701 if (xterm_Shell != (Widget)0)
4702 {
4703 xterm_idx = nfd;
4704 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4705 fds[nfd].events = POLLIN;
4706 nfd++;
4707 }
4708# endif
4709# ifdef FEAT_MOUSE_GPM
4710 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4711 {
4712 gpm_idx = nfd;
4713 fds[nfd].fd = gpm_fd;
4714 fds[nfd].events = POLLIN;
4715 nfd++;
4716 }
4717# endif
4718# ifdef USE_XSMP
4719 if (xsmp_icefd != -1)
4720 {
4721 xsmp_idx = nfd;
4722 fds[nfd].fd = xsmp_icefd;
4723 fds[nfd].events = POLLIN;
4724 nfd++;
4725 }
4726# endif
4727
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004728 ret = poll(fds, nfd, towait);
4729# ifdef FEAT_MZSCHEME
4730 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00004731 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004732 finished = FALSE;
4733# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004734
4735# ifdef FEAT_SNIFF
4736 if (ret < 0)
4737 sniff_disconnect(1);
4738 else if (want_sniff_request)
4739 {
4740 if (fds[SNIFF_IDX].revents & POLLHUP)
4741 sniff_disconnect(1);
4742 if (fds[SNIFF_IDX].revents & POLLIN)
4743 sniff_request_waiting = 1;
4744 }
4745# endif
4746# ifdef FEAT_XCLIPBOARD
4747 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4748 {
4749 xterm_update(); /* Maybe we should hand out clipboard */
4750 if (--ret == 0 && !input_available())
4751 /* Try again */
4752 finished = FALSE;
4753 }
4754# endif
4755# ifdef FEAT_MOUSE_GPM
4756 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4757 {
4758 *check_for_gpm = 1;
4759 }
4760# endif
4761# ifdef USE_XSMP
4762 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4763 {
4764 if (fds[xsmp_idx].revents & POLLIN)
4765 {
4766 busy = TRUE;
4767 xsmp_handle_requests();
4768 busy = FALSE;
4769 }
4770 else if (fds[xsmp_idx].revents & POLLHUP)
4771 {
4772 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004773 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004774 xsmp_close();
4775 }
4776 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004777 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004778 }
4779# endif
4780
4781
4782#else /* HAVE_SELECT */
4783
4784 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004785 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004786 fd_set rfds, efds;
4787 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004788 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004789
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004790# ifdef FEAT_MZSCHEME
4791 mzvim_check_threads();
4792 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4793 {
4794 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4795 mzquantum_used = TRUE;
4796 }
4797# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004798# ifdef __EMX__
4799 /* don't check for incoming chars if not in raw mode, because select()
4800 * always returns TRUE then (in some version of emx.dll) */
4801 if (curr_tmode != TMODE_RAW)
4802 return 0;
4803# endif
4804
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004805 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004806 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004807 tv.tv_sec = towait / 1000;
4808 tv.tv_usec = (towait % 1000) * (1000000/1000);
4809 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004810 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004811 else
4812 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004813
4814 /*
4815 * Select on ready for reading and exceptional condition (end of file).
4816 */
4817 FD_ZERO(&rfds); /* calls bzero() on a sun */
4818 FD_ZERO(&efds);
4819 FD_SET(fd, &rfds);
4820# if !defined(__QNX__) && !defined(__CYGWIN32__)
4821 /* For QNX select() always returns 1 if this is set. Why? */
4822 FD_SET(fd, &efds);
4823# endif
4824 maxfd = fd;
4825
4826# ifdef FEAT_SNIFF
4827 if (want_sniff_request)
4828 {
4829 FD_SET(fd_from_sniff, &rfds);
4830 FD_SET(fd_from_sniff, &efds);
4831 if (maxfd < fd_from_sniff)
4832 maxfd = fd_from_sniff;
4833 }
4834# endif
4835# ifdef FEAT_XCLIPBOARD
4836 if (xterm_Shell != (Widget)0)
4837 {
4838 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4839 if (maxfd < ConnectionNumber(xterm_dpy))
4840 maxfd = ConnectionNumber(xterm_dpy);
4841 }
4842# endif
4843# ifdef FEAT_MOUSE_GPM
4844 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4845 {
4846 FD_SET(gpm_fd, &rfds);
4847 FD_SET(gpm_fd, &efds);
4848 if (maxfd < gpm_fd)
4849 maxfd = gpm_fd;
4850 }
4851# endif
4852# ifdef USE_XSMP
4853 if (xsmp_icefd != -1)
4854 {
4855 FD_SET(xsmp_icefd, &rfds);
4856 FD_SET(xsmp_icefd, &efds);
4857 if (maxfd < xsmp_icefd)
4858 maxfd = xsmp_icefd;
4859 }
4860# endif
4861
4862# ifdef OLD_VMS
4863 /* Old VMS as v6.2 and older have broken select(). It waits more than
4864 * required. Should not be used */
4865 ret = 0;
4866# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004867 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4868# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00004869# ifdef __TANDEM
4870 if (ret == -1 && errno == ENOTSUP)
4871 {
4872 FD_ZERO(&rfds);
4873 FD_ZERO(&efds);
4874 ret = 0;
4875 }
4876#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004877# ifdef FEAT_MZSCHEME
4878 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00004879 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004880 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004881# endif
4882
4883# ifdef FEAT_SNIFF
4884 if (ret < 0 )
4885 sniff_disconnect(1);
4886 else if (ret > 0 && want_sniff_request)
4887 {
4888 if (FD_ISSET(fd_from_sniff, &efds))
4889 sniff_disconnect(1);
4890 if (FD_ISSET(fd_from_sniff, &rfds))
4891 sniff_request_waiting = 1;
4892 }
4893# endif
4894# ifdef FEAT_XCLIPBOARD
4895 if (ret > 0 && xterm_Shell != (Widget)0
4896 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4897 {
4898 xterm_update(); /* Maybe we should hand out clipboard */
4899 /* continue looping when we only got the X event and the input
4900 * buffer is empty */
4901 if (--ret == 0 && !input_available())
4902 {
4903 /* Try again */
4904 finished = FALSE;
4905 }
4906 }
4907# endif
4908# ifdef FEAT_MOUSE_GPM
4909 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4910 {
4911 if (FD_ISSET(gpm_fd, &efds))
4912 gpm_close();
4913 else if (FD_ISSET(gpm_fd, &rfds))
4914 *check_for_gpm = 1;
4915 }
4916# endif
4917# ifdef USE_XSMP
4918 if (ret > 0 && xsmp_icefd != -1)
4919 {
4920 if (FD_ISSET(xsmp_icefd, &efds))
4921 {
4922 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004923 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004924 xsmp_close();
4925 if (--ret == 0)
4926 finished = FALSE; /* keep going if event was only one */
4927 }
4928 else if (FD_ISSET(xsmp_icefd, &rfds))
4929 {
4930 busy = TRUE;
4931 xsmp_handle_requests();
4932 busy = FALSE;
4933 if (--ret == 0)
4934 finished = FALSE; /* keep going if event was only one */
4935 }
4936 }
4937# endif
4938
4939#endif /* HAVE_SELECT */
4940
4941#ifdef MAY_LOOP
4942 if (finished || msec == 0)
4943 break;
4944
4945 /* We're going to loop around again, find out for how long */
4946 if (msec > 0)
4947 {
4948# ifdef USE_START_TV
4949 struct timeval mtv;
4950
4951 /* Compute remaining wait time. */
4952 gettimeofday(&mtv, NULL);
4953 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
4954 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
4955# else
4956 /* Guess we got interrupted halfway. */
4957 msec = msec / 2;
4958# endif
4959 if (msec <= 0)
4960 break; /* waited long enough */
4961 }
4962#endif
4963 }
4964
4965 return (ret > 0);
4966}
4967
4968#ifndef VMS
4969
4970#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004971/*
Bram Moolenaar02743632005-07-25 20:42:36 +00004972 * Expand a path into all matching files and/or directories. Handles "*",
4973 * "?", "[a-z]", "**", etc.
4974 * "path" has backslashes before chars that are not to be expanded.
4975 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004976 */
4977 int
4978mch_expandpath(gap, path, flags)
4979 garray_T *gap;
4980 char_u *path;
4981 int flags; /* EW_* flags */
4982{
Bram Moolenaar02743632005-07-25 20:42:36 +00004983 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004984}
4985#endif
4986
4987/*
4988 * mch_expand_wildcards() - this code does wild-card pattern matching using
4989 * the shell
4990 *
4991 * return OK for success, FAIL for error (you may lose some memory) and put
4992 * an error message in *file.
4993 *
4994 * num_pat is number of input patterns
4995 * pat is array of pointers to input patterns
4996 * num_file is pointer to number of matched file names
4997 * file is pointer to array of pointers to matched file names
4998 */
4999
5000#ifndef SEEK_SET
5001# define SEEK_SET 0
5002#endif
5003#ifndef SEEK_END
5004# define SEEK_END 2
5005#endif
5006
Bram Moolenaar5555acc2006-04-07 21:33:12 +00005007#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00005008
Bram Moolenaar071d4272004-06-13 20:20:40 +00005009/* ARGSUSED */
5010 int
5011mch_expand_wildcards(num_pat, pat, num_file, file, flags)
5012 int num_pat;
5013 char_u **pat;
5014 int *num_file;
5015 char_u ***file;
5016 int flags; /* EW_* flags */
5017{
5018 int i;
5019 size_t len;
5020 char_u *p;
5021 int dir;
5022#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00005023 /*
5024 * This is the OS/2 implementation.
5025 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005026# define EXPL_ALLOC_INC 16
5027 char_u **expl_files;
5028 size_t files_alloced, files_free;
5029 char_u *buf;
5030 int has_wildcard;
5031
5032 *num_file = 0; /* default: no files found */
5033 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
5034 files_free = EXPL_ALLOC_INC; /* how much space is not used */
5035 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
5036 if (*file == NULL)
5037 return FAIL;
5038
5039 for (; num_pat > 0; num_pat--, pat++)
5040 {
5041 expl_files = NULL;
5042 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
5043 /* expand environment var or home dir */
5044 buf = expand_env_save(*pat);
5045 else
5046 buf = vim_strsave(*pat);
5047 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005048 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049 if (has_wildcard) /* yes, so expand them */
5050 expl_files = (char_u **)_fnexplode(buf);
5051
5052 /*
5053 * return value of buf if no wildcards left,
5054 * OR if no match AND EW_NOTFOUND is set.
5055 */
5056 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
5057 || (expl_files == NULL && (flags & EW_NOTFOUND)))
5058 { /* simply save the current contents of *buf */
5059 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
5060 if (expl_files != NULL)
5061 {
5062 expl_files[0] = vim_strsave(buf);
5063 expl_files[1] = NULL;
5064 }
5065 }
5066 vim_free(buf);
5067
5068 /*
5069 * Count number of names resulting from expansion,
5070 * At the same time add a backslash to the end of names that happen to
5071 * be directories, and replace slashes with backslashes.
5072 */
5073 if (expl_files)
5074 {
5075 for (i = 0; (p = expl_files[i]) != NULL; i++)
5076 {
5077 dir = mch_isdir(p);
5078 /* If we don't want dirs and this is one, skip it */
5079 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5080 continue;
5081
Bram Moolenaara2031822006-03-07 22:29:51 +00005082 /* Skip files that are not executable if we check for that. */
5083 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
5084 continue;
5085
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086 if (--files_free == 0)
5087 {
5088 /* need more room in table of pointers */
5089 files_alloced += EXPL_ALLOC_INC;
5090 *file = (char_u **)vim_realloc(*file,
5091 sizeof(char_u **) * files_alloced);
5092 if (*file == NULL)
5093 {
5094 EMSG(_(e_outofmem));
5095 *num_file = 0;
5096 return FAIL;
5097 }
5098 files_free = EXPL_ALLOC_INC;
5099 }
5100 slash_adjust(p);
5101 if (dir)
5102 {
5103 /* For a directory we add a '/', unless it's already
5104 * there. */
5105 len = STRLEN(p);
5106 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5107 {
5108 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005109 if (!after_pathsep((*file)[*num_file],
5110 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005111 {
5112 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005113 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005114 }
5115 }
5116 }
5117 else
5118 {
5119 (*file)[*num_file] = vim_strsave(p);
5120 }
5121
5122 /*
5123 * Error message already given by either alloc or vim_strsave.
5124 * Should return FAIL, but returning OK works also.
5125 */
5126 if ((*file)[*num_file] == NULL)
5127 break;
5128 (*num_file)++;
5129 }
5130 _fnexplodefree((char **)expl_files);
5131 }
5132 }
5133 return OK;
5134
5135#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005136 /*
5137 * This is the non-OS/2 implementation (really Unix).
5138 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005139 int j;
5140 char_u *tempname;
5141 char_u *command;
5142 FILE *fd;
5143 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005144#define STYLE_ECHO 0 /* use "echo", the default */
5145#define STYLE_GLOB 1 /* use "glob", for csh */
5146#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5147#define STYLE_PRINT 3 /* use "print -N", for zsh */
5148#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5149 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005150 int shell_style = STYLE_ECHO;
5151 int check_spaces;
5152 static int did_find_nul = FALSE;
5153 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005154 /* vimglob() function to define for Posix shell */
5155 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo -n \"$1\"; echo; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005156
5157 *num_file = 0; /* default: no files found */
5158 *file = NULL;
5159
5160 /*
5161 * If there are no wildcards, just copy the names to allocated memory.
5162 * Saves a lot of time, because we don't have to start a new shell.
5163 */
5164 if (!have_wildcard(num_pat, pat))
5165 return save_patterns(num_pat, pat, num_file, file);
5166
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005167# ifdef HAVE_SANDBOX
5168 /* Don't allow any shell command in the sandbox. */
5169 if (sandbox != 0 && check_secure())
5170 return FAIL;
5171# endif
5172
Bram Moolenaar071d4272004-06-13 20:20:40 +00005173 /*
5174 * Don't allow the use of backticks in secure and restricted mode.
5175 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005176 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005177 for (i = 0; i < num_pat; ++i)
5178 if (vim_strchr(pat[i], '`') != NULL
5179 && (check_restricted() || check_secure()))
5180 return FAIL;
5181
5182 /*
5183 * get a name for the temp file
5184 */
5185 if ((tempname = vim_tempname('o')) == NULL)
5186 {
5187 EMSG(_(e_notmp));
5188 return FAIL;
5189 }
5190
5191 /*
5192 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005193 * file.
5194 * STYLE_BT: NL separated
5195 * If expanding `cmd` execute it directly.
5196 * STYLE_GLOB: NUL separated
5197 * If we use *csh, "glob" will work better than "echo".
5198 * STYLE_PRINT: NL or NUL separated
5199 * If we use *zsh, "print -N" will work better than "glob".
5200 * STYLE_VIMGLOB: NL separated
5201 * If we use *sh*, we define "vimglob()".
5202 * STYLE_ECHO: space separated.
5203 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005204 */
5205 if (num_pat == 1 && *pat[0] == '`'
5206 && (len = STRLEN(pat[0])) > 2
5207 && *(pat[0] + len - 1) == '`')
5208 shell_style = STYLE_BT;
5209 else if ((len = STRLEN(p_sh)) >= 3)
5210 {
5211 if (STRCMP(p_sh + len - 3, "csh") == 0)
5212 shell_style = STYLE_GLOB;
5213 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5214 shell_style = STYLE_PRINT;
5215 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005216 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5217 "sh") != NULL)
5218 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005219
Bram Moolenaarc7247912008-01-13 12:54:11 +00005220 /* Compute the length of the command. We need 2 extra bytes: for the
5221 * optional '&' and for the NUL.
5222 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005223 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005224 if (shell_style == STYLE_VIMGLOB)
5225 len += STRLEN(sh_vimglob_func);
5226
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005227 for (i = 0; i < num_pat; ++i)
5228 {
5229 /* Count the length of the patterns in the same way as they are put in
5230 * "command" below. */
5231#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005232 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005233#else
5234 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005235 for (j = 0; pat[i][j] != NUL; ++j)
5236 {
5237 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5238 ++len; /* may add a backslash */
5239 ++len;
5240 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005241#endif
5242 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005243 command = alloc(len);
5244 if (command == NULL)
5245 {
5246 /* out of memory */
5247 vim_free(tempname);
5248 return FAIL;
5249 }
5250
5251 /*
5252 * Build the shell command:
5253 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5254 * recognizes this).
5255 * - Add the shell command to print the expanded names.
5256 * - Add the temp file name.
5257 * - Add the file name patterns.
5258 */
5259 if (shell_style == STYLE_BT)
5260 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005261 /* change `command; command& ` to (command; command ) */
5262 STRCPY(command, "(");
5263 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005264 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005265 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005266 while (p > command && vim_iswhite(*p))
5267 --p;
5268 if (*p == '&') /* remove trailing '&' */
5269 {
5270 ampersent = TRUE;
5271 *p = ' ';
5272 }
5273 STRCAT(command, ">");
5274 }
5275 else
5276 {
5277 if (flags & EW_NOTFOUND)
5278 STRCPY(command, "set nonomatch; ");
5279 else
5280 STRCPY(command, "unset nonomatch; ");
5281 if (shell_style == STYLE_GLOB)
5282 STRCAT(command, "glob >");
5283 else if (shell_style == STYLE_PRINT)
5284 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005285 else if (shell_style == STYLE_VIMGLOB)
5286 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005287 else
5288 STRCAT(command, "echo >");
5289 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005290
Bram Moolenaar071d4272004-06-13 20:20:40 +00005291 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005292
Bram Moolenaar071d4272004-06-13 20:20:40 +00005293 if (shell_style != STYLE_BT)
5294 for (i = 0; i < num_pat; ++i)
5295 {
5296 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005297 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005298 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005299#ifdef USE_SYSTEM
5300 STRCAT(command, " \"");
5301 STRCAT(command, pat[i]);
5302 STRCAT(command, "\"");
5303#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005304 int intick = FALSE;
5305
Bram Moolenaar071d4272004-06-13 20:20:40 +00005306 p = command + STRLEN(command);
5307 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005308 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005309 {
5310 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005311 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005312 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5313 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005314 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005315 * backslash inside backticks, before a special character
5316 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005317 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005318 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5319 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005320 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005321 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005322 }
5323 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005324 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005325 /* Put a backslash before a special character, but not
5326 * when inside ``. */
5327 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005328
5329 /* Copy one character. */
5330 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005331 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005332 *p = NUL;
5333#endif
5334 }
5335 if (flags & EW_SILENT)
5336 show_shell_mess = FALSE;
5337 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00005338 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005339
5340 /*
5341 * Using zsh -G: If a pattern has no matches, it is just deleted from
5342 * the argument list, otherwise zsh gives an error message and doesn't
5343 * expand any other pattern.
5344 */
5345 if (shell_style == STYLE_PRINT)
5346 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5347
5348 /*
5349 * If we use -f then shell variables set in .cshrc won't get expanded.
5350 * vi can do it, so we will too, but it is only necessary if there is a "$"
5351 * in one of the patterns, otherwise we can still use the fast option.
5352 */
5353 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5354 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5355
5356 /*
5357 * execute the shell command
5358 */
5359 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5360
5361 /* When running in the background, give it some time to create the temp
5362 * file, but don't wait for it to finish. */
5363 if (ampersent)
5364 mch_delay(10L, TRUE);
5365
5366 extra_shell_arg = NULL; /* cleanup */
5367 show_shell_mess = TRUE;
5368 vim_free(command);
5369
Bram Moolenaarc7247912008-01-13 12:54:11 +00005370 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005371 {
5372 mch_remove(tempname);
5373 vim_free(tempname);
5374 /*
5375 * With interactive completion, the error message is not printed.
5376 * However with USE_SYSTEM, I don't know how to turn off error messages
5377 * from the shell, so screen may still get messed up -- webb.
5378 */
5379#ifndef USE_SYSTEM
5380 if (!(flags & EW_SILENT))
5381#endif
5382 {
5383 redraw_later_clear(); /* probably messed up screen */
5384 msg_putchar('\n'); /* clear bottom line quickly */
5385 cmdline_row = Rows - 1; /* continue on last line */
5386#ifdef USE_SYSTEM
5387 if (!(flags & EW_SILENT))
5388#endif
5389 {
5390 MSG(_(e_wildexpand));
5391 msg_start(); /* don't overwrite this message */
5392 }
5393 }
5394 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5395 * EW_NOTFOUND is given */
5396 if (shell_style == STYLE_BT)
5397 return FAIL;
5398 goto notfound;
5399 }
5400
5401 /*
5402 * read the names from the file into memory
5403 */
5404 fd = fopen((char *)tempname, READBIN);
5405 if (fd == NULL)
5406 {
5407 /* Something went wrong, perhaps a file name with a special char. */
5408 if (!(flags & EW_SILENT))
5409 {
5410 MSG(_(e_wildexpand));
5411 msg_start(); /* don't overwrite this message */
5412 }
5413 vim_free(tempname);
5414 goto notfound;
5415 }
5416 fseek(fd, 0L, SEEK_END);
5417 len = ftell(fd); /* get size of temp file */
5418 fseek(fd, 0L, SEEK_SET);
5419 buffer = alloc(len + 1);
5420 if (buffer == NULL)
5421 {
5422 /* out of memory */
5423 mch_remove(tempname);
5424 vim_free(tempname);
5425 fclose(fd);
5426 return FAIL;
5427 }
5428 i = fread((char *)buffer, 1, len, fd);
5429 fclose(fd);
5430 mch_remove(tempname);
5431 if (i != len)
5432 {
5433 /* unexpected read error */
5434 EMSG2(_(e_notread), tempname);
5435 vim_free(tempname);
5436 vim_free(buffer);
5437 return FAIL;
5438 }
5439 vim_free(tempname);
5440
Bram Moolenaarc7247912008-01-13 12:54:11 +00005441# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005442 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5443 p = buffer;
5444 for (i = 0; i < len; ++i)
5445 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5446 *p++ = buffer[i];
5447 len = p - buffer;
5448# endif
5449
5450
5451 /* file names are separated with Space */
5452 if (shell_style == STYLE_ECHO)
5453 {
5454 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5455 p = buffer;
5456 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5457 {
5458 while (*p != ' ' && *p != '\n')
5459 ++p;
5460 p = skipwhite(p); /* skip to next entry */
5461 }
5462 }
5463 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005464 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005465 {
5466 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5467 p = buffer;
5468 for (i = 0; *p != NUL; ++i) /* count number of entries */
5469 {
5470 while (*p != '\n' && *p != NUL)
5471 ++p;
5472 if (*p != NUL)
5473 ++p;
5474 p = skipwhite(p); /* skip leading white space */
5475 }
5476 }
5477 /* file names are separated with NUL */
5478 else
5479 {
5480 /*
5481 * Some versions of zsh use spaces instead of NULs to separate
5482 * results. Only do this when there is no NUL before the end of the
5483 * buffer, otherwise we would never be able to use file names with
5484 * embedded spaces when zsh does use NULs.
5485 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5486 * don't check for spaces again.
5487 */
5488 check_spaces = FALSE;
5489 if (shell_style == STYLE_PRINT && !did_find_nul)
5490 {
5491 /* If there is a NUL, set did_find_nul, else set check_spaces */
5492 if (len && (int)STRLEN(buffer) < len - 1)
5493 did_find_nul = TRUE;
5494 else
5495 check_spaces = TRUE;
5496 }
5497
5498 /*
5499 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5500 * already is one, for STYLE_GLOB it needs to be added.
5501 */
5502 if (len && buffer[len - 1] == NUL)
5503 --len;
5504 else
5505 buffer[len] = NUL;
5506 i = 0;
5507 for (p = buffer; p < buffer + len; ++p)
5508 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5509 {
5510 ++i;
5511 *p = NUL;
5512 }
5513 if (len)
5514 ++i; /* count last entry */
5515 }
5516 if (i == 0)
5517 {
5518 /*
5519 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5520 * /bin/sh will happily expand it to nothing rather than returning an
5521 * error; and hey, it's good to check anyway -- webb.
5522 */
5523 vim_free(buffer);
5524 goto notfound;
5525 }
5526 *num_file = i;
5527 *file = (char_u **)alloc(sizeof(char_u *) * i);
5528 if (*file == NULL)
5529 {
5530 /* out of memory */
5531 vim_free(buffer);
5532 return FAIL;
5533 }
5534
5535 /*
5536 * Isolate the individual file names.
5537 */
5538 p = buffer;
5539 for (i = 0; i < *num_file; ++i)
5540 {
5541 (*file)[i] = p;
5542 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005543 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
5544 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005545 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00005546 while (!(shell_style == STYLE_ECHO && *p == ' ')
5547 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005548 ++p;
5549 if (p == buffer + len) /* last entry */
5550 *p = NUL;
5551 else
5552 {
5553 *p++ = NUL;
5554 p = skipwhite(p); /* skip to next entry */
5555 }
5556 }
5557 else /* NUL separates */
5558 {
5559 while (*p && p < buffer + len) /* skip entry */
5560 ++p;
5561 ++p; /* skip NUL */
5562 }
5563 }
5564
5565 /*
5566 * Move the file names to allocated memory.
5567 */
5568 for (j = 0, i = 0; i < *num_file; ++i)
5569 {
5570 /* Require the files to exist. Helps when using /bin/sh */
5571 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5572 continue;
5573
5574 /* check if this entry should be included */
5575 dir = (mch_isdir((*file)[i]));
5576 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5577 continue;
5578
Bram Moolenaara2031822006-03-07 22:29:51 +00005579 /* Skip files that are not executable if we check for that. */
5580 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
5581 continue;
5582
Bram Moolenaar071d4272004-06-13 20:20:40 +00005583 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5584 if (p)
5585 {
5586 STRCPY(p, (*file)[i]);
5587 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00005588 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005589 (*file)[j++] = p;
5590 }
5591 }
5592 vim_free(buffer);
5593 *num_file = j;
5594
5595 if (*num_file == 0) /* rejected all entries */
5596 {
5597 vim_free(*file);
5598 *file = NULL;
5599 goto notfound;
5600 }
5601
5602 return OK;
5603
5604notfound:
5605 if (flags & EW_NOTFOUND)
5606 return save_patterns(num_pat, pat, num_file, file);
5607 return FAIL;
5608
5609#endif /* __EMX__ */
5610}
5611
5612#endif /* VMS */
5613
5614#ifndef __EMX__
5615 static int
5616save_patterns(num_pat, pat, num_file, file)
5617 int num_pat;
5618 char_u **pat;
5619 int *num_file;
5620 char_u ***file;
5621{
5622 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005623 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005624
5625 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5626 if (*file == NULL)
5627 return FAIL;
5628 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005629 {
5630 s = vim_strsave(pat[i]);
5631 if (s != NULL)
5632 /* Be compatible with expand_filename(): halve the number of
5633 * backslashes. */
5634 backslash_halve(s);
5635 (*file)[i] = s;
5636 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005637 *num_file = num_pat;
5638 return OK;
5639}
5640#endif
5641
5642
5643/*
5644 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5645 * expand.
5646 */
5647 int
5648mch_has_exp_wildcard(p)
5649 char_u *p;
5650{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005651 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005652 {
5653#ifndef OS2
5654 if (*p == '\\' && p[1] != NUL)
5655 ++p;
5656 else
5657#endif
5658 if (vim_strchr((char_u *)
5659#ifdef VMS
5660 "*?%"
5661#else
5662# ifdef OS2
5663 "*?"
5664# else
5665 "*?[{'"
5666# endif
5667#endif
5668 , *p) != NULL)
5669 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005670 }
5671 return FALSE;
5672}
5673
5674/*
5675 * Return TRUE if the string "p" contains a wildcard.
5676 * Don't recognize '~' at the end as a wildcard.
5677 */
5678 int
5679mch_has_wildcard(p)
5680 char_u *p;
5681{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005682 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005683 {
5684#ifndef OS2
5685 if (*p == '\\' && p[1] != NUL)
5686 ++p;
5687 else
5688#endif
5689 if (vim_strchr((char_u *)
5690#ifdef VMS
5691 "*?%$"
5692#else
5693# ifdef OS2
5694# ifdef VIM_BACKTICK
5695 "*?$`"
5696# else
5697 "*?$"
5698# endif
5699# else
5700 "*?[{`'$"
5701# endif
5702#endif
5703 , *p) != NULL
5704 || (*p == '~' && p[1] != NUL))
5705 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005706 }
5707 return FALSE;
5708}
5709
5710#ifndef __EMX__
5711 static int
5712have_wildcard(num, file)
5713 int num;
5714 char_u **file;
5715{
5716 int i;
5717
5718 for (i = 0; i < num; i++)
5719 if (mch_has_wildcard(file[i]))
5720 return 1;
5721 return 0;
5722}
5723
5724 static int
5725have_dollars(num, file)
5726 int num;
5727 char_u **file;
5728{
5729 int i;
5730
5731 for (i = 0; i < num; i++)
5732 if (vim_strchr(file[i], '$') != NULL)
5733 return TRUE;
5734 return FALSE;
5735}
5736#endif /* ifndef __EMX__ */
5737
5738#ifndef HAVE_RENAME
5739/*
5740 * Scaled-down version of rename(), which is missing in Xenix.
5741 * This version can only move regular files and will fail if the
5742 * destination exists.
5743 */
5744 int
5745mch_rename(src, dest)
5746 const char *src, *dest;
5747{
5748 struct stat st;
5749
5750 if (stat(dest, &st) >= 0) /* fail if destination exists */
5751 return -1;
5752 if (link(src, dest) != 0) /* link file to new name */
5753 return -1;
5754 if (mch_remove(src) == 0) /* delete link to old name */
5755 return 0;
5756 return -1;
5757}
5758#endif /* !HAVE_RENAME */
5759
5760#ifdef FEAT_MOUSE_GPM
5761/*
5762 * Initializes connection with gpm (if it isn't already opened)
5763 * Return 1 if succeeded (or connection already opened), 0 if failed
5764 */
5765 static int
5766gpm_open()
5767{
5768 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5769
5770 if (!gpm_flag)
5771 {
5772 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5773 gpm_connect.defaultMask = ~GPM_HARD;
5774 /* Default handling for mouse move*/
5775 gpm_connect.minMod = 0; /* Handle any modifier keys */
5776 gpm_connect.maxMod = 0xffff;
5777 if (Gpm_Open(&gpm_connect, 0) > 0)
5778 {
5779 /* gpm library tries to handling TSTP causes
5780 * problems. Anyways, we close connection to Gpm whenever
5781 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005782 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00005783 */
5784 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5785 return 1; /* succeed */
5786 }
5787 if (gpm_fd == -2)
5788 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5789 return 0;
5790 }
5791 return 1; /* already open */
5792}
5793
5794/*
5795 * Closes connection to gpm
Bram Moolenaar1a3d0862007-08-30 09:47:38 +00005796 * returns non-zero if connection successfully closed
Bram Moolenaar071d4272004-06-13 20:20:40 +00005797 */
5798 static void
5799gpm_close()
5800{
5801 if (gpm_flag && gpm_fd >= 0) /* if Open */
5802 Gpm_Close();
5803}
5804
5805/* Reads gpm event and adds special keys to input buf. Returns length of
5806 * generated key sequence.
5807 * This function is made after gui_send_mouse_event
5808 */
5809 static int
5810mch_gpm_process()
5811{
5812 int button;
5813 static Gpm_Event gpm_event;
5814 char_u string[6];
5815 int_u vim_modifiers;
5816 int row,col;
5817 unsigned char buttons_mask;
5818 unsigned char gpm_modifiers;
5819 static unsigned char old_buttons = 0;
5820
5821 Gpm_GetEvent(&gpm_event);
5822
5823#ifdef FEAT_GUI
5824 /* Don't put events in the input queue now. */
5825 if (hold_gui_events)
5826 return 0;
5827#endif
5828
5829 row = gpm_event.y - 1;
5830 col = gpm_event.x - 1;
5831
5832 string[0] = ESC; /* Our termcode */
5833 string[1] = 'M';
5834 string[2] = 'G';
5835 switch (GPM_BARE_EVENTS(gpm_event.type))
5836 {
5837 case GPM_DRAG:
5838 string[3] = MOUSE_DRAG;
5839 break;
5840 case GPM_DOWN:
5841 buttons_mask = gpm_event.buttons & ~old_buttons;
5842 old_buttons = gpm_event.buttons;
5843 switch (buttons_mask)
5844 {
5845 case GPM_B_LEFT:
5846 button = MOUSE_LEFT;
5847 break;
5848 case GPM_B_MIDDLE:
5849 button = MOUSE_MIDDLE;
5850 break;
5851 case GPM_B_RIGHT:
5852 button = MOUSE_RIGHT;
5853 break;
5854 default:
5855 return 0;
5856 /*Don't know what to do. Can more than one button be
5857 * reported in one event? */
5858 }
5859 string[3] = (char_u)(button | 0x20);
5860 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5861 break;
5862 case GPM_UP:
5863 string[3] = MOUSE_RELEASE;
5864 old_buttons &= ~gpm_event.buttons;
5865 break;
5866 default:
5867 return 0;
5868 }
5869 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5870 gpm_modifiers = gpm_event.modifiers;
5871 vim_modifiers = 0x0;
5872 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5873 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5874 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5875 */
5876 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5877 vim_modifiers |= MOUSE_SHIFT;
5878
5879 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5880 vim_modifiers |= MOUSE_CTRL;
5881 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5882 vim_modifiers |= MOUSE_ALT;
5883 string[3] |= vim_modifiers;
5884 string[4] = (char_u)(col + ' ' + 1);
5885 string[5] = (char_u)(row + ' ' + 1);
5886 add_to_input_buf(string, 6);
5887 return 6;
5888}
5889#endif /* FEAT_MOUSE_GPM */
5890
5891#if defined(FEAT_LIBCALL) || defined(PROTO)
5892typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
5893typedef char_u * (*INTPROCSTR)__ARGS((int));
5894typedef int (*STRPROCINT)__ARGS((char_u *));
5895typedef int (*INTPROCINT)__ARGS((int));
5896
5897/*
5898 * Call a DLL routine which takes either a string or int param
5899 * and returns an allocated string.
5900 */
5901 int
5902mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
5903 char_u *libname;
5904 char_u *funcname;
5905 char_u *argstring; /* NULL when using a argint */
5906 int argint;
5907 char_u **string_result;/* NULL when using number_result */
5908 int *number_result;
5909{
5910# if defined(USE_DLOPEN)
5911 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005912 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005913# else
5914 shl_t hinstLib;
5915# endif
5916 STRPROCSTR ProcAdd;
5917 INTPROCSTR ProcAddI;
5918 char_u *retval_str = NULL;
5919 int retval_int = 0;
5920 int success = FALSE;
5921
Bram Moolenaarb39ef122006-06-22 16:19:31 +00005922 /*
5923 * Get a handle to the DLL module.
5924 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005925# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00005926 /* First clear any error, it's not cleared by the dlopen() call. */
5927 (void)dlerror();
5928
Bram Moolenaar071d4272004-06-13 20:20:40 +00005929 hinstLib = dlopen((char *)libname, RTLD_LAZY
5930# ifdef RTLD_LOCAL
5931 | RTLD_LOCAL
5932# endif
5933 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005934 if (hinstLib == NULL)
5935 {
5936 /* "dlerr" must be used before dlclose() */
5937 dlerr = (char *)dlerror();
5938 if (dlerr != NULL)
5939 EMSG2(_("dlerror = \"%s\""), dlerr);
5940 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005941# else
5942 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
5943# endif
5944
5945 /* If the handle is valid, try to get the function address. */
5946 if (hinstLib != NULL)
5947 {
5948# ifdef HAVE_SETJMP_H
5949 /*
5950 * Catch a crash when calling the library function. For example when
5951 * using a number where a string pointer is expected.
5952 */
5953 mch_startjmp();
5954 if (SETJMP(lc_jump_env) != 0)
5955 {
5956 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00005957# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005958 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00005959# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005960 mch_didjmp();
5961 }
5962 else
5963# endif
5964 {
5965 retval_str = NULL;
5966 retval_int = 0;
5967
5968 if (argstring != NULL)
5969 {
5970# if defined(USE_DLOPEN)
5971 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005972 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005973# else
5974 if (shl_findsym(&hinstLib, (const char *)funcname,
5975 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
5976 ProcAdd = NULL;
5977# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005978 if ((success = (ProcAdd != NULL
5979# if defined(USE_DLOPEN)
5980 && dlerr == NULL
5981# endif
5982 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005983 {
5984 if (string_result == NULL)
5985 retval_int = ((STRPROCINT)ProcAdd)(argstring);
5986 else
5987 retval_str = (ProcAdd)(argstring);
5988 }
5989 }
5990 else
5991 {
5992# if defined(USE_DLOPEN)
5993 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005994 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005995# else
5996 if (shl_findsym(&hinstLib, (const char *)funcname,
5997 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
5998 ProcAddI = NULL;
5999# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006000 if ((success = (ProcAddI != NULL
6001# if defined(USE_DLOPEN)
6002 && dlerr == NULL
6003# endif
6004 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006005 {
6006 if (string_result == NULL)
6007 retval_int = ((INTPROCINT)ProcAddI)(argint);
6008 else
6009 retval_str = (ProcAddI)(argint);
6010 }
6011 }
6012
6013 /* Save the string before we free the library. */
6014 /* Assume that a "1" or "-1" result is an illegal pointer. */
6015 if (string_result == NULL)
6016 *number_result = retval_int;
6017 else if (retval_str != NULL
6018 && retval_str != (char_u *)1
6019 && retval_str != (char_u *)-1)
6020 *string_result = vim_strsave(retval_str);
6021 }
6022
6023# ifdef HAVE_SETJMP_H
6024 mch_endjmp();
6025# ifdef SIGHASARG
6026 if (lc_signal != 0)
6027 {
6028 int i;
6029
6030 /* try to find the name of this signal */
6031 for (i = 0; signal_info[i].sig != -1; i++)
6032 if (lc_signal == signal_info[i].sig)
6033 break;
6034 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6035 }
6036# endif
6037# endif
6038
Bram Moolenaar071d4272004-06-13 20:20:40 +00006039# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006040 /* "dlerr" must be used before dlclose() */
6041 if (dlerr != NULL)
6042 EMSG2(_("dlerror = \"%s\""), dlerr);
6043
6044 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006045 (void)dlclose(hinstLib);
6046# else
6047 (void)shl_unload(hinstLib);
6048# endif
6049 }
6050
6051 if (!success)
6052 {
6053 EMSG2(_(e_libcall), funcname);
6054 return FAIL;
6055 }
6056
6057 return OK;
6058}
6059#endif
6060
6061#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6062static int xterm_trace = -1; /* default: disabled */
6063static int xterm_button;
6064
6065/*
6066 * Setup a dummy window for X selections in a terminal.
6067 */
6068 void
6069setup_term_clip()
6070{
6071 int z = 0;
6072 char *strp = "";
6073 Widget AppShell;
6074
6075 if (!x_connect_to_server())
6076 return;
6077
6078 open_app_context();
6079 if (app_context != NULL && xterm_Shell == (Widget)0)
6080 {
6081 int (*oldhandler)();
6082#if defined(HAVE_SETJMP_H)
6083 int (*oldIOhandler)();
6084#endif
6085# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6086 struct timeval start_tv;
6087
6088 if (p_verbose > 0)
6089 gettimeofday(&start_tv, NULL);
6090# endif
6091
6092 /* Ignore X errors while opening the display */
6093 oldhandler = XSetErrorHandler(x_error_check);
6094
6095#if defined(HAVE_SETJMP_H)
6096 /* Ignore X IO errors while opening the display */
6097 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6098 mch_startjmp();
6099 if (SETJMP(lc_jump_env) != 0)
6100 {
6101 mch_didjmp();
6102 xterm_dpy = NULL;
6103 }
6104 else
6105#endif
6106 {
6107 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6108 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6109#if defined(HAVE_SETJMP_H)
6110 mch_endjmp();
6111#endif
6112 }
6113
6114#if defined(HAVE_SETJMP_H)
6115 /* Now handle X IO errors normally. */
6116 (void)XSetIOErrorHandler(oldIOhandler);
6117#endif
6118 /* Now handle X errors normally. */
6119 (void)XSetErrorHandler(oldhandler);
6120
6121 if (xterm_dpy == NULL)
6122 {
6123 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006124 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006125 return;
6126 }
6127
6128 /* Catch terminating error of the X server connection. */
6129 (void)XSetIOErrorHandler(x_IOerror_handler);
6130
6131# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6132 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006133 {
6134 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006135 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006136 verbose_leave();
6137 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006138# endif
6139
6140 /* Create a Shell to make converters work. */
6141 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6142 applicationShellWidgetClass, xterm_dpy,
6143 NULL);
6144 if (AppShell == (Widget)0)
6145 return;
6146 xterm_Shell = XtVaCreatePopupShell("VIM",
6147 topLevelShellWidgetClass, AppShell,
6148 XtNmappedWhenManaged, 0,
6149 XtNwidth, 1,
6150 XtNheight, 1,
6151 NULL);
6152 if (xterm_Shell == (Widget)0)
6153 return;
6154
6155 x11_setup_atoms(xterm_dpy);
6156 if (x11_display == NULL)
6157 x11_display = xterm_dpy;
6158
6159 XtRealizeWidget(xterm_Shell);
6160 XSync(xterm_dpy, False);
6161 xterm_update();
6162 }
6163 if (xterm_Shell != (Widget)0)
6164 {
6165 clip_init(TRUE);
6166 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6167 x11_window = (Window)atol(strp);
6168 /* Check if $WINDOWID is valid. */
6169 if (test_x11_window(xterm_dpy) == FAIL)
6170 x11_window = 0;
6171 if (x11_window != 0)
6172 xterm_trace = 0;
6173 }
6174}
6175
6176 void
6177start_xterm_trace(button)
6178 int button;
6179{
6180 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6181 return;
6182 xterm_trace = 1;
6183 xterm_button = button;
6184 do_xterm_trace();
6185}
6186
6187
6188 void
6189stop_xterm_trace()
6190{
6191 if (xterm_trace < 0)
6192 return;
6193 xterm_trace = 0;
6194}
6195
6196/*
6197 * Query the xterm pointer and generate mouse termcodes if necessary
6198 * return TRUE if dragging is active, else FALSE
6199 */
6200 static int
6201do_xterm_trace()
6202{
6203 Window root, child;
6204 int root_x, root_y;
6205 int win_x, win_y;
6206 int row, col;
6207 int_u mask_return;
6208 char_u buf[50];
6209 char_u *strp;
6210 long got_hints;
6211 static char_u *mouse_code;
6212 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6213 static int prev_row = 0, prev_col = 0;
6214 static XSizeHints xterm_hints;
6215
6216 if (xterm_trace <= 0)
6217 return FALSE;
6218
6219 if (xterm_trace == 1)
6220 {
6221 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006222 * have changed recently. */
6223 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6224 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006225 || xterm_hints.width_inc <= 1
6226 || xterm_hints.height_inc <= 1)
6227 {
6228 xterm_trace = -1; /* Not enough data -- disable tracing */
6229 return FALSE;
6230 }
6231
6232 /* Rely on the same mouse code for the duration of this */
6233 mouse_code = find_termcode(mouse_name);
6234 prev_row = mouse_row;
6235 prev_row = mouse_col;
6236 xterm_trace = 2;
6237
6238 /* Find the offset of the chars, there might be a scrollbar on the
6239 * left of the window and/or a menu on the top (eterm etc.) */
6240 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6241 &win_x, &win_y, &mask_return);
6242 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6243 - (xterm_hints.height_inc / 2);
6244 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6245 xterm_hints.y = 2;
6246 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6247 - (xterm_hints.width_inc / 2);
6248 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6249 xterm_hints.x = 2;
6250 return TRUE;
6251 }
6252 if (mouse_code == NULL)
6253 {
6254 xterm_trace = 0;
6255 return FALSE;
6256 }
6257
6258 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6259 &win_x, &win_y, &mask_return);
6260
6261 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6262 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6263 if (row == prev_row && col == prev_col)
6264 return TRUE;
6265
6266 STRCPY(buf, mouse_code);
6267 strp = buf + STRLEN(buf);
6268 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6269 *strp++ = (char_u)(col + ' ' + 1);
6270 *strp++ = (char_u)(row + ' ' + 1);
6271 *strp = 0;
6272 add_to_input_buf(buf, STRLEN(buf));
6273
6274 prev_row = row;
6275 prev_col = col;
6276 return TRUE;
6277}
6278
6279# if defined(FEAT_GUI) || defined(PROTO)
6280/*
6281 * Destroy the display, window and app_context. Required for GTK.
6282 */
6283 void
6284clear_xterm_clip()
6285{
6286 if (xterm_Shell != (Widget)0)
6287 {
6288 XtDestroyWidget(xterm_Shell);
6289 xterm_Shell = (Widget)0;
6290 }
6291 if (xterm_dpy != NULL)
6292 {
6293#if 0
6294 /* Lesstif and Solaris crash here, lose some memory */
6295 XtCloseDisplay(xterm_dpy);
6296#endif
6297 if (x11_display == xterm_dpy)
6298 x11_display = NULL;
6299 xterm_dpy = NULL;
6300 }
6301#if 0
6302 if (app_context != (XtAppContext)NULL)
6303 {
6304 /* Lesstif and Solaris crash here, lose some memory */
6305 XtDestroyApplicationContext(app_context);
6306 app_context = (XtAppContext)NULL;
6307 }
6308#endif
6309}
6310# endif
6311
6312/*
6313 * Catch up with any queued X events. This may put keyboard input into the
6314 * input buffer, call resize call-backs, trigger timers etc. If there is
6315 * nothing in the X event queue (& no timers pending), then we return
6316 * immediately.
6317 */
6318 static void
6319xterm_update()
6320{
6321 XEvent event;
6322
6323 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6324 {
6325 XtAppNextEvent(app_context, &event);
6326#ifdef FEAT_CLIENTSERVER
6327 {
6328 XPropertyEvent *e = (XPropertyEvent *)&event;
6329
6330 if (e->type == PropertyNotify && e->window == commWindow
6331 && e->atom == commProperty && e->state == PropertyNewValue)
6332 serverEventProc(xterm_dpy, &event);
6333 }
6334#endif
6335 XtDispatchEvent(&event);
6336 }
6337}
6338
6339 int
6340clip_xterm_own_selection(cbd)
6341 VimClipboard *cbd;
6342{
6343 if (xterm_Shell != (Widget)0)
6344 return clip_x11_own_selection(xterm_Shell, cbd);
6345 return FAIL;
6346}
6347
6348 void
6349clip_xterm_lose_selection(cbd)
6350 VimClipboard *cbd;
6351{
6352 if (xterm_Shell != (Widget)0)
6353 clip_x11_lose_selection(xterm_Shell, cbd);
6354}
6355
6356 void
6357clip_xterm_request_selection(cbd)
6358 VimClipboard *cbd;
6359{
6360 if (xterm_Shell != (Widget)0)
6361 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6362}
6363
6364 void
6365clip_xterm_set_selection(cbd)
6366 VimClipboard *cbd;
6367{
6368 clip_x11_set_selection(cbd);
6369}
6370#endif
6371
6372
6373#if defined(USE_XSMP) || defined(PROTO)
6374/*
6375 * Code for X Session Management Protocol.
6376 */
6377static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6378static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6379static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6380static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6381static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6382
6383
6384# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6385static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6386
6387/*
6388 * This is our chance to ask the user if they want to save,
6389 * or abort the logout
6390 */
6391/*ARGSUSED*/
6392 static void
6393xsmp_handle_interaction(smc_conn, client_data)
6394 SmcConn smc_conn;
6395 SmPointer client_data;
6396{
6397 cmdmod_T save_cmdmod;
6398 int cancel_shutdown = False;
6399
6400 save_cmdmod = cmdmod;
6401 cmdmod.confirm = TRUE;
6402 if (check_changed_any(FALSE))
6403 /* Mustn't logout */
6404 cancel_shutdown = True;
6405 cmdmod = save_cmdmod;
6406 setcursor(); /* position cursor */
6407 out_flush();
6408
6409 /* Done interaction */
6410 SmcInteractDone(smc_conn, cancel_shutdown);
6411
6412 /* Finish off
6413 * Only end save-yourself here if we're not cancelling shutdown;
6414 * we'll get a cancelled callback later in which we'll end it.
6415 * Hopefully get around glitchy SMs (like GNOME-1)
6416 */
6417 if (!cancel_shutdown)
6418 {
6419 xsmp.save_yourself = False;
6420 SmcSaveYourselfDone(smc_conn, True);
6421 }
6422}
6423# endif
6424
6425/*
6426 * Callback that starts save-yourself.
6427 */
6428/*ARGSUSED*/
6429 static void
6430xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6431 shutdown, interact_style, fast)
6432 SmcConn smc_conn;
6433 SmPointer client_data;
6434 int save_type;
6435 Bool shutdown;
6436 int interact_style;
6437 Bool fast;
6438{
6439 /* Handle already being in saveyourself */
6440 if (xsmp.save_yourself)
6441 SmcSaveYourselfDone(smc_conn, True);
6442 xsmp.save_yourself = True;
6443 xsmp.shutdown = shutdown;
6444
6445 /* First up, preserve all files */
6446 out_flush();
6447 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6448
6449 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006450 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006451
6452# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6453 /* Now see if we can ask about unsaved files */
6454 if (shutdown && !fast && gui.in_use)
6455 /* Need to interact with user, but need SM's permission */
6456 SmcInteractRequest(smc_conn, SmDialogError,
6457 xsmp_handle_interaction, client_data);
6458 else
6459# endif
6460 {
6461 /* Can stop the cycle here */
6462 SmcSaveYourselfDone(smc_conn, True);
6463 xsmp.save_yourself = False;
6464 }
6465}
6466
6467
6468/*
6469 * Callback to warn us of imminent death.
6470 */
6471/*ARGSUSED*/
6472 static void
6473xsmp_die(smc_conn, client_data)
6474 SmcConn smc_conn;
6475 SmPointer client_data;
6476{
6477 xsmp_close();
6478
6479 /* quit quickly leaving swapfiles for modified buffers behind */
6480 getout_preserve_modified(0);
6481}
6482
6483
6484/*
6485 * Callback to tell us that save-yourself has completed.
6486 */
6487/*ARGSUSED*/
6488 static void
6489xsmp_save_complete(smc_conn, client_data)
6490 SmcConn smc_conn;
6491 SmPointer client_data;
6492{
6493 xsmp.save_yourself = False;
6494}
6495
6496
6497/*
6498 * Callback to tell us that an instigated shutdown was cancelled
6499 * (maybe even by us)
6500 */
6501/*ARGSUSED*/
6502 static void
6503xsmp_shutdown_cancelled(smc_conn, client_data)
6504 SmcConn smc_conn;
6505 SmPointer client_data;
6506{
6507 if (xsmp.save_yourself)
6508 SmcSaveYourselfDone(smc_conn, True);
6509 xsmp.save_yourself = False;
6510 xsmp.shutdown = False;
6511}
6512
6513
6514/*
6515 * Callback to tell us that a new ICE connection has been established.
6516 */
6517/*ARGSUSED*/
6518 static void
6519xsmp_ice_connection(iceConn, clientData, opening, watchData)
6520 IceConn iceConn;
6521 IcePointer clientData;
6522 Bool opening;
6523 IcePointer *watchData;
6524{
6525 /* Intercept creation of ICE connection fd */
6526 if (opening)
6527 {
6528 xsmp_icefd = IceConnectionNumber(iceConn);
6529 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6530 }
6531}
6532
6533
6534/* Handle any ICE processing that's required; return FAIL if SM lost */
6535 int
6536xsmp_handle_requests()
6537{
6538 Bool rep;
6539
6540 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6541 == IceProcessMessagesIOError)
6542 {
6543 /* Lost ICE */
6544 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006545 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006546 xsmp_close();
6547 return FAIL;
6548 }
6549 else
6550 return OK;
6551}
6552
6553static int dummy;
6554
6555/* Set up X Session Management Protocol */
6556 void
6557xsmp_init(void)
6558{
6559 char errorstring[80];
6560 char *clientid;
6561 SmcCallbacks smcallbacks;
6562#if 0
6563 SmPropValue smname;
6564 SmProp smnameprop;
6565 SmProp *smprops[1];
6566#endif
6567
6568 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006569 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006570
6571 xsmp.save_yourself = xsmp.shutdown = False;
6572
6573 /* Set up SM callbacks - must have all, even if they're not used */
6574 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6575 smcallbacks.save_yourself.client_data = NULL;
6576 smcallbacks.die.callback = xsmp_die;
6577 smcallbacks.die.client_data = NULL;
6578 smcallbacks.save_complete.callback = xsmp_save_complete;
6579 smcallbacks.save_complete.client_data = NULL;
6580 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6581 smcallbacks.shutdown_cancelled.client_data = NULL;
6582
6583 /* Set up a watch on ICE connection creations. The "dummy" argument is
6584 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6585 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6586 {
6587 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006588 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006589 return;
6590 }
6591
6592 /* Create an SM connection */
6593 xsmp.smcconn = SmcOpenConnection(
6594 NULL,
6595 NULL,
6596 SmProtoMajor,
6597 SmProtoMinor,
6598 SmcSaveYourselfProcMask | SmcDieProcMask
6599 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6600 &smcallbacks,
6601 NULL,
6602 &clientid,
6603 sizeof(errorstring),
6604 errorstring);
6605 if (xsmp.smcconn == NULL)
6606 {
6607 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00006608
Bram Moolenaar071d4272004-06-13 20:20:40 +00006609 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006610 {
6611 vim_snprintf(errorreport, sizeof(errorreport),
6612 _("XSMP SmcOpenConnection failed: %s"), errorstring);
6613 verb_msg((char_u *)errorreport);
6614 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006615 return;
6616 }
6617 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6618
6619#if 0
6620 /* ID ourselves */
6621 smname.value = "vim";
6622 smname.length = 3;
6623 smnameprop.name = "SmProgram";
6624 smnameprop.type = "SmARRAY8";
6625 smnameprop.num_vals = 1;
6626 smnameprop.vals = &smname;
6627
6628 smprops[0] = &smnameprop;
6629 SmcSetProperties(xsmp.smcconn, 1, smprops);
6630#endif
6631}
6632
6633
6634/* Shut down XSMP comms. */
6635 void
6636xsmp_close()
6637{
6638 if (xsmp_icefd != -1)
6639 {
6640 SmcCloseConnection(xsmp.smcconn, 0, NULL);
6641 xsmp_icefd = -1;
6642 }
6643}
6644#endif /* USE_XSMP */
6645
6646
6647#ifdef EBCDIC
6648/* Translate character to its CTRL- value */
6649char CtrlTable[] =
6650{
6651/* 00 - 5E */
6652 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6653 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6654 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6655 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6656 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6657 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6658/* ^ */ 0x1E,
6659/* - */ 0x1F,
6660/* 61 - 6C */
6661 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6662/* _ */ 0x1F,
6663/* 6E - 80 */
6664 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6665/* a */ 0x01,
6666/* b */ 0x02,
6667/* c */ 0x03,
6668/* d */ 0x37,
6669/* e */ 0x2D,
6670/* f */ 0x2E,
6671/* g */ 0x2F,
6672/* h */ 0x16,
6673/* i */ 0x05,
6674/* 8A - 90 */
6675 0, 0, 0, 0, 0, 0, 0,
6676/* j */ 0x15,
6677/* k */ 0x0B,
6678/* l */ 0x0C,
6679/* m */ 0x0D,
6680/* n */ 0x0E,
6681/* o */ 0x0F,
6682/* p */ 0x10,
6683/* q */ 0x11,
6684/* r */ 0x12,
6685/* 9A - A1 */
6686 0, 0, 0, 0, 0, 0, 0, 0,
6687/* s */ 0x13,
6688/* t */ 0x3C,
6689/* u */ 0x3D,
6690/* v */ 0x32,
6691/* w */ 0x26,
6692/* x */ 0x18,
6693/* y */ 0x19,
6694/* z */ 0x3F,
6695/* AA - AC */
6696 0, 0, 0,
6697/* [ */ 0x27,
6698/* AE - BC */
6699 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6700/* ] */ 0x1D,
6701/* BE - C0 */ 0, 0, 0,
6702/* A */ 0x01,
6703/* B */ 0x02,
6704/* C */ 0x03,
6705/* D */ 0x37,
6706/* E */ 0x2D,
6707/* F */ 0x2E,
6708/* G */ 0x2F,
6709/* H */ 0x16,
6710/* I */ 0x05,
6711/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6712/* J */ 0x15,
6713/* K */ 0x0B,
6714/* L */ 0x0C,
6715/* M */ 0x0D,
6716/* N */ 0x0E,
6717/* O */ 0x0F,
6718/* P */ 0x10,
6719/* Q */ 0x11,
6720/* R */ 0x12,
6721/* DA - DF */ 0, 0, 0, 0, 0, 0,
6722/* \ */ 0x1C,
6723/* E1 */ 0,
6724/* S */ 0x13,
6725/* T */ 0x3C,
6726/* U */ 0x3D,
6727/* V */ 0x32,
6728/* W */ 0x26,
6729/* X */ 0x18,
6730/* Y */ 0x19,
6731/* Z */ 0x3F,
6732/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6733 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6734};
6735
6736char MetaCharTable[]=
6737{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6738 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6739 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6740 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6741 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6742};
6743
6744
6745/* TODO: Use characters NOT numbers!!! */
6746char CtrlCharTable[]=
6747{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6748 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6749 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6750 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6751 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6752};
6753
6754
6755#endif