blob: 1b0ec703ee642101a6c7c79bb648a022232d1982 [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
48/*
49 * Use this prototype for select, some include files have a wrong prototype
50 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000051#ifndef __TANDEM
52# undef select
53# ifdef __BEOS__
54# define select beos_select
55# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000056#endif
57
Bram Moolenaara2442432007-04-26 14:26:37 +000058#ifdef __CYGWIN__
59# ifndef WIN32
60# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() */
61# endif
62#endif
63
Bram Moolenaar071d4272004-06-13 20:20:40 +000064#if defined(HAVE_SELECT)
65extern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
66#endif
67
68#ifdef FEAT_MOUSE_GPM
69# include <gpm.h>
70/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
71 * I just copied relevant defines here. A cleaner solution would be to put gpm
72 * code into separate file and include there linux/keyboard.h
73 */
74/* #include <linux/keyboard.h> */
75# define KG_SHIFT 0
76# define KG_CTRL 2
77# define KG_ALT 3
78# define KG_ALTGR 1
79# define KG_SHIFTL 4
80# define KG_SHIFTR 5
81# define KG_CTRLL 6
82# define KG_CTRLR 7
83# define KG_CAPSSHIFT 8
84
85static void gpm_close __ARGS((void));
86static int gpm_open __ARGS((void));
87static int mch_gpm_process __ARGS((void));
88#endif
89
90/*
91 * end of autoconf section. To be extended...
92 */
93
94/* Are the following #ifdefs still required? And why? Is that for X11? */
95
96#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
97# ifdef SIGWINCH
98# undef SIGWINCH
99# endif
100# ifdef TIOCGWINSZ
101# undef TIOCGWINSZ
102# endif
103#endif
104
105#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
106# define SIGWINCH SIGWINDOW
107#endif
108
109#ifdef FEAT_X11
110# include <X11/Xlib.h>
111# include <X11/Xutil.h>
112# include <X11/Xatom.h>
113# ifdef FEAT_XCLIPBOARD
114# include <X11/Intrinsic.h>
115# include <X11/Shell.h>
116# include <X11/StringDefs.h>
117static Widget xterm_Shell = (Widget)0;
118static void xterm_update __ARGS((void));
119# endif
120
121# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
122Window x11_window = 0;
123# endif
124Display *x11_display = NULL;
125
126# ifdef FEAT_TITLE
127static int get_x11_windis __ARGS((void));
128static void set_x11_title __ARGS((char_u *));
129static void set_x11_icon __ARGS((char_u *));
130# endif
131#endif
132
133#ifdef FEAT_TITLE
134static int get_x11_title __ARGS((int));
135static int get_x11_icon __ARGS((int));
136
137static char_u *oldtitle = NULL;
138static int did_set_title = FALSE;
139static char_u *oldicon = NULL;
140static int did_set_icon = FALSE;
141#endif
142
143static void may_core_dump __ARGS((void));
144
145static int WaitForChar __ARGS((long));
146#if defined(__BEOS__)
147int RealWaitForChar __ARGS((int, long, int *));
148#else
149static int RealWaitForChar __ARGS((int, long, int *));
150#endif
151
152#ifdef FEAT_XCLIPBOARD
153static int do_xterm_trace __ARGS((void));
Bram Moolenaarcf851ce2005-06-16 21:52:47 +0000154# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000155#endif
156
157static void handle_resize __ARGS((void));
158
159#if defined(SIGWINCH)
160static RETSIGTYPE sig_winch __ARGS(SIGPROTOARG);
161#endif
162#if defined(SIGINT)
163static RETSIGTYPE catch_sigint __ARGS(SIGPROTOARG);
164#endif
165#if defined(SIGPWR)
166static RETSIGTYPE catch_sigpwr __ARGS(SIGPROTOARG);
167#endif
168#if defined(SIGALRM) && defined(FEAT_X11) \
169 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
170# define SET_SIG_ALARM
171static RETSIGTYPE sig_alarm __ARGS(SIGPROTOARG);
172static int sig_alarm_called;
173#endif
174static RETSIGTYPE deathtrap __ARGS(SIGPROTOARG);
175
Bram Moolenaardf177f62005-02-22 08:39:57 +0000176static void catch_int_signal __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000177static void set_signals __ARGS((void));
178static void catch_signals __ARGS((RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)()));
179#ifndef __EMX__
180static int have_wildcard __ARGS((int, char_u **));
181static int have_dollars __ARGS((int, char_u **));
182#endif
183
Bram Moolenaar071d4272004-06-13 20:20:40 +0000184#ifndef __EMX__
185static int save_patterns __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file));
186#endif
187
188#ifndef SIG_ERR
189# define SIG_ERR ((RETSIGTYPE (*)())-1)
190#endif
191
192static int do_resize = FALSE;
193#ifndef __EMX__
194static char_u *extra_shell_arg = NULL;
195static int show_shell_mess = TRUE;
196#endif
197static int deadly_signal = 0; /* The signal we caught */
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000198static int in_mch_delay = FALSE; /* sleeping in mch_delay() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199
200static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
201
202#ifdef USE_XSMP
203typedef struct
204{
205 SmcConn smcconn; /* The SM connection ID */
206 IceConn iceconn; /* The ICE connection ID */
207 Bool save_yourself; /* If we're in the middle of a save_yourself */
208 Bool shutdown; /* If we're in shutdown mode */
209} xsmp_config_T;
210
211static xsmp_config_T xsmp;
212#endif
213
214#ifdef SYS_SIGLIST_DECLARED
215/*
216 * I have seen
217 * extern char *_sys_siglist[NSIG];
218 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
219 * that describe the signals. That is nearly what we want here. But
220 * autoconf does only check for sys_siglist (without the underscore), I
221 * do not want to change everything today.... jw.
222 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.in
223 */
224#endif
225
226static struct signalinfo
227{
228 int sig; /* Signal number, eg. SIGSEGV etc */
229 char *name; /* Signal name (not char_u!). */
230 char deadly; /* Catch as a deadly signal? */
231} signal_info[] =
232{
233#ifdef SIGHUP
234 {SIGHUP, "HUP", TRUE},
235#endif
236#ifdef SIGQUIT
237 {SIGQUIT, "QUIT", TRUE},
238#endif
239#ifdef SIGILL
240 {SIGILL, "ILL", TRUE},
241#endif
242#ifdef SIGTRAP
243 {SIGTRAP, "TRAP", TRUE},
244#endif
245#ifdef SIGABRT
246 {SIGABRT, "ABRT", TRUE},
247#endif
248#ifdef SIGEMT
249 {SIGEMT, "EMT", TRUE},
250#endif
251#ifdef SIGFPE
252 {SIGFPE, "FPE", TRUE},
253#endif
254#ifdef SIGBUS
255 {SIGBUS, "BUS", TRUE},
256#endif
257#ifdef SIGSEGV
258 {SIGSEGV, "SEGV", TRUE},
259#endif
260#ifdef SIGSYS
261 {SIGSYS, "SYS", TRUE},
262#endif
263#ifdef SIGALRM
264 {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
265#endif
266#ifdef SIGTERM
267 {SIGTERM, "TERM", TRUE},
268#endif
269#ifdef SIGVTALRM
270 {SIGVTALRM, "VTALRM", TRUE},
271#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000272#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
273 /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
274 * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000275 {SIGPROF, "PROF", TRUE},
276#endif
277#ifdef SIGXCPU
278 {SIGXCPU, "XCPU", TRUE},
279#endif
280#ifdef SIGXFSZ
281 {SIGXFSZ, "XFSZ", TRUE},
282#endif
283#ifdef SIGUSR1
284 {SIGUSR1, "USR1", TRUE},
285#endif
286#ifdef SIGUSR2
287 {SIGUSR2, "USR2", TRUE},
288#endif
289#ifdef SIGINT
290 {SIGINT, "INT", FALSE},
291#endif
292#ifdef SIGWINCH
293 {SIGWINCH, "WINCH", FALSE},
294#endif
295#ifdef SIGTSTP
296 {SIGTSTP, "TSTP", FALSE},
297#endif
298#ifdef SIGPIPE
299 {SIGPIPE, "PIPE", FALSE},
300#endif
301 {-1, "Unknown!", FALSE}
302};
303
304 void
305mch_write(s, len)
306 char_u *s;
307 int len;
308{
309 write(1, (char *)s, len);
310 if (p_wd) /* Unix is too fast, slow down a bit more */
311 RealWaitForChar(read_cmd_fd, p_wd, NULL);
312}
313
314/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000315 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000316 * Get a characters from the keyboard.
317 * Return the number of characters that are available.
318 * If wtime == 0 do not wait for characters.
319 * If wtime == n wait a short time for characters.
320 * If wtime == -1 wait forever for characters.
321 */
322 int
323mch_inchar(buf, maxlen, wtime, tb_change_cnt)
324 char_u *buf;
325 int maxlen;
326 long wtime; /* don't use "time", MIPS cannot handle it */
327 int tb_change_cnt;
328{
329 int len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000330
331 /* Check if window changed size while we were busy, perhaps the ":set
332 * columns=99" command was used. */
333 while (do_resize)
334 handle_resize();
335
336 if (wtime >= 0)
337 {
338 while (WaitForChar(wtime) == 0) /* no character available */
339 {
340 if (!do_resize) /* return if not interrupted by resize */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000341 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 handle_resize();
343 }
344 }
345 else /* wtime == -1 */
346 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347 /*
348 * If there is no character available within 'updatetime' seconds
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000349 * flush all the swap files to disk.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 * Also done when interrupted by SIGWINCH.
351 */
352 if (WaitForChar(p_ut) == 0)
353 {
354#ifdef FEAT_AUTOCMD
Bram Moolenaard35f9712005-12-18 22:02:33 +0000355 if (trigger_cursorhold() && maxlen >= 3
356 && !typebuf_changed(tb_change_cnt))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000357 {
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000358 buf[0] = K_SPECIAL;
359 buf[1] = KS_EXTRA;
360 buf[2] = (int)KE_CURSORHOLD;
361 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000362 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000363#endif
Bram Moolenaard4098f52005-06-27 22:37:13 +0000364 before_blocking();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000365 }
366 }
367
368 for (;;) /* repeat until we got a character */
369 {
370 while (do_resize) /* window changed size */
371 handle_resize();
372 /*
373 * we want to be interrupted by the winch signal
374 */
375 WaitForChar(-1L);
376 if (do_resize) /* interrupted by SIGWINCH signal */
377 continue;
378
379 /* If input was put directly in typeahead buffer bail out here. */
380 if (typebuf_changed(tb_change_cnt))
381 return 0;
382
383 /*
384 * For some terminals we only get one character at a time.
385 * We want the get all available characters, so we could keep on
386 * trying until none is available
387 * For some other terminals this is quite slow, that's why we don't do
388 * it.
389 */
390 len = read_from_input_buf(buf, (long)maxlen);
391 if (len > 0)
392 {
393#ifdef OS2
394 int i;
395
396 for (i = 0; i < len; i++)
397 if (buf[i] == 0)
398 buf[i] = K_NUL;
399#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000400 return len;
401 }
402 }
403}
404
405 static void
406handle_resize()
407{
408 do_resize = FALSE;
409 shell_resized();
410}
411
412/*
413 * return non-zero if a character is available
414 */
415 int
416mch_char_avail()
417{
418 return WaitForChar(0L);
419}
420
421#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
422# ifdef HAVE_SYS_RESOURCE_H
423# include <sys/resource.h>
424# endif
425# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
426# include <sys/sysctl.h>
427# endif
428# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
429# include <sys/sysinfo.h>
430# endif
431
432/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000433 * Return total amount of memory available in Kbyte.
434 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000435 */
436/* ARGSUSED */
437 long_u
438mch_total_mem(special)
439 int special;
440{
441# ifdef __EMX__
Bram Moolenaar914572a2007-05-01 11:37:47 +0000442 return ulimit(3, 0L) >> 10; /* always 32MB? */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000443# else
444 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000445 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000446
447# ifdef HAVE_SYSCTL
448 int mib[2], physmem;
449 size_t len;
450
451 /* BSD way of getting the amount of RAM available. */
452 mib[0] = CTL_HW;
453 mib[1] = HW_USERMEM;
454 len = sizeof(physmem);
455 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
456 mem = (long_u)physmem;
457# endif
458
459# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
460 if (mem == 0)
461 {
462 struct sysinfo sinfo;
463
464 /* Linux way of getting amount of RAM available */
465 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000466 {
467# ifdef HAVE_SYSINFO_MEM_UNIT
468 /* avoid overflow as much as possible */
469 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
470 {
471 sinfo.mem_unit = sinfo.mem_unit >> 1;
472 --shiftright;
473 }
474 mem = sinfo.totalram * sinfo.mem_unit;
475# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000476 mem = sinfo.totalram;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000477# endif
478 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000479 }
480# endif
481
482# ifdef HAVE_SYSCONF
483 if (mem == 0)
484 {
485 long pagesize, pagecount;
486
487 /* Solaris way of getting amount of RAM available */
488 pagesize = sysconf(_SC_PAGESIZE);
489 pagecount = sysconf(_SC_PHYS_PAGES);
490 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000491 {
492 /* avoid overflow as much as possible */
493 while (shiftright > 0 && (pagesize & 1) == 0)
494 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000495 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000496 --shiftright;
497 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000499 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500 }
501# endif
502
503 /* Return the minimum of the physical memory and the user limit, because
504 * using more than the user limit may cause Vim to be terminated. */
505# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
506 {
507 struct rlimit rlp;
508
509 if (getrlimit(RLIMIT_DATA, &rlp) == 0
510 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
511# ifdef RLIM_INFINITY
512 && rlp.rlim_cur != RLIM_INFINITY
513# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000514 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000515 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000516 {
517 mem = (long_u)rlp.rlim_cur;
518 shiftright = 10;
519 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000520 }
521# endif
522
523 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000524 return mem >> shiftright;
525 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526# endif
527}
528#endif
529
530 void
531mch_delay(msec, ignoreinput)
532 long msec;
533 int ignoreinput;
534{
535 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000536#ifdef FEAT_MZSCHEME
537 long total = msec; /* remember original value */
538#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000539
540 if (ignoreinput)
541 {
542 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000543 * here. But we don't want QUIT to kill us (CTRL-\ used in a
544 * shell may produce SIGQUIT). */
545 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546 old_tmode = curr_tmode;
547 if (curr_tmode == TMODE_RAW)
548 settmode(TMODE_SLEEP);
549
550 /*
551 * Everybody sleeps in a different way...
552 * Prefer nanosleep(), some versions of usleep() can only sleep up to
553 * one second.
554 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000555#ifdef FEAT_MZSCHEME
556 do
557 {
558 /* if total is large enough, wait by portions in p_mzq */
559 if (total > p_mzq)
560 msec = p_mzq;
561 else
562 msec = total;
563 total -= msec;
564#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565#ifdef HAVE_NANOSLEEP
566 {
567 struct timespec ts;
568
569 ts.tv_sec = msec / 1000;
570 ts.tv_nsec = (msec % 1000) * 1000000;
571 (void)nanosleep(&ts, NULL);
572 }
573#else
574# ifdef HAVE_USLEEP
575 while (msec >= 1000)
576 {
577 usleep((unsigned int)(999 * 1000));
578 msec -= 999;
579 }
580 usleep((unsigned int)(msec * 1000));
581# else
582# ifndef HAVE_SELECT
583 poll(NULL, 0, (int)msec);
584# else
585# ifdef __EMX__
586 _sleep2(msec);
587# else
588 {
589 struct timeval tv;
590
591 tv.tv_sec = msec / 1000;
592 tv.tv_usec = (msec % 1000) * 1000;
593 /*
594 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
595 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
596 */
597 select(0, NULL, NULL, NULL, &tv);
598 }
599# endif /* __EMX__ */
600# endif /* HAVE_SELECT */
601# endif /* HAVE_NANOSLEEP */
602#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000603#ifdef FEAT_MZSCHEME
604 }
605 while (total > 0);
606#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000607
608 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000609 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610 }
611 else
612 WaitForChar(msec);
613}
614
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000615#if 0 /* disabled, no longer needed now that regmatch() is not recursive */
616# if defined(HAVE_GETRLIMIT)
617# define HAVE_STACK_LIMIT
618# endif
619#endif
620
621#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
623# define HAVE_CHECK_STACK_GROWTH
624/*
625 * Support for checking for an almost-out-of-stack-space situation.
626 */
627
628/*
629 * Return a pointer to an item on the stack. Used to find out if the stack
630 * grows up or down.
631 */
632static void check_stack_growth __ARGS((char *p));
633static int stack_grows_downwards;
634
635/*
636 * Find out if the stack grows upwards or downwards.
637 * "p" points to a variable on the stack of the caller.
638 */
639 static void
640check_stack_growth(p)
641 char *p;
642{
643 int i;
644
645 stack_grows_downwards = (p > (char *)&i);
646}
647#endif
648
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000649#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000650static char *stack_limit = NULL;
651
652#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
653# include <pthread.h>
654# include <pthread_np.h>
655#endif
656
657/*
658 * Find out until how var the stack can grow without getting into trouble.
659 * Called when starting up and when switching to the signal stack in
660 * deathtrap().
661 */
662 static void
663get_stack_limit()
664{
665 struct rlimit rlp;
666 int i;
667 long lim;
668
669 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
670 * limit doesn't fit in a long (rlim_cur might be "long long"). */
671 if (getrlimit(RLIMIT_STACK, &rlp) == 0
672 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
673# ifdef RLIM_INFINITY
674 && rlp.rlim_cur != RLIM_INFINITY
675# endif
676 )
677 {
678 lim = (long)rlp.rlim_cur;
679#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
680 {
681 pthread_attr_t attr;
682 size_t size;
683
684 /* On FreeBSD the initial thread always has a fixed stack size, no
685 * matter what the limits are set to. Normally it's 1 Mbyte. */
686 pthread_attr_init(&attr);
687 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
688 {
689 pthread_attr_getstacksize(&attr, &size);
690 if (lim > (long)size)
691 lim = (long)size;
692 }
693 pthread_attr_destroy(&attr);
694 }
695#endif
696 if (stack_grows_downwards)
697 {
698 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
699 if (stack_limit >= (char *)&i)
700 /* overflow, set to 1/16 of current stack position */
701 stack_limit = (char *)((long)&i / 16L);
702 }
703 else
704 {
705 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
706 if (stack_limit <= (char *)&i)
707 stack_limit = NULL; /* overflow */
708 }
709 }
710}
711
712/*
713 * Return FAIL when running out of stack space.
714 * "p" must point to any variable local to the caller that's on the stack.
715 */
716 int
717mch_stackcheck(p)
718 char *p;
719{
720 if (stack_limit != NULL)
721 {
722 if (stack_grows_downwards)
723 {
724 if (p < stack_limit)
725 return FAIL;
726 }
727 else if (p > stack_limit)
728 return FAIL;
729 }
730 return OK;
731}
732#endif
733
734#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
735/*
736 * Support for using the signal stack.
737 * This helps when we run out of stack space, which causes a SIGSEGV. The
738 * signal handler then must run on another stack, since the normal stack is
739 * completely full.
740 */
741
742#ifndef SIGSTKSZ
743# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
744#endif
745
746# ifdef HAVE_SIGALTSTACK
747static stack_t sigstk; /* for sigaltstack() */
748# else
749static struct sigstack sigstk; /* for sigstack() */
750# endif
751
752static void init_signal_stack __ARGS((void));
753static char *signal_stack;
754
755 static void
756init_signal_stack()
757{
758 if (signal_stack != NULL)
759 {
760# ifdef HAVE_SIGALTSTACK
Bram Moolenaar1a3d0862007-08-30 09:47:38 +0000761# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
762 || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
764 * "struct sigaltstack" needs to be declared. */
765 extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
766# endif
767
768# ifdef HAVE_SS_BASE
769 sigstk.ss_base = signal_stack;
770# else
771 sigstk.ss_sp = signal_stack;
772# endif
773 sigstk.ss_size = SIGSTKSZ;
774 sigstk.ss_flags = 0;
775 (void)sigaltstack(&sigstk, NULL);
776# else
777 sigstk.ss_sp = signal_stack;
778 if (stack_grows_downwards)
779 sigstk.ss_sp += SIGSTKSZ - 1;
780 sigstk.ss_onstack = 0;
781 (void)sigstack(&sigstk, NULL);
782# endif
783 }
784}
785#endif
786
787/*
788 * We need correct potatotypes for a signal function, otherwise mean compilers
789 * will barf when the second argument to signal() is ``wrong''.
790 * Let me try it with a few tricky defines from my own osdef.h (jw).
791 */
792#if defined(SIGWINCH)
793/* ARGSUSED */
794 static RETSIGTYPE
795sig_winch SIGDEFARG(sigarg)
796{
797 /* this is not required on all systems, but it doesn't hurt anybody */
798 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
799 do_resize = TRUE;
800 SIGRETURN;
801}
802#endif
803
804#if defined(SIGINT)
805/* ARGSUSED */
806 static RETSIGTYPE
807catch_sigint SIGDEFARG(sigarg)
808{
809 /* this is not required on all systems, but it doesn't hurt anybody */
810 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
811 got_int = TRUE;
812 SIGRETURN;
813}
814#endif
815
816#if defined(SIGPWR)
817/* ARGSUSED */
818 static RETSIGTYPE
819catch_sigpwr SIGDEFARG(sigarg)
820{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000821 /* this is not required on all systems, but it doesn't hurt anybody */
822 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000823 /*
824 * I'm not sure we get the SIGPWR signal when the system is really going
825 * down or when the batteries are almost empty. Just preserve the swap
826 * files and don't exit, that can't do any harm.
827 */
828 ml_sync_all(FALSE, FALSE);
829 SIGRETURN;
830}
831#endif
832
833#ifdef SET_SIG_ALARM
834/*
835 * signal function for alarm().
836 */
837/* ARGSUSED */
838 static RETSIGTYPE
839sig_alarm SIGDEFARG(sigarg)
840{
841 /* doesn't do anything, just to break a system call */
842 sig_alarm_called = TRUE;
843 SIGRETURN;
844}
845#endif
846
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000847#if (defined(HAVE_SETJMP_H) \
848 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
849 || defined(FEAT_LIBCALL))) \
850 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000851/*
852 * A simplistic version of setjmp() that only allows one level of using.
853 * Don't call twice before calling mch_endjmp()!.
854 * Usage:
855 * mch_startjmp();
856 * if (SETJMP(lc_jump_env) != 0)
857 * {
858 * mch_didjmp();
859 * EMSG("crash!");
860 * }
861 * else
862 * {
863 * do_the_work;
864 * mch_endjmp();
865 * }
866 * Note: Can't move SETJMP() here, because a function calling setjmp() must
867 * not return before the saved environment is used.
868 * Returns OK for normal return, FAIL when the protected code caused a
869 * problem and LONGJMP() was used.
870 */
871 void
872mch_startjmp()
873{
874#ifdef SIGHASARG
875 lc_signal = 0;
876#endif
877 lc_active = TRUE;
878}
879
880 void
881mch_endjmp()
882{
883 lc_active = FALSE;
884}
885
886 void
887mch_didjmp()
888{
889# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
890 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
891 * otherwise catching the signal only works once. */
892 init_signal_stack();
893# endif
894}
895#endif
896
897/*
898 * This function handles deadly signals.
899 * It tries to preserve any swap file and exit properly.
900 * (partly from Elvis).
901 */
902 static RETSIGTYPE
903deathtrap SIGDEFARG(sigarg)
904{
905 static int entered = 0; /* count the number of times we got here.
906 Note: when memory has been corrupted
907 this may get an arbitrary value! */
908#ifdef SIGHASARG
909 int i;
910#endif
911
912#if defined(HAVE_SETJMP_H)
913 /*
914 * Catch a crash in protected code.
915 * Restores the environment saved in lc_jump_env, which looks like
916 * SETJMP() returns 1.
917 */
918 if (lc_active)
919 {
920# if defined(SIGHASARG)
921 lc_signal = sigarg;
922# endif
923 lc_active = FALSE; /* don't jump again */
924 LONGJMP(lc_jump_env, 1);
925 /* NOTREACHED */
926 }
927#endif
928
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000929#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000930# ifdef SIGQUIT
931 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
932 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
933 * pressing CTRL-\, but we don't want Vim to exit then. */
934 if (in_mch_delay && sigarg == SIGQUIT)
935 SIGRETURN;
936# endif
937
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000938 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
939 * here. This avoids that a non-reentrant function is interrupted, e.g.,
940 * free(). Calling free() again may then cause a crash. */
941 if (entered == 0
942 && (0
943# ifdef SIGHUP
944 || sigarg == SIGHUP
945# endif
946# ifdef SIGQUIT
947 || sigarg == SIGQUIT
948# endif
949# ifdef SIGTERM
950 || sigarg == SIGTERM
951# endif
952# ifdef SIGPWR
953 || sigarg == SIGPWR
954# endif
955# ifdef SIGUSR1
956 || sigarg == SIGUSR1
957# endif
958# ifdef SIGUSR2
959 || sigarg == SIGUSR2
960# endif
961 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +0000962 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000963 SIGRETURN;
964#endif
965
Bram Moolenaar071d4272004-06-13 20:20:40 +0000966 /* Remember how often we have been called. */
967 ++entered;
968
969#ifdef FEAT_EVAL
970 /* Set the v:dying variable. */
971 set_vim_var_nr(VV_DYING, (long)entered);
972#endif
973
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000974#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +0000975 /* Since we are now using the signal stack, need to reset the stack
976 * limit. Otherwise using a regexp will fail. */
977 get_stack_limit();
978#endif
979
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +0000980#if 0
981 /* This is for opening gdb the moment Vim crashes.
982 * You need to manually adjust the file name and Vim executable name.
983 * Suggested by SungHyun Nam. */
984 {
985# define VI_GDB_FILE "/tmp/vimgdb"
986# define VIM_NAME "/usr/bin/vim"
987 FILE *fp = fopen(VI_GDB_FILE, "w");
988 if (fp)
989 {
990 fprintf(fp,
991 "file %s\n"
992 "attach %d\n"
993 "set height 1000\n"
994 "bt full\n"
995 , VIM_NAME, getpid());
996 fclose(fp);
997 system("xterm -e gdb -x "VI_GDB_FILE);
998 unlink(VI_GDB_FILE);
999 }
1000 }
1001#endif
1002
Bram Moolenaar071d4272004-06-13 20:20:40 +00001003#ifdef SIGHASARG
1004 /* try to find the name of this signal */
1005 for (i = 0; signal_info[i].sig != -1; i++)
1006 if (sigarg == signal_info[i].sig)
1007 break;
1008 deadly_signal = sigarg;
1009#endif
1010
1011 full_screen = FALSE; /* don't write message to the GUI, it might be
1012 * part of the problem... */
1013 /*
1014 * If something goes wrong after entering here, we may get here again.
1015 * When this happens, give a message and try to exit nicely (resetting the
1016 * terminal mode, etc.)
1017 * When this happens twice, just exit, don't even try to give a message,
1018 * stack may be corrupt or something weird.
1019 * When this still happens again (or memory was corrupted in such a way
1020 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1021 */
1022 if (entered >= 3)
1023 {
1024 reset_signals(); /* don't catch any signals anymore */
1025 may_core_dump();
1026 if (entered >= 4)
1027 _exit(8);
1028 exit(7);
1029 }
1030 if (entered == 2)
1031 {
1032 OUT_STR(_("Vim: Double signal, exiting\n"));
1033 out_flush();
1034 getout(1);
1035 }
1036
1037#ifdef SIGHASARG
1038 sprintf((char *)IObuff, _("Vim: Caught deadly signal %s\n"),
1039 signal_info[i].name);
1040#else
1041 sprintf((char *)IObuff, _("Vim: Caught deadly signal\n"));
1042#endif
1043 preserve_exit(); /* preserve files and exit */
1044
Bram Moolenaar009b2592004-10-24 19:18:58 +00001045#ifdef NBDEBUG
1046 reset_signals();
1047 may_core_dump();
1048 abort();
1049#endif
1050
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051 SIGRETURN;
1052}
1053
1054#ifdef _REENTRANT
1055/*
1056 * On Solaris with multi-threading, suspending might not work immediately.
1057 * Catch the SIGCONT signal, which will be used as an indication whether the
1058 * suspending has been done or not.
1059 */
1060static int sigcont_received;
1061static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1062
1063/*
1064 * signal handler for SIGCONT
1065 */
1066/* ARGSUSED */
1067 static RETSIGTYPE
1068sigcont_handler SIGDEFARG(sigarg)
1069{
1070 sigcont_received = TRUE;
1071 SIGRETURN;
1072}
1073#endif
1074
1075/*
1076 * If the machine has job control, use it to suspend the program,
1077 * otherwise fake it by starting a new shell.
1078 */
1079 void
1080mch_suspend()
1081{
1082 /* BeOS does have SIGTSTP, but it doesn't work. */
1083#if defined(SIGTSTP) && !defined(__BEOS__)
1084 out_flush(); /* needed to make cursor visible on some systems */
1085 settmode(TMODE_COOK);
1086 out_flush(); /* needed to disable mouse on some systems */
1087
1088# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1089 /* Since we are going to sleep, we can't respond to requests for the X
1090 * selections. Lose them, otherwise other applications will hang. But
1091 * first copy the text to cut buffer 0. */
1092 if (clip_star.owned || clip_plus.owned)
1093 {
1094 x11_export_final_selection();
1095 if (clip_star.owned)
1096 clip_lose_selection(&clip_star);
1097 if (clip_plus.owned)
1098 clip_lose_selection(&clip_plus);
1099 if (x11_display != NULL)
1100 XFlush(x11_display);
1101 }
1102# endif
1103
1104# ifdef _REENTRANT
1105 sigcont_received = FALSE;
1106# endif
1107 kill(0, SIGTSTP); /* send ourselves a STOP signal */
1108# ifdef _REENTRANT
1109 /* When we didn't suspend immediately in the kill(), do it now. Happens
1110 * on multi-threaded Solaris. */
1111 if (!sigcont_received)
1112 pause();
1113# endif
1114
1115# ifdef FEAT_TITLE
1116 /*
1117 * Set oldtitle to NULL, so the current title is obtained again.
1118 */
1119 vim_free(oldtitle);
1120 oldtitle = NULL;
1121# endif
1122 settmode(TMODE_RAW);
1123 need_check_timestamps = TRUE;
1124 did_check_timestamps = FALSE;
1125#else
1126 suspend_shell();
1127#endif
1128}
1129
1130 void
1131mch_init()
1132{
1133 Columns = 80;
1134 Rows = 24;
1135
1136 out_flush();
1137 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001138
Bram Moolenaar56718732006-03-15 22:53:57 +00001139#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001140 mac_conv_init();
1141#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001142}
1143
1144 static void
1145set_signals()
1146{
1147#if defined(SIGWINCH)
1148 /*
1149 * WINDOW CHANGE signal is handled with sig_winch().
1150 */
1151 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1152#endif
1153
1154 /*
1155 * We want the STOP signal to work, to make mch_suspend() work.
1156 * For "rvim" the STOP signal is ignored.
1157 */
1158#ifdef SIGTSTP
1159 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1160#endif
1161#ifdef _REENTRANT
1162 signal(SIGCONT, sigcont_handler);
1163#endif
1164
1165 /*
1166 * We want to ignore breaking of PIPEs.
1167 */
1168#ifdef SIGPIPE
1169 signal(SIGPIPE, SIG_IGN);
1170#endif
1171
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001173 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001174#endif
1175
1176 /*
1177 * Ignore alarm signals (Perl's alarm() generates it).
1178 */
1179#ifdef SIGALRM
1180 signal(SIGALRM, SIG_IGN);
1181#endif
1182
1183 /*
1184 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1185 * work will be lost.
1186 */
1187#ifdef SIGPWR
1188 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1189#endif
1190
1191 /*
1192 * Arrange for other signals to gracefully shutdown Vim.
1193 */
1194 catch_signals(deathtrap, SIG_ERR);
1195
1196#if defined(FEAT_GUI) && defined(SIGHUP)
1197 /*
1198 * When the GUI is running, ignore the hangup signal.
1199 */
1200 if (gui.in_use)
1201 signal(SIGHUP, SIG_IGN);
1202#endif
1203}
1204
Bram Moolenaardf177f62005-02-22 08:39:57 +00001205#if defined(SIGINT) || defined(PROTO)
1206/*
1207 * Catch CTRL-C (only works while in Cooked mode).
1208 */
1209 static void
1210catch_int_signal()
1211{
1212 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1213}
1214#endif
1215
Bram Moolenaar071d4272004-06-13 20:20:40 +00001216 void
1217reset_signals()
1218{
1219 catch_signals(SIG_DFL, SIG_DFL);
1220#ifdef _REENTRANT
1221 /* SIGCONT isn't in the list, because its default action is ignore */
1222 signal(SIGCONT, SIG_DFL);
1223#endif
1224}
1225
1226 static void
1227catch_signals(func_deadly, func_other)
1228 RETSIGTYPE (*func_deadly)();
1229 RETSIGTYPE (*func_other)();
1230{
1231 int i;
1232
1233 for (i = 0; signal_info[i].sig != -1; i++)
1234 if (signal_info[i].deadly)
1235 {
1236#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1237 struct sigaction sa;
1238
1239 /* Setup to use the alternate stack for the signal function. */
1240 sa.sa_handler = func_deadly;
1241 sigemptyset(&sa.sa_mask);
1242# if defined(__linux__) && defined(_REENTRANT)
1243 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1244 * thread handling in combination with using the alternate stack:
1245 * pthread library functions try to use the stack pointer to
1246 * identify the current thread, causing a SEGV signal, which
1247 * recursively calls deathtrap() and hangs. */
1248 sa.sa_flags = 0;
1249# else
1250 sa.sa_flags = SA_ONSTACK;
1251# endif
1252 sigaction(signal_info[i].sig, &sa, NULL);
1253#else
1254# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1255 struct sigvec sv;
1256
1257 /* Setup to use the alternate stack for the signal function. */
1258 sv.sv_handler = func_deadly;
1259 sv.sv_mask = 0;
1260 sv.sv_flags = SV_ONSTACK;
1261 sigvec(signal_info[i].sig, &sv, NULL);
1262# else
1263 signal(signal_info[i].sig, func_deadly);
1264# endif
1265#endif
1266 }
1267 else if (func_other != SIG_ERR)
1268 signal(signal_info[i].sig, func_other);
1269}
1270
1271/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001272 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001273 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1274 * return TRUE
1275 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1276 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
1277 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001278 * Returns TRUE when Vim should exit.
1279 */
1280 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001281vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001282 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001283{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001284 static int got_signal = 0;
1285 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001286
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001287 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001288 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001289 case SIGNAL_BLOCK: blocked = TRUE;
1290 break;
1291
1292 case SIGNAL_UNBLOCK: blocked = FALSE;
1293 if (got_signal != 0)
1294 {
1295 kill(getpid(), got_signal);
1296 got_signal = 0;
1297 }
1298 break;
1299
1300 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001301 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001302 got_signal = sig;
1303#ifdef SIGPWR
1304 if (sig != SIGPWR)
1305#endif
1306 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001307 break;
1308 }
1309 return FALSE;
1310}
1311
1312/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001313 * Check_win checks whether we have an interactive stdout.
1314 */
1315/* ARGSUSED */
1316 int
1317mch_check_win(argc, argv)
1318 int argc;
1319 char **argv;
1320{
1321#ifdef OS2
1322 /*
1323 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1324 * name, mostly it's just "vim" and found in the path, which is unusable.
1325 */
1326 if (mch_isFullName(argv[0]))
1327 exe_name = vim_strsave((char_u *)argv[0]);
1328#endif
1329 if (isatty(1))
1330 return OK;
1331 return FAIL;
1332}
1333
1334/*
1335 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1336 */
1337 int
1338mch_input_isatty()
1339{
1340 if (isatty(read_cmd_fd))
1341 return TRUE;
1342 return FALSE;
1343}
1344
1345#ifdef FEAT_X11
1346
1347# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1348 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1349
1350static void xopen_message __ARGS((struct timeval *tvp));
1351
1352/*
1353 * Give a message about the elapsed time for opening the X window.
1354 */
1355 static void
1356xopen_message(tvp)
1357 struct timeval *tvp; /* must contain start time */
1358{
1359 struct timeval end_tv;
1360
1361 /* Compute elapsed time. */
1362 gettimeofday(&end_tv, NULL);
1363 smsg((char_u *)_("Opening the X display took %ld msec"),
1364 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001365 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001366}
1367# endif
1368#endif
1369
1370#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1371/*
1372 * A few functions shared by X11 title and clipboard code.
1373 */
1374static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1375static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1376static int x_connect_to_server __ARGS((void));
1377static int test_x11_window __ARGS((Display *dpy));
1378
1379static int got_x_error = FALSE;
1380
1381/*
1382 * X Error handler, otherwise X just exits! (very rude) -- webb
1383 */
1384 static int
1385x_error_handler(dpy, error_event)
1386 Display *dpy;
1387 XErrorEvent *error_event;
1388{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001389 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001390 STRCAT(IObuff, _("\nVim: Got X error\n"));
1391
1392 /* We cannot print a message and continue, because no X calls are allowed
1393 * here (causes my system to hang). Silently continuing might be an
1394 * alternative... */
1395 preserve_exit(); /* preserve files and exit */
1396
1397 return 0; /* NOTREACHED */
1398}
1399
1400/*
1401 * Another X Error handler, just used to check for errors.
1402 */
1403/* ARGSUSED */
1404 static int
1405x_error_check(dpy, error_event)
1406 Display *dpy;
1407 XErrorEvent *error_event;
1408{
1409 got_x_error = TRUE;
1410 return 0;
1411}
1412
1413#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1414# if defined(HAVE_SETJMP_H)
1415/*
1416 * An X IO Error handler, used to catch error while opening the display.
1417 */
1418static int x_IOerror_check __ARGS((Display *dpy));
1419
1420/* ARGSUSED */
1421 static int
1422x_IOerror_check(dpy)
1423 Display *dpy;
1424{
1425 /* This function should not return, it causes exit(). Longjump instead. */
1426 LONGJMP(lc_jump_env, 1);
1427 /*NOTREACHED*/
1428 return 0;
1429}
1430# endif
1431
1432/*
1433 * An X IO Error handler, used to catch terminal errors.
1434 */
1435static int x_IOerror_handler __ARGS((Display *dpy));
1436
1437/* ARGSUSED */
1438 static int
1439x_IOerror_handler(dpy)
1440 Display *dpy;
1441{
1442 xterm_dpy = NULL;
1443 x11_window = 0;
1444 x11_display = NULL;
1445 xterm_Shell = (Widget)0;
1446
1447 /* This function should not return, it causes exit(). Longjump instead. */
1448 LONGJMP(x_jump_env, 1);
1449 /*NOTREACHED*/
1450 return 0;
1451}
1452#endif
1453
1454/*
1455 * Return TRUE when connection to the X server is desired.
1456 */
1457 static int
1458x_connect_to_server()
1459{
1460 regmatch_T regmatch;
1461
1462#if defined(FEAT_CLIENTSERVER)
1463 if (x_force_connect)
1464 return TRUE;
1465#endif
1466 if (x_no_connect)
1467 return FALSE;
1468
1469 /* Check for a match with "exclude:" from 'clipboard'. */
1470 if (clip_exclude_prog != NULL)
1471 {
1472 regmatch.rm_ic = FALSE; /* Don't ignore case */
1473 regmatch.regprog = clip_exclude_prog;
1474 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1475 return FALSE;
1476 }
1477 return TRUE;
1478}
1479
1480/*
1481 * Test if "dpy" and x11_window are valid by getting the window title.
1482 * I don't actually want it yet, so there may be a simpler call to use, but
1483 * this will cause the error handler x_error_check() to be called if anything
1484 * is wrong, such as the window pointer being invalid (as can happen when the
1485 * user changes his DISPLAY, but not his WINDOWID) -- webb
1486 */
1487 static int
1488test_x11_window(dpy)
1489 Display *dpy;
1490{
1491 int (*old_handler)();
1492 XTextProperty text_prop;
1493
1494 old_handler = XSetErrorHandler(x_error_check);
1495 got_x_error = FALSE;
1496 if (XGetWMName(dpy, x11_window, &text_prop))
1497 XFree((void *)text_prop.value);
1498 XSync(dpy, False);
1499 (void)XSetErrorHandler(old_handler);
1500
1501 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001502 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001503
1504 return (got_x_error ? FAIL : OK);
1505}
1506#endif
1507
1508#ifdef FEAT_TITLE
1509
1510#ifdef FEAT_X11
1511
1512static int get_x11_thing __ARGS((int get_title, int test_only));
1513
1514/*
1515 * try to get x11 window and display
1516 *
1517 * return FAIL for failure, OK otherwise
1518 */
1519 static int
1520get_x11_windis()
1521{
1522 char *winid;
1523 static int result = -1;
1524#define XD_NONE 0 /* x11_display not set here */
1525#define XD_HERE 1 /* x11_display opened here */
1526#define XD_GUI 2 /* x11_display used from gui.dpy */
1527#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1528 static int x11_display_from = XD_NONE;
1529 static int did_set_error_handler = FALSE;
1530
1531 if (!did_set_error_handler)
1532 {
1533 /* X just exits if it finds an error otherwise! */
1534 (void)XSetErrorHandler(x_error_handler);
1535 did_set_error_handler = TRUE;
1536 }
1537
Bram Moolenaar9372a112005-12-06 19:59:18 +00001538#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001539 if (gui.in_use)
1540 {
1541 /*
1542 * If the X11 display was opened here before, for the window where Vim
1543 * was started, close that one now to avoid a memory leak.
1544 */
1545 if (x11_display_from == XD_HERE && x11_display != NULL)
1546 {
1547 XCloseDisplay(x11_display);
1548 x11_display_from = XD_NONE;
1549 }
1550 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1551 {
1552 x11_display_from = XD_GUI;
1553 return OK;
1554 }
1555 x11_display = NULL;
1556 return FAIL;
1557 }
1558 else if (x11_display_from == XD_GUI)
1559 {
1560 /* GUI must have stopped somehow, clear x11_display */
1561 x11_window = 0;
1562 x11_display = NULL;
1563 x11_display_from = XD_NONE;
1564 }
1565#endif
1566
1567 /* When started with the "-X" argument, don't try connecting. */
1568 if (!x_connect_to_server())
1569 return FAIL;
1570
1571 /*
1572 * If WINDOWID not set, should try another method to find out
1573 * what the current window number is. The only code I know for
1574 * this is very complicated.
1575 * We assume that zero is invalid for WINDOWID.
1576 */
1577 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1578 x11_window = (Window)atol(winid);
1579
1580#ifdef FEAT_XCLIPBOARD
1581 if (xterm_dpy != NULL && x11_window != 0)
1582 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001583 /* We may have checked it already, but Gnome terminal can move us to
1584 * another window, so we need to check every time. */
1585 if (x11_display_from != XD_XTERM)
1586 {
1587 /*
1588 * If the X11 display was opened here before, for the window where
1589 * Vim was started, close that one now to avoid a memory leak.
1590 */
1591 if (x11_display_from == XD_HERE && x11_display != NULL)
1592 XCloseDisplay(x11_display);
1593 x11_display = xterm_dpy;
1594 x11_display_from = XD_XTERM;
1595 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596 if (test_x11_window(x11_display) == FAIL)
1597 {
1598 /* probably bad $WINDOWID */
1599 x11_window = 0;
1600 x11_display = NULL;
1601 x11_display_from = XD_NONE;
1602 return FAIL;
1603 }
1604 return OK;
1605 }
1606#endif
1607
1608 if (x11_window == 0 || x11_display == NULL)
1609 result = -1;
1610
1611 if (result != -1) /* Have already been here and set this */
1612 return result; /* Don't do all these X calls again */
1613
1614 if (x11_window != 0 && x11_display == NULL)
1615 {
1616#ifdef SET_SIG_ALARM
1617 RETSIGTYPE (*sig_save)();
1618#endif
1619#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1620 struct timeval start_tv;
1621
1622 if (p_verbose > 0)
1623 gettimeofday(&start_tv, NULL);
1624#endif
1625
1626#ifdef SET_SIG_ALARM
1627 /*
1628 * Opening the Display may hang if the DISPLAY setting is wrong, or
1629 * the network connection is bad. Set an alarm timer to get out.
1630 */
1631 sig_alarm_called = FALSE;
1632 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1633 (RETSIGTYPE (*)())sig_alarm);
1634 alarm(2);
1635#endif
1636 x11_display = XOpenDisplay(NULL);
1637
1638#ifdef SET_SIG_ALARM
1639 alarm(0);
1640 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1641 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001642 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001643#endif
1644 if (x11_display != NULL)
1645 {
1646# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1647 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001648 {
1649 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001650 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001651 verbose_leave();
1652 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001653# endif
1654 if (test_x11_window(x11_display) == FAIL)
1655 {
1656 /* Maybe window id is bad */
1657 x11_window = 0;
1658 XCloseDisplay(x11_display);
1659 x11_display = NULL;
1660 }
1661 else
1662 x11_display_from = XD_HERE;
1663 }
1664 }
1665 if (x11_window == 0 || x11_display == NULL)
1666 return (result = FAIL);
1667 return (result = OK);
1668}
1669
1670/*
1671 * Determine original x11 Window Title
1672 */
1673 static int
1674get_x11_title(test_only)
1675 int test_only;
1676{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001677 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001678}
1679
1680/*
1681 * Determine original x11 Window icon
1682 */
1683 static int
1684get_x11_icon(test_only)
1685 int test_only;
1686{
1687 int retval = FALSE;
1688
1689 retval = get_x11_thing(FALSE, test_only);
1690
1691 /* could not get old icon, use terminal name */
1692 if (oldicon == NULL && !test_only)
1693 {
1694 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1695 oldicon = T_NAME + 8;
1696 else
1697 oldicon = T_NAME;
1698 }
1699
1700 return retval;
1701}
1702
1703 static int
1704get_x11_thing(get_title, test_only)
1705 int get_title; /* get title string */
1706 int test_only;
1707{
1708 XTextProperty text_prop;
1709 int retval = FALSE;
1710 Status status;
1711
1712 if (get_x11_windis() == OK)
1713 {
1714 /* Get window/icon name if any */
1715 if (get_title)
1716 status = XGetWMName(x11_display, x11_window, &text_prop);
1717 else
1718 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1719
1720 /*
1721 * If terminal is xterm, then x11_window may be a child window of the
1722 * outer xterm window that actually contains the window/icon name, so
1723 * keep traversing up the tree until a window with a title/icon is
1724 * found.
1725 */
1726 /* Previously this was only done for xterm and alikes. I don't see a
1727 * reason why it would fail for other terminal emulators.
1728 * if (term_is_xterm) */
1729 {
1730 Window root;
1731 Window parent;
1732 Window win = x11_window;
1733 Window *children;
1734 unsigned int num_children;
1735
1736 while (!status || text_prop.value == NULL)
1737 {
1738 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1739 &num_children))
1740 break;
1741 if (children)
1742 XFree((void *)children);
1743 if (parent == root || parent == 0)
1744 break;
1745
1746 win = parent;
1747 if (get_title)
1748 status = XGetWMName(x11_display, win, &text_prop);
1749 else
1750 status = XGetWMIconName(x11_display, win, &text_prop);
1751 }
1752 }
1753 if (status && text_prop.value != NULL)
1754 {
1755 retval = TRUE;
1756 if (!test_only)
1757 {
1758#ifdef FEAT_XFONTSET
1759 if (text_prop.encoding == XA_STRING)
1760 {
1761#endif
1762 if (get_title)
1763 oldtitle = vim_strsave((char_u *)text_prop.value);
1764 else
1765 oldicon = vim_strsave((char_u *)text_prop.value);
1766#ifdef FEAT_XFONTSET
1767 }
1768 else
1769 {
1770 char **cl;
1771 Status transform_status;
1772 int n = 0;
1773
1774 transform_status = XmbTextPropertyToTextList(x11_display,
1775 &text_prop,
1776 &cl, &n);
1777 if (transform_status >= Success && n > 0 && cl[0])
1778 {
1779 if (get_title)
1780 oldtitle = vim_strsave((char_u *) cl[0]);
1781 else
1782 oldicon = vim_strsave((char_u *) cl[0]);
1783 XFreeStringList(cl);
1784 }
1785 else
1786 {
1787 if (get_title)
1788 oldtitle = vim_strsave((char_u *)text_prop.value);
1789 else
1790 oldicon = vim_strsave((char_u *)text_prop.value);
1791 }
1792 }
1793#endif
1794 }
1795 XFree((void *)text_prop.value);
1796 }
1797 }
1798 return retval;
1799}
1800
1801/* Are Xutf8 functions available? Avoid error from old compilers. */
1802#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1803# if X_HAVE_UTF8_STRING
1804# define USE_UTF8_STRING
1805# endif
1806#endif
1807
1808/*
1809 * Set x11 Window Title
1810 *
1811 * get_x11_windis() must be called before this and have returned OK
1812 */
1813 static void
1814set_x11_title(title)
1815 char_u *title;
1816{
1817 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1818 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1819 * supported everywhere and STRING doesn't work for multi-byte titles.
1820 */
1821#ifdef USE_UTF8_STRING
1822 if (enc_utf8)
1823 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1824 NULL, NULL, 0, NULL, NULL, NULL);
1825 else
1826#endif
1827 {
1828#if XtSpecificationRelease >= 4
1829# ifdef FEAT_XFONTSET
1830 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1831 NULL, NULL, 0, NULL, NULL, NULL);
1832# else
1833 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001834 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835
1836 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001837 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001838 XSetWMProperties(x11_display, x11_window, &text_prop,
1839 NULL, NULL, 0, NULL, NULL, NULL);
1840# endif
1841#else
1842 XStoreName(x11_display, x11_window, (char *)title);
1843#endif
1844 }
1845 XFlush(x11_display);
1846}
1847
1848/*
1849 * Set x11 Window icon
1850 *
1851 * get_x11_windis() must be called before this and have returned OK
1852 */
1853 static void
1854set_x11_icon(icon)
1855 char_u *icon;
1856{
1857 /* See above for comments about using X*SetWMProperties(). */
1858#ifdef USE_UTF8_STRING
1859 if (enc_utf8)
1860 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1861 NULL, 0, NULL, NULL, NULL);
1862 else
1863#endif
1864 {
1865#if XtSpecificationRelease >= 4
1866# ifdef FEAT_XFONTSET
1867 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1868 NULL, 0, NULL, NULL, NULL);
1869# else
1870 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001871 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001872
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001873 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001874 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
1875 NULL, 0, NULL, NULL, NULL);
1876# endif
1877#else
1878 XSetIconName(x11_display, x11_window, (char *)icon);
1879#endif
1880 }
1881 XFlush(x11_display);
1882}
1883
1884#else /* FEAT_X11 */
1885
1886/*ARGSUSED*/
1887 static int
1888get_x11_title(test_only)
1889 int test_only;
1890{
1891 return FALSE;
1892}
1893
1894 static int
1895get_x11_icon(test_only)
1896 int test_only;
1897{
1898 if (!test_only)
1899 {
1900 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1901 oldicon = T_NAME + 8;
1902 else
1903 oldicon = T_NAME;
1904 }
1905 return FALSE;
1906}
1907
1908#endif /* FEAT_X11 */
1909
1910 int
1911mch_can_restore_title()
1912{
1913 return get_x11_title(TRUE);
1914}
1915
1916 int
1917mch_can_restore_icon()
1918{
1919 return get_x11_icon(TRUE);
1920}
1921
1922/*
1923 * Set the window title and icon.
1924 */
1925 void
1926mch_settitle(title, icon)
1927 char_u *title;
1928 char_u *icon;
1929{
1930 int type = 0;
1931 static int recursive = 0;
1932
1933 if (T_NAME == NULL) /* no terminal name (yet) */
1934 return;
1935 if (title == NULL && icon == NULL) /* nothing to do */
1936 return;
1937
1938 /* When one of the X11 functions causes a deadly signal, we get here again
1939 * recursively. Avoid hanging then (something is probably locked). */
1940 if (recursive)
1941 return;
1942 ++recursive;
1943
1944 /*
1945 * if the window ID and the display is known, we may use X11 calls
1946 */
1947#ifdef FEAT_X11
1948 if (get_x11_windis() == OK)
1949 type = 1;
1950#else
1951# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
1952 if (gui.in_use)
1953 type = 1;
1954# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001955#endif
1956
1957 /*
1958 * Note: if "t_TS" is set, title is set with escape sequence rather
1959 * than x11 calls, because the x11 calls don't always work
1960 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001961 if ((type || *T_TS != NUL) && title != NULL)
1962 {
1963 if (oldtitle == NULL
1964#ifdef FEAT_GUI
1965 && !gui.in_use
1966#endif
1967 ) /* first call but not in GUI, save title */
1968 (void)get_x11_title(FALSE);
1969
1970 if (*T_TS != NUL) /* it's OK if t_fs is empty */
1971 term_settitle(title);
1972#ifdef FEAT_X11
1973 else
1974# ifdef FEAT_GUI_GTK
1975 if (!gui.in_use) /* don't do this if GTK+ is running */
1976# endif
1977 set_x11_title(title); /* x11 */
1978#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00001979#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001980 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
1981 else
1982 gui_mch_settitle(title, icon);
1983#endif
1984 did_set_title = TRUE;
1985 }
1986
1987 if ((type || *T_CIS != NUL) && icon != NULL)
1988 {
1989 if (oldicon == NULL
1990#ifdef FEAT_GUI
1991 && !gui.in_use
1992#endif
1993 ) /* first call, save icon */
1994 get_x11_icon(FALSE);
1995
1996 if (*T_CIS != NUL)
1997 {
1998 out_str(T_CIS); /* set icon start */
1999 out_str_nf(icon);
2000 out_str(T_CIE); /* set icon end */
2001 out_flush();
2002 }
2003#ifdef FEAT_X11
2004 else
2005# ifdef FEAT_GUI_GTK
2006 if (!gui.in_use) /* don't do this if GTK+ is running */
2007# endif
2008 set_x11_icon(icon); /* x11 */
2009#endif
2010 did_set_icon = TRUE;
2011 }
2012 --recursive;
2013}
2014
2015/*
2016 * Restore the window/icon title.
2017 * "which" is one of:
2018 * 1 only restore title
2019 * 2 only restore icon
2020 * 3 restore title and icon
2021 */
2022 void
2023mch_restore_title(which)
2024 int which;
2025{
2026 /* only restore the title or icon when it has been set */
2027 mch_settitle(((which & 1) && did_set_title) ?
2028 (oldtitle ? oldtitle : p_titleold) : NULL,
2029 ((which & 2) && did_set_icon) ? oldicon : NULL);
2030}
2031
2032#endif /* FEAT_TITLE */
2033
2034/*
2035 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002036 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002037 */
2038 int
2039vim_is_xterm(name)
2040 char_u *name;
2041{
2042 if (name == NULL)
2043 return FALSE;
2044 return (STRNICMP(name, "xterm", 5) == 0
2045 || STRNICMP(name, "nxterm", 6) == 0
2046 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002047 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002048 || STRNICMP(name, "rxvt", 4) == 0
2049 || STRCMP(name, "builtin_xterm") == 0);
2050}
2051
2052#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2053/*
2054 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2055 * Return 1 for "xterm".
2056 * Return 2 for "xterm2".
2057 */
2058 int
2059use_xterm_mouse()
2060{
2061 if (ttym_flags == TTYM_XTERM2)
2062 return 2;
2063 if (ttym_flags == TTYM_XTERM)
2064 return 1;
2065 return 0;
2066}
2067#endif
2068
2069 int
2070vim_is_iris(name)
2071 char_u *name;
2072{
2073 if (name == NULL)
2074 return FALSE;
2075 return (STRNICMP(name, "iris-ansi", 9) == 0
2076 || STRCMP(name, "builtin_iris-ansi") == 0);
2077}
2078
2079 int
2080vim_is_vt300(name)
2081 char_u *name;
2082{
2083 if (name == NULL)
2084 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002085 /* catch VT100 - VT5xx */
2086 return ((STRNICMP(name, "vt", 2) == 0
2087 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002088 || STRCMP(name, "builtin_vt320") == 0);
2089}
2090
2091/*
2092 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2093 * This should include all windowed terminal emulators.
2094 */
2095 int
2096vim_is_fastterm(name)
2097 char_u *name;
2098{
2099 if (name == NULL)
2100 return FALSE;
2101 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2102 return TRUE;
2103 return ( STRNICMP(name, "hpterm", 6) == 0
2104 || STRNICMP(name, "sun-cmd", 7) == 0
2105 || STRNICMP(name, "screen", 6) == 0
2106 || STRNICMP(name, "dtterm", 6) == 0);
2107}
2108
2109/*
2110 * Insert user name in s[len].
2111 * Return OK if a name found.
2112 */
2113 int
2114mch_get_user_name(s, len)
2115 char_u *s;
2116 int len;
2117{
2118#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002119 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002120 return OK;
2121#else
2122 return mch_get_uname(getuid(), s, len);
2123#endif
2124}
2125
2126/*
2127 * Insert user name for "uid" in s[len].
2128 * Return OK if a name found.
2129 */
2130 int
2131mch_get_uname(uid, s, len)
2132 uid_t uid;
2133 char_u *s;
2134 int len;
2135{
2136#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2137 struct passwd *pw;
2138
2139 if ((pw = getpwuid(uid)) != NULL
2140 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2141 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002142 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002143 return OK;
2144 }
2145#endif
2146 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2147 return FAIL; /* a number is not a name */
2148}
2149
2150/*
2151 * Insert host name is s[len].
2152 */
2153
2154#ifdef HAVE_SYS_UTSNAME_H
2155 void
2156mch_get_host_name(s, len)
2157 char_u *s;
2158 int len;
2159{
2160 struct utsname vutsname;
2161
2162 if (uname(&vutsname) < 0)
2163 *s = NUL;
2164 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002165 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002166}
2167#else /* HAVE_SYS_UTSNAME_H */
2168
2169# ifdef HAVE_SYS_SYSTEMINFO_H
2170# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2171# endif
2172
2173 void
2174mch_get_host_name(s, len)
2175 char_u *s;
2176 int len;
2177{
2178# ifdef VAXC
2179 vaxc$gethostname((char *)s, len);
2180# else
2181 gethostname((char *)s, len);
2182# endif
2183 s[len - 1] = NUL; /* make sure it's terminated */
2184}
2185#endif /* HAVE_SYS_UTSNAME_H */
2186
2187/*
2188 * return process ID
2189 */
2190 long
2191mch_get_pid()
2192{
2193 return (long)getpid();
2194}
2195
2196#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2197static char *strerror __ARGS((int));
2198
2199 static char *
2200strerror(err)
2201 int err;
2202{
2203 extern int sys_nerr;
2204 extern char *sys_errlist[];
2205 static char er[20];
2206
2207 if (err > 0 && err < sys_nerr)
2208 return (sys_errlist[err]);
2209 sprintf(er, "Error %d", err);
2210 return er;
2211}
2212#endif
2213
2214/*
2215 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2216 * Return OK for success, FAIL for failure.
2217 */
2218 int
2219mch_dirname(buf, len)
2220 char_u *buf;
2221 int len;
2222{
2223#if defined(USE_GETCWD)
2224 if (getcwd((char *)buf, len) == NULL)
2225 {
2226 STRCPY(buf, strerror(errno));
2227 return FAIL;
2228 }
2229 return OK;
2230#else
2231 return (getwd((char *)buf) != NULL ? OK : FAIL);
2232#endif
2233}
2234
2235#if defined(OS2) || defined(PROTO)
2236/*
2237 * Replace all slashes by backslashes.
2238 * When 'shellslash' set do it the other way around.
2239 */
2240 void
2241slash_adjust(p)
2242 char_u *p;
2243{
2244 while (*p)
2245 {
2246 if (*p == psepcN)
2247 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002248 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249 }
2250}
2251#endif
2252
2253/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002254 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255 *
2256 * return FAIL for failure, OK for success
2257 */
2258 int
2259mch_FullName(fname, buf, len, force)
2260 char_u *fname, *buf;
2261 int len;
2262 int force; /* also expand when already absolute path */
2263{
2264 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002265#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002266 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002267#endif
2268#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002269 int fd = -1;
2270 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002271#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002272 char_u olddir[MAXPATHL];
2273 char_u *p;
2274 int retval = OK;
2275
Bram Moolenaar38323e42007-03-06 19:22:53 +00002276#ifdef VMS
2277 fname = vms_fixfilename(fname);
2278#endif
2279
Bram Moolenaara2442432007-04-26 14:26:37 +00002280#ifdef __CYGWIN__
2281 /*
2282 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2283 */
2284 cygwin_conv_to_posix_path(fname, fname);
2285#endif
2286
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287 /* expand it if forced or not an absolute path */
2288 if (force || !mch_isFullName(fname))
2289 {
2290 /*
2291 * If the file name has a path, change to that directory for a moment,
2292 * and then do the getwd() (and get back to where we were).
2293 * This will get the correct path name with "../" things.
2294 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002295#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296 only_drive = 0;
2297 if (((p = vim_strrchr(fname, '/')) != NULL)
2298 || ((p = vim_strrchr(fname, '\\')) != NULL)
2299 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002300#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002301 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002302#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002303 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002304#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002305 /*
2306 * Use fchdir() if possible, it's said to be faster and more
2307 * reliable. But on SunOS 4 it might not work. Check this by
2308 * doing a fchdir() right now.
2309 */
2310 if (!dont_fchdir)
2311 {
2312 fd = open(".", O_RDONLY | O_EXTRA, 0);
2313 if (fd >= 0 && fchdir(fd) < 0)
2314 {
2315 close(fd);
2316 fd = -1;
2317 dont_fchdir = TRUE; /* don't try again */
2318 }
2319 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002320#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002321
2322 /* Only change directory when we are sure we can return to where
2323 * we are now. After doing "su" chdir(".") might not work. */
2324 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002325#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002326 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002327#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328 (mch_dirname(olddir, MAXPATHL) == FAIL
2329 || mch_chdir((char *)olddir) != 0))
2330 {
2331 p = NULL; /* can't get current dir: don't chdir */
2332 retval = FAIL;
2333 }
2334 else
2335 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002336#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337 /*
2338 * compensate for case where ':' from "D:" was the only
2339 * path separator detected in the file name; the _next_
2340 * character has to be removed, and then restored later.
2341 */
2342 if (only_drive)
2343 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002344#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002345 /* The directory is copied into buf[], to be able to remove
2346 * the file name without changing it (could be a string in
2347 * read-only memory) */
2348 if (p - fname >= len)
2349 retval = FAIL;
2350 else
2351 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002352 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002353 if (mch_chdir((char *)buf))
2354 retval = FAIL;
2355 else
2356 fname = p + 1;
2357 *buf = NUL;
2358 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002359#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 if (only_drive)
2361 {
2362 p--;
2363 if (retval != FAIL)
2364 fname--;
2365 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002366#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367 }
2368 }
2369 if (mch_dirname(buf, len) == FAIL)
2370 {
2371 retval = FAIL;
2372 *buf = NUL;
2373 }
2374 if (p != NULL)
2375 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002376#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 if (fd >= 0)
2378 {
2379 l = fchdir(fd);
2380 close(fd);
2381 }
2382 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002383#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002384 l = mch_chdir((char *)olddir);
2385 if (l != 0)
2386 EMSG(_(e_prev_dir));
2387 }
2388
2389 l = STRLEN(buf);
2390 if (l >= len)
2391 retval = FAIL;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002392#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002393 else
2394 {
2395 if (l > 0 && buf[l - 1] != '/' && *fname != NUL
2396 && STRCMP(fname, ".") != 0)
2397 STRCAT(buf, "/");
2398 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002399#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002400 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002401
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402 /* Catch file names which are too long. */
2403 if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len)
2404 return FAIL;
2405
2406 /* Do not append ".", "/dir/." is equal to "/dir". */
2407 if (STRCMP(fname, ".") != 0)
2408 STRCAT(buf, fname);
2409
2410 return OK;
2411}
2412
2413/*
2414 * Return TRUE if "fname" does not depend on the current directory.
2415 */
2416 int
2417mch_isFullName(fname)
2418 char_u *fname;
2419{
2420#ifdef __EMX__
2421 return _fnisabs(fname);
2422#else
2423# ifdef VMS
2424 return ( fname[0] == '/' || fname[0] == '.' ||
2425 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2426 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2427 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2428# else
2429 return (*fname == '/' || *fname == '~');
2430# endif
2431#endif
2432}
2433
Bram Moolenaar24552be2005-12-10 20:17:30 +00002434#if defined(USE_FNAME_CASE) || defined(PROTO)
2435/*
2436 * Set the case of the file name, if it already exists. This will cause the
2437 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002438 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002439 */
2440/*ARGSUSED*/
2441 void
2442fname_case(name, len)
2443 char_u *name;
2444 int len; /* buffer size, only used when name gets longer */
2445{
2446 struct stat st;
2447 char_u *slash, *tail;
2448 DIR *dirp;
2449 struct dirent *dp;
2450
2451 if (lstat((char *)name, &st) >= 0)
2452 {
2453 /* Open the directory where the file is located. */
2454 slash = vim_strrchr(name, '/');
2455 if (slash == NULL)
2456 {
2457 dirp = opendir(".");
2458 tail = name;
2459 }
2460 else
2461 {
2462 *slash = NUL;
2463 dirp = opendir((char *)name);
2464 *slash = '/';
2465 tail = slash + 1;
2466 }
2467
2468 if (dirp != NULL)
2469 {
2470 while ((dp = readdir(dirp)) != NULL)
2471 {
2472 /* Only accept names that differ in case and are the same byte
2473 * length. TODO: accept different length name. */
2474 if (STRICMP(tail, dp->d_name) == 0
2475 && STRLEN(tail) == STRLEN(dp->d_name))
2476 {
2477 char_u newname[MAXPATHL + 1];
2478 struct stat st2;
2479
2480 /* Verify the inode is equal. */
2481 vim_strncpy(newname, name, MAXPATHL);
2482 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2483 MAXPATHL - (tail - name));
2484 if (lstat((char *)newname, &st2) >= 0
2485 && st.st_ino == st2.st_ino
2486 && st.st_dev == st2.st_dev)
2487 {
2488 STRCPY(tail, dp->d_name);
2489 break;
2490 }
2491 }
2492 }
2493
2494 closedir(dirp);
2495 }
2496 }
2497}
2498#endif
2499
Bram Moolenaar071d4272004-06-13 20:20:40 +00002500/*
2501 * Get file permissions for 'name'.
2502 * Returns -1 when it doesn't exist.
2503 */
2504 long
2505mch_getperm(name)
2506 char_u *name;
2507{
2508 struct stat statb;
2509
2510 /* Keep the #ifdef outside of stat(), it may be a macro. */
2511#ifdef VMS
2512 if (stat((char *)vms_fixfilename(name), &statb))
2513#else
2514 if (stat((char *)name, &statb))
2515#endif
2516 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002517#ifdef __INTERIX
2518 /* The top bit makes the value negative, which means the file doesn't
2519 * exist. Remove the bit, we don't use it. */
2520 return statb.st_mode & ~S_ADDACE;
2521#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002522 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002523#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002524}
2525
2526/*
2527 * set file permission for 'name' to 'perm'
2528 *
2529 * return FAIL for failure, OK otherwise
2530 */
2531 int
2532mch_setperm(name, perm)
2533 char_u *name;
2534 long perm;
2535{
2536 return (chmod((char *)
2537#ifdef VMS
2538 vms_fixfilename(name),
2539#else
2540 name,
2541#endif
2542 (mode_t)perm) == 0 ? OK : FAIL);
2543}
2544
2545#if defined(HAVE_ACL) || defined(PROTO)
2546# ifdef HAVE_SYS_ACL_H
2547# include <sys/acl.h>
2548# endif
2549# ifdef HAVE_SYS_ACCESS_H
2550# include <sys/access.h>
2551# endif
2552
2553# ifdef HAVE_SOLARIS_ACL
2554typedef struct vim_acl_solaris_T {
2555 int acl_cnt;
2556 aclent_t *acl_entry;
2557} vim_acl_solaris_T;
2558# endif
2559
2560/*
2561 * Return a pointer to the ACL of file "fname" in allocated memory.
2562 * Return NULL if the ACL is not available for whatever reason.
2563 */
2564 vim_acl_T
2565mch_get_acl(fname)
2566 char_u *fname;
2567{
2568 vim_acl_T ret = NULL;
2569#ifdef HAVE_POSIX_ACL
2570 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2571#else
2572#ifdef HAVE_SOLARIS_ACL
2573 vim_acl_solaris_T *aclent;
2574
2575 aclent = malloc(sizeof(vim_acl_solaris_T));
2576 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2577 {
2578 free(aclent);
2579 return NULL;
2580 }
2581 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2582 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2583 {
2584 free(aclent->acl_entry);
2585 free(aclent);
2586 return NULL;
2587 }
2588 ret = (vim_acl_T)aclent;
2589#else
2590#if defined(HAVE_AIX_ACL)
2591 int aclsize;
2592 struct acl *aclent;
2593
2594 aclsize = sizeof(struct acl);
2595 aclent = malloc(aclsize);
2596 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2597 {
2598 if (errno == ENOSPC)
2599 {
2600 aclsize = aclent->acl_len;
2601 aclent = realloc(aclent, aclsize);
2602 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2603 {
2604 free(aclent);
2605 return NULL;
2606 }
2607 }
2608 else
2609 {
2610 free(aclent);
2611 return NULL;
2612 }
2613 }
2614 ret = (vim_acl_T)aclent;
2615#endif /* HAVE_AIX_ACL */
2616#endif /* HAVE_SOLARIS_ACL */
2617#endif /* HAVE_POSIX_ACL */
2618 return ret;
2619}
2620
2621/*
2622 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2623 */
2624 void
2625mch_set_acl(fname, aclent)
2626 char_u *fname;
2627 vim_acl_T aclent;
2628{
2629 if (aclent == NULL)
2630 return;
2631#ifdef HAVE_POSIX_ACL
2632 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2633#else
2634#ifdef HAVE_SOLARIS_ACL
2635 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2636 ((vim_acl_solaris_T *)aclent)->acl_entry);
2637#else
2638#ifdef HAVE_AIX_ACL
2639 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2640#endif /* HAVE_AIX_ACL */
2641#endif /* HAVE_SOLARIS_ACL */
2642#endif /* HAVE_POSIX_ACL */
2643}
2644
2645 void
2646mch_free_acl(aclent)
2647 vim_acl_T aclent;
2648{
2649 if (aclent == NULL)
2650 return;
2651#ifdef HAVE_POSIX_ACL
2652 acl_free((acl_t)aclent);
2653#else
2654#ifdef HAVE_SOLARIS_ACL
2655 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2656 free(aclent);
2657#else
2658#ifdef HAVE_AIX_ACL
2659 free(aclent);
2660#endif /* HAVE_AIX_ACL */
2661#endif /* HAVE_SOLARIS_ACL */
2662#endif /* HAVE_POSIX_ACL */
2663}
2664#endif
2665
2666/*
2667 * Set hidden flag for "name".
2668 */
2669/* ARGSUSED */
2670 void
2671mch_hide(name)
2672 char_u *name;
2673{
2674 /* can't hide a file */
2675}
2676
2677/*
2678 * return TRUE if "name" is a directory
2679 * return FALSE if "name" is not a directory
2680 * return FALSE for error
2681 */
2682 int
2683mch_isdir(name)
2684 char_u *name;
2685{
2686 struct stat statb;
2687
2688 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2689 return FALSE;
2690 if (stat((char *)name, &statb))
2691 return FALSE;
2692#ifdef _POSIX_SOURCE
2693 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2694#else
2695 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2696#endif
2697}
2698
Bram Moolenaar071d4272004-06-13 20:20:40 +00002699static int executable_file __ARGS((char_u *name));
2700
2701/*
2702 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2703 */
2704 static int
2705executable_file(name)
2706 char_u *name;
2707{
2708 struct stat st;
2709
2710 if (stat((char *)name, &st))
2711 return 0;
2712 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2713}
2714
2715/*
2716 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2717 * Return -1 if unknown.
2718 */
2719 int
2720mch_can_exe(name)
2721 char_u *name;
2722{
2723 char_u *buf;
2724 char_u *p, *e;
2725 int retval;
2726
2727 /* If it's an absolute or relative path don't need to use $PATH. */
2728 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2729 || (name[1] == '.' && name[2] == '/'))))
2730 return executable_file(name);
2731
2732 p = (char_u *)getenv("PATH");
2733 if (p == NULL || *p == NUL)
2734 return -1;
2735 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2736 if (buf == NULL)
2737 return -1;
2738
2739 /*
2740 * Walk through all entries in $PATH to check if "name" exists there and
2741 * is an executable file.
2742 */
2743 for (;;)
2744 {
2745 e = (char_u *)strchr((char *)p, ':');
2746 if (e == NULL)
2747 e = p + STRLEN(p);
2748 if (e - p <= 1) /* empty entry means current dir */
2749 STRCPY(buf, "./");
2750 else
2751 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002752 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002753 add_pathsep(buf);
2754 }
2755 STRCAT(buf, name);
2756 retval = executable_file(buf);
2757 if (retval == 1)
2758 break;
2759
2760 if (*e != ':')
2761 break;
2762 p = e + 1;
2763 }
2764
2765 vim_free(buf);
2766 return retval;
2767}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002768
2769/*
2770 * Check what "name" is:
2771 * NODE_NORMAL: file or directory (or doesn't exist)
2772 * NODE_WRITABLE: writable device, socket, fifo, etc.
2773 * NODE_OTHER: non-writable things
2774 */
2775 int
2776mch_nodetype(name)
2777 char_u *name;
2778{
2779 struct stat st;
2780
2781 if (stat((char *)name, &st))
2782 return NODE_NORMAL;
2783 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2784 return NODE_NORMAL;
2785#ifndef OS2
2786 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2787 return NODE_OTHER;
2788#endif
2789 /* Everything else is writable? */
2790 return NODE_WRITABLE;
2791}
2792
2793 void
2794mch_early_init()
2795{
2796#ifdef HAVE_CHECK_STACK_GROWTH
2797 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002798
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799 check_stack_growth((char *)&i);
2800
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002801# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002802 get_stack_limit();
2803# endif
2804
2805#endif
2806
2807 /*
2808 * Setup an alternative stack for signals. Helps to catch signals when
2809 * running out of stack space.
2810 * Use of sigaltstack() is preferred, it's more portable.
2811 * Ignore any errors.
2812 */
2813#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2814 signal_stack = malloc(SIGSTKSZ);
2815 init_signal_stack();
2816#endif
2817}
2818
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002819#if defined(EXITFREE) || defined(PROTO)
2820 void
2821mch_free_mem()
2822{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002823# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2824 if (clip_star.owned)
2825 clip_lose_selection(&clip_star);
2826 if (clip_plus.owned)
2827 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002828# endif
2829# if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
2830 if (xterm_Shell != (Widget)0)
2831 XtDestroyWidget(xterm_Shell);
2832 if (xterm_dpy != NULL)
2833 XtCloseDisplay(xterm_dpy);
2834 if (app_context != (XtAppContext)NULL)
2835 XtDestroyApplicationContext(app_context);
2836# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002837# ifdef FEAT_X11
2838 if (x11_display != NULL && x11_display != xterm_dpy)
2839 XCloseDisplay(x11_display);
2840# endif
2841# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2842 vim_free(signal_stack);
2843 signal_stack = NULL;
2844# endif
2845# ifdef FEAT_TITLE
2846 vim_free(oldtitle);
2847 vim_free(oldicon);
2848# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002849}
2850#endif
2851
Bram Moolenaar071d4272004-06-13 20:20:40 +00002852static void exit_scroll __ARGS((void));
2853
2854/*
2855 * Output a newline when exiting.
2856 * Make sure the newline goes to the same stream as the text.
2857 */
2858 static void
2859exit_scroll()
2860{
Bram Moolenaardf177f62005-02-22 08:39:57 +00002861 if (silent_mode)
2862 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002863 if (newline_on_exit || msg_didout)
2864 {
2865 if (msg_use_printf())
2866 {
2867 if (info_message)
2868 mch_msg("\n");
2869 else
2870 mch_errmsg("\r\n");
2871 }
2872 else
2873 out_char('\n');
2874 }
2875 else
2876 {
2877 restore_cterm_colors(); /* get original colors back */
2878 msg_clr_eos_force(); /* clear the rest of the display */
2879 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
2880 }
2881}
2882
2883 void
2884mch_exit(r)
2885 int r;
2886{
2887 exiting = TRUE;
2888
2889#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
2890 x11_export_final_selection();
2891#endif
2892
2893#ifdef FEAT_GUI
2894 if (!gui.in_use)
2895#endif
2896 {
2897 settmode(TMODE_COOK);
2898#ifdef FEAT_TITLE
2899 mch_restore_title(3); /* restore xterm title and icon name */
2900#endif
2901 /*
2902 * When t_ti is not empty but it doesn't cause swapping terminal
2903 * pages, need to output a newline when msg_didout is set. But when
2904 * t_ti does swap pages it should not go to the shell page. Do this
2905 * before stoptermcap().
2906 */
2907 if (swapping_screen() && !newline_on_exit)
2908 exit_scroll();
2909
2910 /* Stop termcap: May need to check for T_CRV response, which
2911 * requires RAW mode. */
2912 stoptermcap();
2913
2914 /*
2915 * A newline is only required after a message in the alternate screen.
2916 * This is set to TRUE by wait_return().
2917 */
2918 if (!swapping_screen() || newline_on_exit)
2919 exit_scroll();
2920
2921 /* Cursor may have been switched off without calling starttermcap()
2922 * when doing "vim -u vimrc" and vimrc contains ":q". */
2923 if (full_screen)
2924 cursor_on();
2925 }
2926 out_flush();
2927 ml_close_all(TRUE); /* remove all memfiles */
2928 may_core_dump();
2929#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002930 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931 gui_exit(r);
2932#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00002933
Bram Moolenaar56718732006-03-15 22:53:57 +00002934#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00002935 mac_conv_cleanup();
2936#endif
2937
Bram Moolenaar071d4272004-06-13 20:20:40 +00002938#ifdef __QNX__
2939 /* A core dump won't be created if the signal handler
2940 * doesn't return, so we can't call exit() */
2941 if (deadly_signal != 0)
2942 return;
2943#endif
2944
Bram Moolenaar009b2592004-10-24 19:18:58 +00002945#ifdef FEAT_NETBEANS_INTG
2946 if (usingNetbeans)
2947 netbeans_send_disconnect();
2948#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002949
2950#ifdef EXITFREE
2951 free_all_mem();
2952#endif
2953
Bram Moolenaar071d4272004-06-13 20:20:40 +00002954 exit(r);
2955}
2956
2957 static void
2958may_core_dump()
2959{
2960 if (deadly_signal != 0)
2961 {
2962 signal(deadly_signal, SIG_DFL);
2963 kill(getpid(), deadly_signal); /* Die using the signal we caught */
2964 }
2965}
2966
2967#ifndef VMS
2968
2969 void
2970mch_settmode(tmode)
2971 int tmode;
2972{
2973 static int first = TRUE;
2974
2975 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2976#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2977 /*
2978 * for "new" tty systems
2979 */
2980# ifdef HAVE_TERMIOS_H
2981 static struct termios told;
2982 struct termios tnew;
2983# else
2984 static struct termio told;
2985 struct termio tnew;
2986# endif
2987
2988 if (first)
2989 {
2990 first = FALSE;
2991# if defined(HAVE_TERMIOS_H)
2992 tcgetattr(read_cmd_fd, &told);
2993# else
2994 ioctl(read_cmd_fd, TCGETA, &told);
2995# endif
2996 }
2997
2998 tnew = told;
2999 if (tmode == TMODE_RAW)
3000 {
3001 /*
3002 * ~ICRNL enables typing ^V^M
3003 */
3004 tnew.c_iflag &= ~ICRNL;
3005 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3006# if defined(IEXTEN) && !defined(__MINT__)
3007 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3008 /* but it breaks function keys on MINT */
3009# endif
3010 );
3011# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3012 tnew.c_oflag &= ~ONLCR;
3013# endif
3014 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3015 tnew.c_cc[VTIME] = 0; /* don't wait */
3016 }
3017 else if (tmode == TMODE_SLEEP)
3018 tnew.c_lflag &= ~(ECHO);
3019
3020# if defined(HAVE_TERMIOS_H)
3021 {
3022 int n = 10;
3023
3024 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3025 * few times. */
3026 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3027 && errno == EINTR && n > 0)
3028 --n;
3029 }
3030# else
3031 ioctl(read_cmd_fd, TCSETA, &tnew);
3032# endif
3033
3034#else
3035
3036 /*
3037 * for "old" tty systems
3038 */
3039# ifndef TIOCSETN
3040# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3041# endif
3042 static struct sgttyb ttybold;
3043 struct sgttyb ttybnew;
3044
3045 if (first)
3046 {
3047 first = FALSE;
3048 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3049 }
3050
3051 ttybnew = ttybold;
3052 if (tmode == TMODE_RAW)
3053 {
3054 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3055 ttybnew.sg_flags |= RAW;
3056 }
3057 else if (tmode == TMODE_SLEEP)
3058 ttybnew.sg_flags &= ~(ECHO);
3059 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3060#endif
3061 curr_tmode = tmode;
3062}
3063
3064/*
3065 * Try to get the code for "t_kb" from the stty setting
3066 *
3067 * Even if termcap claims a backspace key, the user's setting *should*
3068 * prevail. stty knows more about reality than termcap does, and if
3069 * somebody's usual erase key is DEL (which, for most BSD users, it will
3070 * be), they're going to get really annoyed if their erase key starts
3071 * doing forward deletes for no reason. (Eric Fischer)
3072 */
3073 void
3074get_stty()
3075{
3076 char_u buf[2];
3077 char_u *p;
3078
3079 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3080#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3081 /* for "new" tty systems */
3082# ifdef HAVE_TERMIOS_H
3083 struct termios keys;
3084# else
3085 struct termio keys;
3086# endif
3087
3088# if defined(HAVE_TERMIOS_H)
3089 if (tcgetattr(read_cmd_fd, &keys) != -1)
3090# else
3091 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3092# endif
3093 {
3094 buf[0] = keys.c_cc[VERASE];
3095 intr_char = keys.c_cc[VINTR];
3096#else
3097 /* for "old" tty systems */
3098 struct sgttyb keys;
3099
3100 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3101 {
3102 buf[0] = keys.sg_erase;
3103 intr_char = keys.sg_kill;
3104#endif
3105 buf[1] = NUL;
3106 add_termcode((char_u *)"kb", buf, FALSE);
3107
3108 /*
3109 * If <BS> and <DEL> are now the same, redefine <DEL>.
3110 */
3111 p = find_termcode((char_u *)"kD");
3112 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3113 do_fixdel(NULL);
3114 }
3115#if 0
3116 } /* to keep cindent happy */
3117#endif
3118}
3119
3120#endif /* VMS */
3121
3122#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3123/*
3124 * Set mouse clicks on or off.
3125 */
3126 void
3127mch_setmouse(on)
3128 int on;
3129{
3130 static int ison = FALSE;
3131 int xterm_mouse_vers;
3132
3133 if (on == ison) /* return quickly if nothing to do */
3134 return;
3135
3136 xterm_mouse_vers = use_xterm_mouse();
3137 if (xterm_mouse_vers > 0)
3138 {
3139 if (on) /* enable mouse events, use mouse tracking if available */
3140 out_str_nf((char_u *)
3141 (xterm_mouse_vers > 1
3142 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3143 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3144 else /* disable mouse events, could probably always send the same */
3145 out_str_nf((char_u *)
3146 (xterm_mouse_vers > 1
3147 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3148 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3149 ison = on;
3150 }
3151
3152# ifdef FEAT_MOUSE_DEC
3153 else if (ttym_flags == TTYM_DEC)
3154 {
3155 if (on) /* enable mouse events */
3156 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3157 else /* disable mouse events */
3158 out_str_nf((char_u *)"\033['z");
3159 ison = on;
3160 }
3161# endif
3162
3163# ifdef FEAT_MOUSE_GPM
3164 else
3165 {
3166 if (on)
3167 {
3168 if (gpm_open())
3169 ison = TRUE;
3170 }
3171 else
3172 {
3173 gpm_close();
3174 ison = FALSE;
3175 }
3176 }
3177# endif
3178
3179# ifdef FEAT_MOUSE_JSB
3180 else
3181 {
3182 if (on)
3183 {
3184 /* D - Enable Mouse up/down messages
3185 * L - Enable Left Button Reporting
3186 * M - Enable Middle Button Reporting
3187 * R - Enable Right Button Reporting
3188 * K - Enable SHIFT and CTRL key Reporting
3189 * + - Enable Advanced messaging of mouse moves and up/down messages
3190 * Q - Quiet No Ack
3191 * # - Numeric value of mouse pointer required
3192 * 0 = Multiview 2000 cursor, used as standard
3193 * 1 = Windows Arrow
3194 * 2 = Windows I Beam
3195 * 3 = Windows Hour Glass
3196 * 4 = Windows Cross Hair
3197 * 5 = Windows UP Arrow
3198 */
3199#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3200 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3201 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3202#else
3203 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3204 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3205#endif
3206 ison = TRUE;
3207 }
3208 else
3209 {
3210 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3211 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3212 ison = FALSE;
3213 }
3214 }
3215# endif
3216# ifdef FEAT_MOUSE_PTERM
3217 else
3218 {
3219 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3220 if (on)
3221 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3222 else
3223 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3224 ison = on;
3225 }
3226# endif
3227}
3228
3229/*
3230 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3231 */
3232 void
3233check_mouse_termcode()
3234{
3235# ifdef FEAT_MOUSE_XTERM
3236 if (use_xterm_mouse()
3237# ifdef FEAT_GUI
3238 && !gui.in_use
3239# endif
3240 )
3241 {
3242 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003243 ? IF_EB("\233M", CSI_STR "M")
3244 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003245 if (*p_mouse != NUL)
3246 {
3247 /* force mouse off and maybe on to send possibly new mouse
3248 * activation sequence to the xterm, with(out) drag tracing. */
3249 mch_setmouse(FALSE);
3250 setmouse();
3251 }
3252 }
3253 else
3254 del_mouse_termcode(KS_MOUSE);
3255# endif
3256
3257# ifdef FEAT_MOUSE_GPM
3258 if (!use_xterm_mouse()
3259# ifdef FEAT_GUI
3260 && !gui.in_use
3261# endif
3262 )
3263 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3264# endif
3265
3266# ifdef FEAT_MOUSE_JSB
3267 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3268 if (!use_xterm_mouse()
3269# ifdef FEAT_GUI
3270 && !gui.in_use
3271# endif
3272 )
3273 set_mouse_termcode(KS_JSBTERM_MOUSE,
3274 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3275 else
3276 del_mouse_termcode(KS_JSBTERM_MOUSE);
3277# endif
3278
3279# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003280 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003281 * define it in the GUI or when using an xterm. */
3282 if (!use_xterm_mouse()
3283# ifdef FEAT_GUI
3284 && !gui.in_use
3285# endif
3286 )
3287 set_mouse_termcode(KS_NETTERM_MOUSE,
3288 (char_u *)IF_EB("\033}", ESC_STR "}"));
3289 else
3290 del_mouse_termcode(KS_NETTERM_MOUSE);
3291# endif
3292
3293# ifdef FEAT_MOUSE_DEC
3294 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3295 if (!use_xterm_mouse()
3296# ifdef FEAT_GUI
3297 && !gui.in_use
3298# endif
3299 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003300 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3301 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003302 else
3303 del_mouse_termcode(KS_DEC_MOUSE);
3304# endif
3305# ifdef FEAT_MOUSE_PTERM
3306 /* same as the dec mouse */
3307 if (!use_xterm_mouse()
3308# ifdef FEAT_GUI
3309 && !gui.in_use
3310# endif
3311 )
3312 set_mouse_termcode(KS_PTERM_MOUSE,
3313 (char_u *) IF_EB("\033[", ESC_STR "["));
3314 else
3315 del_mouse_termcode(KS_PTERM_MOUSE);
3316# endif
3317}
3318#endif
3319
3320/*
3321 * set screen mode, always fails.
3322 */
3323/* ARGSUSED */
3324 int
3325mch_screenmode(arg)
3326 char_u *arg;
3327{
3328 EMSG(_(e_screenmode));
3329 return FAIL;
3330}
3331
3332#ifndef VMS
3333
3334/*
3335 * Try to get the current window size:
3336 * 1. with an ioctl(), most accurate method
3337 * 2. from the environment variables LINES and COLUMNS
3338 * 3. from the termcap
3339 * 4. keep using the old values
3340 * Return OK when size could be determined, FAIL otherwise.
3341 */
3342 int
3343mch_get_shellsize()
3344{
3345 long rows = 0;
3346 long columns = 0;
3347 char_u *p;
3348
3349 /*
3350 * For OS/2 use _scrsize().
3351 */
3352# ifdef __EMX__
3353 {
3354 int s[2];
3355
3356 _scrsize(s);
3357 columns = s[0];
3358 rows = s[1];
3359 }
3360# endif
3361
3362 /*
3363 * 1. try using an ioctl. It is the most accurate method.
3364 *
3365 * Try using TIOCGWINSZ first, some systems that have it also define
3366 * TIOCGSIZE but don't have a struct ttysize.
3367 */
3368# ifdef TIOCGWINSZ
3369 {
3370 struct winsize ws;
3371 int fd = 1;
3372
3373 /* When stdout is not a tty, use stdin for the ioctl(). */
3374 if (!isatty(fd) && isatty(read_cmd_fd))
3375 fd = read_cmd_fd;
3376 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3377 {
3378 columns = ws.ws_col;
3379 rows = ws.ws_row;
3380 }
3381 }
3382# else /* TIOCGWINSZ */
3383# ifdef TIOCGSIZE
3384 {
3385 struct ttysize ts;
3386 int fd = 1;
3387
3388 /* When stdout is not a tty, use stdin for the ioctl(). */
3389 if (!isatty(fd) && isatty(read_cmd_fd))
3390 fd = read_cmd_fd;
3391 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3392 {
3393 columns = ts.ts_cols;
3394 rows = ts.ts_lines;
3395 }
3396 }
3397# endif /* TIOCGSIZE */
3398# endif /* TIOCGWINSZ */
3399
3400 /*
3401 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003402 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3403 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003404 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003405 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003406 {
3407 if ((p = (char_u *)getenv("LINES")))
3408 rows = atoi((char *)p);
3409 if ((p = (char_u *)getenv("COLUMNS")))
3410 columns = atoi((char *)p);
3411 }
3412
3413#ifdef HAVE_TGETENT
3414 /*
3415 * 3. try reading "co" and "li" entries from termcap
3416 */
3417 if (columns == 0 || rows == 0)
3418 getlinecol(&columns, &rows);
3419#endif
3420
3421 /*
3422 * 4. If everything fails, use the old values
3423 */
3424 if (columns <= 0 || rows <= 0)
3425 return FAIL;
3426
3427 Rows = rows;
3428 Columns = columns;
3429 return OK;
3430}
3431
3432/*
3433 * Try to set the window size to Rows and Columns.
3434 */
3435 void
3436mch_set_shellsize()
3437{
3438 if (*T_CWS)
3439 {
3440 /*
3441 * NOTE: if you get an error here that term_set_winsize() is
3442 * undefined, check the output of configure. It could probably not
3443 * find a ncurses, termcap or termlib library.
3444 */
3445 term_set_winsize((int)Rows, (int)Columns);
3446 out_flush();
3447 screen_start(); /* don't know where cursor is now */
3448 }
3449}
3450
3451#endif /* VMS */
3452
3453/*
3454 * Rows and/or Columns has changed.
3455 */
3456 void
3457mch_new_shellsize()
3458{
3459 /* Nothing to do. */
3460}
3461
Bram Moolenaardf177f62005-02-22 08:39:57 +00003462#ifndef USE_SYSTEM
3463static void append_ga_line __ARGS((garray_T *gap));
3464
3465/*
3466 * Append the text in "gap" below the cursor line and clear "gap".
3467 */
3468 static void
3469append_ga_line(gap)
3470 garray_T *gap;
3471{
3472 /* Remove trailing CR. */
3473 if (gap->ga_len > 0
3474 && !curbuf->b_p_bin
3475 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3476 --gap->ga_len;
3477 ga_append(gap, NUL);
3478 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3479 gap->ga_len = 0;
3480}
3481#endif
3482
Bram Moolenaar071d4272004-06-13 20:20:40 +00003483 int
3484mch_call_shell(cmd, options)
3485 char_u *cmd;
3486 int options; /* SHELL_*, see vim.h */
3487{
3488#ifdef VMS
3489 char *ifn = NULL;
3490 char *ofn = NULL;
3491#endif
3492 int tmode = cur_tmode;
3493#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3494 int x;
3495# ifndef __EMX__
3496 char_u *newcmd; /* only needed for unix */
3497# else
3498 /*
3499 * Set the preferred shell in the EMXSHELL environment variable (but
3500 * only if it is different from what is already in the environment).
3501 * Emx then takes care of whether to use "/c" or "-c" in an
3502 * intelligent way. Simply pass the whole thing to emx's system() call.
3503 * Emx also starts an interactive shell if system() is passed an empty
3504 * string.
3505 */
3506 char_u *p, *old;
3507
3508 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3509 {
3510 /* should check HAVE_SETENV, but I know we don't have it. */
3511 p = alloc(10 + strlen(p_sh));
3512 if (p)
3513 {
3514 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3515 putenv((char *)p); /* don't free the pointer! */
3516 }
3517 }
3518# endif
3519
3520 out_flush();
3521
3522 if (options & SHELL_COOKED)
3523 settmode(TMODE_COOK); /* set to normal mode */
3524
3525# ifdef __EMX__
3526 if (cmd == NULL)
3527 x = system(""); /* this starts an interactive shell in emx */
3528 else
3529 x = system((char *)cmd);
3530 /* system() returns -1 when error occurs in starting shell */
3531 if (x == -1 && !emsg_silent)
3532 {
3533 MSG_PUTS(_("\nCannot execute shell "));
3534 msg_outtrans(p_sh);
3535 msg_putchar('\n');
3536 }
3537# else /* not __EMX__ */
3538 if (cmd == NULL)
3539 x = system((char *)p_sh);
3540 else
3541 {
3542# ifdef VMS
3543 if (ofn = strchr((char *)cmd, '>'))
3544 *ofn++ = '\0';
3545 if (ifn = strchr((char *)cmd, '<'))
3546 {
3547 char *p;
3548
3549 *ifn++ = '\0';
3550 p = strchr(ifn,' '); /* chop off any trailing spaces */
3551 if (p)
3552 *p = '\0';
3553 }
3554 if (ofn)
3555 x = vms_sys((char *)cmd, ofn, ifn);
3556 else
3557 x = system((char *)cmd);
3558# else
3559 newcmd = lalloc(STRLEN(p_sh)
3560 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3561 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3562 if (newcmd == NULL)
3563 x = 0;
3564 else
3565 {
3566 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3567 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3568 (char *)p_shcf,
3569 (char *)cmd);
3570 x = system((char *)newcmd);
3571 vim_free(newcmd);
3572 }
3573# endif
3574 }
3575# ifdef VMS
3576 x = vms_sys_status(x);
3577# endif
3578 if (emsg_silent)
3579 ;
3580 else if (x == 127)
3581 MSG_PUTS(_("\nCannot execute shell sh\n"));
3582# endif /* __EMX__ */
3583 else if (x && !(options & SHELL_SILENT))
3584 {
3585 MSG_PUTS(_("\nshell returned "));
3586 msg_outnum((long)x);
3587 msg_putchar('\n');
3588 }
3589
3590 if (tmode == TMODE_RAW)
3591 settmode(TMODE_RAW); /* set to raw mode */
3592# ifdef FEAT_TITLE
3593 resettitle();
3594# endif
3595 return x;
3596
3597#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3598
Bram Moolenaardf177f62005-02-22 08:39:57 +00003599# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3600 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003601
3602 char_u *newcmd = NULL;
3603 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003604 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003605 pid_t wait_pid = 0;
3606# ifdef HAVE_UNION_WAIT
3607 union wait status;
3608# else
3609 int status = -1;
3610# endif
3611 int retval = -1;
3612 char **argv = NULL;
3613 int argc;
3614 int i;
3615 char_u *p;
3616 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003618# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003619 int pty_slave_fd = -1;
3620 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003621# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003622 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003623 int fd_fromshell[2];
3624 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003625# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003626 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003627# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003628 static char envbuf_Rows[20];
3629 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003630# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003631 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003632
3633 out_flush();
3634 if (options & SHELL_COOKED)
3635 settmode(TMODE_COOK); /* set to normal mode */
3636
Bram Moolenaar071d4272004-06-13 20:20:40 +00003637 newcmd = vim_strsave(p_sh);
3638 if (newcmd == NULL) /* out of memory */
3639 goto error;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003640
3641 /*
3642 * Do this loop twice:
3643 * 1: find number of arguments
3644 * 2: separate them and build argv[]
3645 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646 for (i = 0; i < 2; ++i)
3647 {
3648 p = newcmd;
3649 inquote = FALSE;
3650 argc = 0;
3651 for (;;)
3652 {
3653 if (i == 1)
3654 argv[argc] = (char *)p;
3655 ++argc;
3656 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3657 {
3658 if (*p == '"')
3659 inquote = !inquote;
3660 ++p;
3661 }
3662 if (*p == NUL)
3663 break;
3664 if (i == 1)
3665 *p++ = NUL;
3666 p = skipwhite(p);
3667 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003668 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003669 {
3670 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3671 if (argv == NULL) /* out of memory */
3672 goto error;
3673 }
3674 }
3675 if (cmd != NULL)
3676 {
3677 if (extra_shell_arg != NULL)
3678 argv[argc++] = (char *)extra_shell_arg;
3679 argv[argc++] = (char *)p_shcf;
3680 argv[argc++] = (char *)cmd;
3681 }
3682 argv[argc] = NULL;
3683
Bram Moolenaar071d4272004-06-13 20:20:40 +00003684 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003685 * For the GUI, when writing the output into the buffer and when reading
3686 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3687 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003688 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003689 if ((options & (SHELL_READ|SHELL_WRITE))
3690# ifdef FEAT_GUI
3691 || (gui.in_use && show_shell_mess)
3692# endif
3693 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003694 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003695# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003696 /*
3697 * Try to open a master pty.
3698 * If this works, open the slave pty.
3699 * If the slave can't be opened, close the master pty.
3700 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003701 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003702 {
3703 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3704 if (pty_master_fd >= 0 && ((pty_slave_fd =
3705 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3706 {
3707 close(pty_master_fd);
3708 pty_master_fd = -1;
3709 }
3710 }
3711 /*
3712 * If not opening a pty or it didn't work, try using pipes.
3713 */
3714 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003715# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716 {
3717 pipe_error = (pipe(fd_toshell) < 0);
3718 if (!pipe_error) /* pipe create OK */
3719 {
3720 pipe_error = (pipe(fd_fromshell) < 0);
3721 if (pipe_error) /* pipe create failed */
3722 {
3723 close(fd_toshell[0]);
3724 close(fd_toshell[1]);
3725 }
3726 }
3727 if (pipe_error)
3728 {
3729 MSG_PUTS(_("\nCannot create pipes\n"));
3730 out_flush();
3731 }
3732 }
3733 }
3734
3735 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003736 {
3737# ifdef __BEOS__
3738 beos_cleanup_read_thread();
3739# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003740
Bram Moolenaar071d4272004-06-13 20:20:40 +00003741 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3742 {
3743 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003744 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003746 || (gui.in_use && show_shell_mess)
3747# endif
3748 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003749 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003750# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751 if (pty_master_fd >= 0) /* close the pseudo tty */
3752 {
3753 close(pty_master_fd);
3754 close(pty_slave_fd);
3755 }
3756 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003757# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003758 {
3759 close(fd_toshell[0]);
3760 close(fd_toshell[1]);
3761 close(fd_fromshell[0]);
3762 close(fd_fromshell[1]);
3763 }
3764 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765 }
3766 else if (pid == 0) /* child */
3767 {
3768 reset_signals(); /* handle signals normally */
3769
3770 if (!show_shell_mess || (options & SHELL_EXPAND))
3771 {
3772 int fd;
3773
3774 /*
3775 * Don't want to show any message from the shell. Can't just
3776 * close stdout and stderr though, because some systems will
3777 * break if you try to write to them after that, so we must
3778 * use dup() to replace them with something else -- webb
3779 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3780 * waiting for input.
3781 */
3782 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3783 fclose(stdin);
3784 fclose(stdout);
3785 fclose(stderr);
3786
3787 /*
3788 * If any of these open()'s and dup()'s fail, we just continue
3789 * anyway. It's not fatal, and on most systems it will make
3790 * no difference at all. On a few it will cause the execvp()
3791 * to exit with a non-zero status even when the completion
3792 * could be done, which is nothing too serious. If the open()
3793 * or dup() failed we'd just do the same thing ourselves
3794 * anyway -- webb
3795 */
3796 if (fd >= 0)
3797 {
3798 dup(fd); /* To replace stdin (file descriptor 0) */
3799 dup(fd); /* To replace stdout (file descriptor 1) */
3800 dup(fd); /* To replace stderr (file descriptor 2) */
3801
3802 /* Don't need this now that we've duplicated it */
3803 close(fd);
3804 }
3805 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003806 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003807# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003808 || gui.in_use
3809# endif
3810 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003811 {
3812
Bram Moolenaardf177f62005-02-22 08:39:57 +00003813# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003814 /* Create our own process group, so that the child and all its
3815 * children can be kill()ed. Don't do this when using pipes,
3816 * because stdin is not a tty, we would loose /dev/tty. */
3817 if (p_stmp)
3818 (void)setsid();
Bram Moolenaardf177f62005-02-22 08:39:57 +00003819# endif
3820# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003821 if (pty_slave_fd >= 0)
3822 {
3823 /* push stream discipline modules */
3824 if (options & SHELL_COOKED)
3825 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003826# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003827 /* Try to become controlling tty (probably doesn't work,
3828 * unless run by root) */
3829 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003830# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003831 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003832# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003833 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003834# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003835 setenv("TERM", "dumb", 1);
3836 sprintf((char *)envbuf, "%ld", Rows);
3837 setenv("ROWS", (char *)envbuf, 1);
3838 sprintf((char *)envbuf, "%ld", Rows);
3839 setenv("LINES", (char *)envbuf, 1);
3840 sprintf((char *)envbuf, "%ld", Columns);
3841 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003842# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003843 /*
3844 * Putenv does not copy the string, it has to remain valid.
3845 * Use a static array to avoid loosing allocated memory.
3846 */
3847 putenv("TERM=dumb");
3848 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
3849 putenv(envbuf_Rows);
3850 sprintf(envbuf_Rows, "LINES=%ld", Rows);
3851 putenv(envbuf_Rows);
3852 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
3853 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003854# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003855
Bram Moolenaara5792f52005-11-23 21:25:05 +00003856 /*
3857 * stderr is only redirected when using the GUI, so that a
3858 * program like gpg can still access the terminal to get a
3859 * passphrase using stderr.
3860 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003861# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003862 if (pty_master_fd >= 0)
3863 {
3864 close(pty_master_fd); /* close master side of pty */
3865
3866 /* set up stdin/stdout/stderr for the child */
3867 close(0);
3868 dup(pty_slave_fd);
3869 close(1);
3870 dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003871 if (gui.in_use)
3872 {
3873 close(2);
3874 dup(pty_slave_fd);
3875 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003876
3877 close(pty_slave_fd); /* has been dupped, close it now */
3878 }
3879 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003880# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003881 {
3882 /* set up stdin for the child */
3883 close(fd_toshell[1]);
3884 close(0);
3885 dup(fd_toshell[0]);
3886 close(fd_toshell[0]);
3887
3888 /* set up stdout for the child */
3889 close(fd_fromshell[0]);
3890 close(1);
3891 dup(fd_fromshell[1]);
3892 close(fd_fromshell[1]);
3893
Bram Moolenaara5792f52005-11-23 21:25:05 +00003894# ifdef FEAT_GUI
3895 if (gui.in_use)
3896 {
3897 /* set up stderr for the child */
3898 close(2);
3899 dup(1);
3900 }
3901# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003902 }
3903 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003904
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905 /*
3906 * There is no type cast for the argv, because the type may be
3907 * different on different machines. This may cause a warning
3908 * message with strict compilers, don't worry about it.
3909 * Call _exit() instead of exit() to avoid closing the connection
3910 * to the X server (esp. with GTK, which uses atexit()).
3911 */
3912 execvp(argv[0], argv);
3913 _exit(EXEC_FAILED); /* exec failed, return failure code */
3914 }
3915 else /* parent */
3916 {
3917 /*
3918 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003919 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003920 */
3921 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003922 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003923
3924 /*
3925 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003926 * This is also used to pipe stdin/stdout to/from the external
3927 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003928 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003929 if ((options & (SHELL_READ|SHELL_WRITE))
3930# ifdef FEAT_GUI
3931 || (gui.in_use && show_shell_mess)
3932# endif
3933 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003934 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003935# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003936 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003937# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003938 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003939# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003940 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
3941 int ta_len = 0; /* valid bytes in ta_buf[] */
3942 int len;
3943 int p_more_save;
3944 int old_State;
3945 int c;
3946 int toshell_fd;
3947 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003948 garray_T ga;
3949 int noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003950
Bram Moolenaardf177f62005-02-22 08:39:57 +00003951# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003952 if (pty_master_fd >= 0)
3953 {
3954 close(pty_slave_fd); /* close slave side of pty */
3955 fromshell_fd = pty_master_fd;
3956 toshell_fd = dup(pty_master_fd);
3957 }
3958 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003959# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003960 {
3961 close(fd_toshell[0]);
3962 close(fd_fromshell[1]);
3963 toshell_fd = fd_toshell[1];
3964 fromshell_fd = fd_fromshell[0];
3965 }
3966
3967 /*
3968 * Write to the child if there are typed characters.
3969 * Read from the child if there are characters available.
3970 * Repeat the reading a few times if more characters are
3971 * available. Need to check for typed keys now and then, but
3972 * not too often (delays when no chars are available).
3973 * This loop is quit if no characters can be read from the pty
3974 * (WaitForChar detected special condition), or there are no
3975 * characters available and the child has exited.
3976 * Only check if the child has exited when there is no more
3977 * output. The child may exit before all the output has
3978 * been printed.
3979 *
3980 * Currently this busy loops!
3981 * This can probably dead-lock when the write blocks!
3982 */
3983 p_more_save = p_more;
3984 p_more = FALSE;
3985 old_State = State;
3986 State = EXTERNCMD; /* don't redraw at window resize */
3987
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003988 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003989 {
3990 /* Fork a process that will write the lines to the
3991 * external program. */
3992 if ((wpid = fork()) == -1)
3993 {
3994 MSG_PUTS(_("\nCannot fork\n"));
3995 }
3996 else if (wpid == 0)
3997 {
3998 linenr_T lnum = curbuf->b_op_start.lnum;
3999 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004000 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004001 char_u *s;
4002 size_t l;
4003
4004 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004005 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004006 for (;;)
4007 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004008 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004009 if (l == 0)
4010 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004011 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004012 /* NL -> NUL translation */
4013 len = write(toshell_fd, "", (size_t)1);
4014 else
4015 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004016 s = vim_strchr(lp + written, NL);
4017 len = write(toshell_fd, (char *)lp + written,
4018 s == NULL ? l : s - (lp + written));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004019 }
4020 if (len == l)
4021 {
4022 /* Finished a line, add a NL, unless this line
4023 * should not have one. */
4024 if (lnum != curbuf->b_op_end.lnum
4025 || !curbuf->b_p_bin
4026 || (lnum != write_no_eol_lnum
4027 && (lnum !=
4028 curbuf->b_ml.ml_line_count
4029 || curbuf->b_p_eol)))
4030 write(toshell_fd, "\n", (size_t)1);
4031 ++lnum;
4032 if (lnum > curbuf->b_op_end.lnum)
4033 {
4034 /* finished all the lines, close pipe */
4035 close(toshell_fd);
4036 toshell_fd = -1;
4037 break;
4038 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004039 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004040 written = 0;
4041 }
4042 else if (len > 0)
4043 written += len;
4044 }
4045 _exit(0);
4046 }
4047 else
4048 {
4049 close(toshell_fd);
4050 toshell_fd = -1;
4051 }
4052 }
4053
4054 if (options & SHELL_READ)
4055 ga_init2(&ga, 1, BUFLEN);
4056
4057 noread_cnt = 0;
4058
Bram Moolenaar071d4272004-06-13 20:20:40 +00004059 for (;;)
4060 {
4061 /*
4062 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004063 * if there are any.
4064 * Don't do this if we are expanding wild cards (would eat
4065 * typeahead).
4066 * Don't do this when filtering and terminal is in cooked
4067 * mode, the shell command will handle the I/O. Avoids
4068 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004069 * Don't get characters when the child has already
4070 * finished (wait_pid == 0).
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004071 * Don't get extra characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004072 * Don't read characters unless we didn't get output for a
4073 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004074 */
4075 len = 0;
4076 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004077 && ((options &
4078 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4079 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
4080#ifdef FEAT_GUI
4081 || gui.in_use
4082#endif
4083 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004084 && wait_pid == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00004086 || (noread_cnt > 4
4087 && (len = ui_inchar(ta_buf,
4088 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004089 {
4090 /*
4091 * For pipes:
4092 * Check for CTRL-C: send interrupt signal to child.
4093 * Check for CTRL-D: EOF, close pipe to child.
4094 */
4095 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4096 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004097# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004098 /*
4099 * Send SIGINT to the child's group or all
4100 * processes in our group.
4101 */
4102 if (ta_buf[ta_len] == Ctrl_C
4103 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004104 {
4105# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004107# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004108 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004109# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004110 if (wpid > 0)
4111 kill(wpid, SIGINT);
4112 }
4113# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114 if (pty_master_fd < 0 && toshell_fd >= 0
4115 && ta_buf[ta_len] == Ctrl_D)
4116 {
4117 close(toshell_fd);
4118 toshell_fd = -1;
4119 }
4120 }
4121
4122 /* replace K_BS by <BS> and K_DEL by <DEL> */
4123 for (i = ta_len; i < ta_len + len; ++i)
4124 {
4125 if (ta_buf[i] == CSI && len - i > 2)
4126 {
4127 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4128 if (c == K_DEL || c == K_KDEL || c == K_BS)
4129 {
4130 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4131 (size_t)(len - i - 2));
4132 if (c == K_DEL || c == K_KDEL)
4133 ta_buf[i] = DEL;
4134 else
4135 ta_buf[i] = Ctrl_H;
4136 len -= 2;
4137 }
4138 }
4139 else if (ta_buf[i] == '\r')
4140 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004141# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004142 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004143 i += (*mb_ptr2len)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004144# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004145 }
4146
4147 /*
4148 * For pipes: echo the typed characters.
4149 * For a pty this does not seem to work.
4150 */
4151 if (pty_master_fd < 0)
4152 {
4153 for (i = ta_len; i < ta_len + len; ++i)
4154 {
4155 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4156 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004157# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004158 else if (has_mbyte)
4159 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004160 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161
4162 msg_outtrans_len(ta_buf + i, l);
4163 i += l - 1;
4164 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004165# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004166 else
4167 msg_outtrans_len(ta_buf + i, 1);
4168 }
4169 windgoto(msg_row, msg_col);
4170 out_flush();
4171 }
4172
4173 ta_len += len;
4174
4175 /*
4176 * Write the characters to the child, unless EOF has
4177 * been typed for pipes. Write one character at a
4178 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004179 * When writing buffer lines, drop the typed
4180 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004181 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004182 if (options & SHELL_WRITE)
4183 ta_len = 0;
4184 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004185 {
4186 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4187 if (len > 0)
4188 {
4189 ta_len -= len;
4190 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004191 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004192 }
4193 }
4194 }
4195
Bram Moolenaardf177f62005-02-22 08:39:57 +00004196 if (got_int)
4197 {
4198 /* CTRL-C sends a signal to the child, we ignore it
4199 * ourselves */
4200# ifdef HAVE_SETSID
4201 kill(-pid, SIGINT);
4202# else
4203 kill(0, SIGINT);
4204# endif
4205 if (wpid > 0)
4206 kill(wpid, SIGINT);
4207 got_int = FALSE;
4208 }
4209
Bram Moolenaar071d4272004-06-13 20:20:40 +00004210 /*
4211 * Check if the child has any characters to be printed.
4212 * Read them and write them to our window. Repeat this as
4213 * long as there is something to do, avoid the 10ms wait
4214 * for mch_inchar(), or sending typeahead characters to
4215 * the external process.
4216 * TODO: This should handle escape sequences, compatible
4217 * to some terminal (vt52?).
4218 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004219 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4221 {
4222 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004223# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004224 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004225# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004226 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004227# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228 );
4229 if (len <= 0) /* end of file or error */
4230 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004231
4232 noread_cnt = 0;
4233 if (options & SHELL_READ)
4234 {
4235 /* Do NUL -> NL translation, append NL separated
4236 * lines to the current buffer. */
4237 for (i = 0; i < len; ++i)
4238 {
4239 if (buffer[i] == NL)
4240 append_ga_line(&ga);
4241 else if (buffer[i] == NUL)
4242 ga_append(&ga, NL);
4243 else
4244 ga_append(&ga, buffer[i]);
4245 }
4246 }
4247# ifdef FEAT_MBYTE
4248 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004249 {
4250 int l;
4251
Bram Moolenaardf177f62005-02-22 08:39:57 +00004252 len += buffer_off;
4253 buffer[len] = NUL;
4254
Bram Moolenaar071d4272004-06-13 20:20:40 +00004255 /* Check if the last character in buffer[] is
4256 * incomplete, keep these bytes for the next
4257 * round. */
4258 for (p = buffer; p < buffer + len; p += l)
4259 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004260 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004261 if (l == 0)
4262 l = 1; /* NUL byte? */
4263 else if (MB_BYTE2LEN(*p) != l)
4264 break;
4265 }
4266 if (p == buffer) /* no complete character */
4267 {
4268 /* avoid getting stuck at an illegal byte */
4269 if (len >= 12)
4270 ++p;
4271 else
4272 {
4273 buffer_off = len;
4274 continue;
4275 }
4276 }
4277 c = *p;
4278 *p = NUL;
4279 msg_puts(buffer);
4280 if (p < buffer + len)
4281 {
4282 *p = c;
4283 buffer_off = (buffer + len) - p;
4284 mch_memmove(buffer, p, buffer_off);
4285 continue;
4286 }
4287 buffer_off = 0;
4288 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004289# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004290 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004291 {
4292 buffer[len] = NUL;
4293 msg_puts(buffer);
4294 }
4295
4296 windgoto(msg_row, msg_col);
4297 cursor_on();
4298 out_flush();
4299 if (got_int)
4300 break;
4301 }
4302
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004303 /* If we already detected the child has finished break the
4304 * loop now. */
4305 if (wait_pid == pid)
4306 break;
4307
Bram Moolenaar071d4272004-06-13 20:20:40 +00004308 /*
4309 * Check if the child still exists, before checking for
4310 * typed characters (otherwise we would loose typeahead).
4311 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004312# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004313 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004314# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004315 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004316# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004317 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4318 || (wait_pid == pid && WIFEXITED(status)))
4319 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004320 /* Don't break the loop yet, try reading more
4321 * characters from "fromshell_fd" first. When using
4322 * pipes there might still be something to read and
4323 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004324 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004325 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004326 else
4327 wait_pid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328 }
4329finished:
4330 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004331 if (options & SHELL_READ)
4332 {
4333 if (ga.ga_len > 0)
4334 {
4335 append_ga_line(&ga);
4336 /* remember that the NL was missing */
4337 write_no_eol_lnum = curwin->w_cursor.lnum;
4338 }
4339 else
4340 write_no_eol_lnum = 0;
4341 ga_clear(&ga);
4342 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004343
Bram Moolenaar071d4272004-06-13 20:20:40 +00004344 /*
4345 * Give all typeahead that wasn't used back to ui_inchar().
4346 */
4347 if (ta_len)
4348 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349 State = old_State;
4350 if (toshell_fd >= 0)
4351 close(toshell_fd);
4352 close(fromshell_fd);
4353 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004354
4355 /*
4356 * Wait until our child has exited.
4357 * Ignore wait() returning pids of other children and returning
4358 * because of some signal like SIGWINCH.
4359 * Don't wait if wait_pid was already set above, indicating the
4360 * child already exited.
4361 */
4362 while (wait_pid != pid)
4363 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004364# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004365 /* Ugly hack: when compiled with Python threads are probably
4366 * used, in which case wait() sometimes hangs for no obvious
4367 * reason. Use waitpid() instead and loop (like the GUI). */
4368# ifdef __NeXT__
4369 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4370# else
4371 wait_pid = waitpid(pid, &status, WNOHANG);
4372# endif
4373 if (wait_pid == 0)
4374 {
4375 /* Wait for 1/100 sec before trying again. */
4376 mch_delay(10L, TRUE);
4377 continue;
4378 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004379# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004380 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004381# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004382 if (wait_pid <= 0
4383# ifdef ECHILD
4384 && errno == ECHILD
4385# endif
4386 )
4387 break;
4388 }
4389
Bram Moolenaardf177f62005-02-22 08:39:57 +00004390 /* Make sure the child that writes to the external program is
4391 * dead. */
4392 if (wpid > 0)
4393 kill(wpid, SIGKILL);
4394
Bram Moolenaar071d4272004-06-13 20:20:40 +00004395 /*
4396 * Set to raw mode right now, otherwise a CTRL-C after
4397 * catch_signals() will kill Vim.
4398 */
4399 if (tmode == TMODE_RAW)
4400 settmode(TMODE_RAW);
4401 did_settmode = TRUE;
4402 set_signals();
4403
4404 if (WIFEXITED(status))
4405 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004406 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004407 retval = WEXITSTATUS(status);
4408 if (retval && !emsg_silent)
4409 {
4410 if (retval == EXEC_FAILED)
4411 {
4412 MSG_PUTS(_("\nCannot execute shell "));
4413 msg_outtrans(p_sh);
4414 msg_putchar('\n');
4415 }
4416 else if (!(options & SHELL_SILENT))
4417 {
4418 MSG_PUTS(_("\nshell returned "));
4419 msg_outnum((long)retval);
4420 msg_putchar('\n');
4421 }
4422 }
4423 }
4424 else
4425 MSG_PUTS(_("\nCommand terminated\n"));
4426 }
4427 }
4428 vim_free(argv);
4429
4430error:
4431 if (!did_settmode)
4432 if (tmode == TMODE_RAW)
4433 settmode(TMODE_RAW); /* set to raw mode */
4434# ifdef FEAT_TITLE
4435 resettitle();
4436# endif
4437 vim_free(newcmd);
4438
4439 return retval;
4440
4441#endif /* USE_SYSTEM */
4442}
4443
4444/*
4445 * Check for CTRL-C typed by reading all available characters.
4446 * In cooked mode we should get SIGINT, no need to check.
4447 */
4448 void
4449mch_breakcheck()
4450{
4451 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4452 fill_input_buf(FALSE);
4453}
4454
4455/*
4456 * Wait "msec" msec until a character is available from the keyboard or from
4457 * inbuf[]. msec == -1 will block forever.
4458 * When a GUI is being used, this will never get called -- webb
4459 */
4460 static int
4461WaitForChar(msec)
4462 long msec;
4463{
4464#ifdef FEAT_MOUSE_GPM
4465 int gpm_process_wanted;
4466#endif
4467#ifdef FEAT_XCLIPBOARD
4468 int rest;
4469#endif
4470 int avail;
4471
4472 if (input_available()) /* something in inbuf[] */
4473 return 1;
4474
4475#if defined(FEAT_MOUSE_DEC)
4476 /* May need to query the mouse position. */
4477 if (WantQueryMouse)
4478 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004479 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004480 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4481 }
4482#endif
4483
4484 /*
4485 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4486 * events. This is a bit complicated, because they might both be defined.
4487 */
4488#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4489# ifdef FEAT_XCLIPBOARD
4490 rest = 0;
4491 if (do_xterm_trace())
4492 rest = msec;
4493# endif
4494 do
4495 {
4496# ifdef FEAT_XCLIPBOARD
4497 if (rest != 0)
4498 {
4499 msec = XT_TRACE_DELAY;
4500 if (rest >= 0 && rest < XT_TRACE_DELAY)
4501 msec = rest;
4502 if (rest >= 0)
4503 rest -= msec;
4504 }
4505# endif
4506# ifdef FEAT_MOUSE_GPM
4507 gpm_process_wanted = 0;
4508 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4509# else
4510 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4511# endif
4512 if (!avail)
4513 {
4514 if (input_available())
4515 return 1;
4516# ifdef FEAT_XCLIPBOARD
4517 if (rest == 0 || !do_xterm_trace())
4518# endif
4519 break;
4520 }
4521 }
4522 while (FALSE
4523# ifdef FEAT_MOUSE_GPM
4524 || (gpm_process_wanted && mch_gpm_process() == 0)
4525# endif
4526# ifdef FEAT_XCLIPBOARD
4527 || (!avail && rest != 0)
4528# endif
4529 );
4530
4531#else
4532 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4533#endif
4534 return avail;
4535}
4536
4537/*
4538 * Wait "msec" msec until a character is available from file descriptor "fd".
4539 * Time == -1 will block forever.
4540 * When a GUI is being used, this will not be used for input -- webb
4541 * Returns also, when a request from Sniff is waiting -- toni.
4542 * Or when a Linux GPM mouse event is waiting.
4543 */
4544/* ARGSUSED */
4545#if defined(__BEOS__)
4546 int
4547#else
4548 static int
4549#endif
4550RealWaitForChar(fd, msec, check_for_gpm)
4551 int fd;
4552 long msec;
4553 int *check_for_gpm;
4554{
4555 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004556#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557 static int busy = FALSE;
4558
4559 /* May retry getting characters after an event was handled. */
4560# define MAY_LOOP
4561
4562# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4563 /* Remember at what time we started, so that we know how much longer we
4564 * should wait after being interrupted. */
4565# define USE_START_TV
4566 struct timeval start_tv;
4567
4568 if (msec > 0 && (
4569# ifdef FEAT_XCLIPBOARD
4570 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004571# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004572 ||
4573# endif
4574# endif
4575# ifdef USE_XSMP
4576 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004577# ifdef FEAT_MZSCHEME
4578 ||
4579# endif
4580# endif
4581# ifdef FEAT_MZSCHEME
4582 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004583# endif
4584 ))
4585 gettimeofday(&start_tv, NULL);
4586# endif
4587
4588 /* Handle being called recursively. This may happen for the session
4589 * manager stuff, it may save the file, which does a breakcheck. */
4590 if (busy)
4591 return 0;
4592#endif
4593
4594#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00004595 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004596#endif
4597 {
4598#ifdef MAY_LOOP
4599 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004600# ifdef FEAT_MZSCHEME
4601 int mzquantum_used = FALSE;
4602# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004603#endif
4604#ifndef HAVE_SELECT
4605 struct pollfd fds[5];
4606 int nfd;
4607# ifdef FEAT_XCLIPBOARD
4608 int xterm_idx = -1;
4609# endif
4610# ifdef FEAT_MOUSE_GPM
4611 int gpm_idx = -1;
4612# endif
4613# ifdef USE_XSMP
4614 int xsmp_idx = -1;
4615# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004616 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004618# ifdef FEAT_MZSCHEME
4619 mzvim_check_threads();
4620 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4621 {
4622 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4623 mzquantum_used = TRUE;
4624 }
4625# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004626 fds[0].fd = fd;
4627 fds[0].events = POLLIN;
4628 nfd = 1;
4629
4630# ifdef FEAT_SNIFF
4631# define SNIFF_IDX 1
4632 if (want_sniff_request)
4633 {
4634 fds[SNIFF_IDX].fd = fd_from_sniff;
4635 fds[SNIFF_IDX].events = POLLIN;
4636 nfd++;
4637 }
4638# endif
4639# ifdef FEAT_XCLIPBOARD
4640 if (xterm_Shell != (Widget)0)
4641 {
4642 xterm_idx = nfd;
4643 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4644 fds[nfd].events = POLLIN;
4645 nfd++;
4646 }
4647# endif
4648# ifdef FEAT_MOUSE_GPM
4649 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4650 {
4651 gpm_idx = nfd;
4652 fds[nfd].fd = gpm_fd;
4653 fds[nfd].events = POLLIN;
4654 nfd++;
4655 }
4656# endif
4657# ifdef USE_XSMP
4658 if (xsmp_icefd != -1)
4659 {
4660 xsmp_idx = nfd;
4661 fds[nfd].fd = xsmp_icefd;
4662 fds[nfd].events = POLLIN;
4663 nfd++;
4664 }
4665# endif
4666
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004667 ret = poll(fds, nfd, towait);
4668# ifdef FEAT_MZSCHEME
4669 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00004670 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004671 finished = FALSE;
4672# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004673
4674# ifdef FEAT_SNIFF
4675 if (ret < 0)
4676 sniff_disconnect(1);
4677 else if (want_sniff_request)
4678 {
4679 if (fds[SNIFF_IDX].revents & POLLHUP)
4680 sniff_disconnect(1);
4681 if (fds[SNIFF_IDX].revents & POLLIN)
4682 sniff_request_waiting = 1;
4683 }
4684# endif
4685# ifdef FEAT_XCLIPBOARD
4686 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4687 {
4688 xterm_update(); /* Maybe we should hand out clipboard */
4689 if (--ret == 0 && !input_available())
4690 /* Try again */
4691 finished = FALSE;
4692 }
4693# endif
4694# ifdef FEAT_MOUSE_GPM
4695 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4696 {
4697 *check_for_gpm = 1;
4698 }
4699# endif
4700# ifdef USE_XSMP
4701 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4702 {
4703 if (fds[xsmp_idx].revents & POLLIN)
4704 {
4705 busy = TRUE;
4706 xsmp_handle_requests();
4707 busy = FALSE;
4708 }
4709 else if (fds[xsmp_idx].revents & POLLHUP)
4710 {
4711 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004712 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004713 xsmp_close();
4714 }
4715 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004716 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004717 }
4718# endif
4719
4720
4721#else /* HAVE_SELECT */
4722
4723 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004724 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004725 fd_set rfds, efds;
4726 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004727 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004728
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004729# ifdef FEAT_MZSCHEME
4730 mzvim_check_threads();
4731 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4732 {
4733 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4734 mzquantum_used = TRUE;
4735 }
4736# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004737# ifdef __EMX__
4738 /* don't check for incoming chars if not in raw mode, because select()
4739 * always returns TRUE then (in some version of emx.dll) */
4740 if (curr_tmode != TMODE_RAW)
4741 return 0;
4742# endif
4743
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004744 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004745 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004746 tv.tv_sec = towait / 1000;
4747 tv.tv_usec = (towait % 1000) * (1000000/1000);
4748 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004749 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004750 else
4751 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004752
4753 /*
4754 * Select on ready for reading and exceptional condition (end of file).
4755 */
4756 FD_ZERO(&rfds); /* calls bzero() on a sun */
4757 FD_ZERO(&efds);
4758 FD_SET(fd, &rfds);
4759# if !defined(__QNX__) && !defined(__CYGWIN32__)
4760 /* For QNX select() always returns 1 if this is set. Why? */
4761 FD_SET(fd, &efds);
4762# endif
4763 maxfd = fd;
4764
4765# ifdef FEAT_SNIFF
4766 if (want_sniff_request)
4767 {
4768 FD_SET(fd_from_sniff, &rfds);
4769 FD_SET(fd_from_sniff, &efds);
4770 if (maxfd < fd_from_sniff)
4771 maxfd = fd_from_sniff;
4772 }
4773# endif
4774# ifdef FEAT_XCLIPBOARD
4775 if (xterm_Shell != (Widget)0)
4776 {
4777 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4778 if (maxfd < ConnectionNumber(xterm_dpy))
4779 maxfd = ConnectionNumber(xterm_dpy);
4780 }
4781# endif
4782# ifdef FEAT_MOUSE_GPM
4783 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4784 {
4785 FD_SET(gpm_fd, &rfds);
4786 FD_SET(gpm_fd, &efds);
4787 if (maxfd < gpm_fd)
4788 maxfd = gpm_fd;
4789 }
4790# endif
4791# ifdef USE_XSMP
4792 if (xsmp_icefd != -1)
4793 {
4794 FD_SET(xsmp_icefd, &rfds);
4795 FD_SET(xsmp_icefd, &efds);
4796 if (maxfd < xsmp_icefd)
4797 maxfd = xsmp_icefd;
4798 }
4799# endif
4800
4801# ifdef OLD_VMS
4802 /* Old VMS as v6.2 and older have broken select(). It waits more than
4803 * required. Should not be used */
4804 ret = 0;
4805# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004806 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4807# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00004808# ifdef __TANDEM
4809 if (ret == -1 && errno == ENOTSUP)
4810 {
4811 FD_ZERO(&rfds);
4812 FD_ZERO(&efds);
4813 ret = 0;
4814 }
4815#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004816# ifdef FEAT_MZSCHEME
4817 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00004818 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004819 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004820# endif
4821
4822# ifdef FEAT_SNIFF
4823 if (ret < 0 )
4824 sniff_disconnect(1);
4825 else if (ret > 0 && want_sniff_request)
4826 {
4827 if (FD_ISSET(fd_from_sniff, &efds))
4828 sniff_disconnect(1);
4829 if (FD_ISSET(fd_from_sniff, &rfds))
4830 sniff_request_waiting = 1;
4831 }
4832# endif
4833# ifdef FEAT_XCLIPBOARD
4834 if (ret > 0 && xterm_Shell != (Widget)0
4835 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4836 {
4837 xterm_update(); /* Maybe we should hand out clipboard */
4838 /* continue looping when we only got the X event and the input
4839 * buffer is empty */
4840 if (--ret == 0 && !input_available())
4841 {
4842 /* Try again */
4843 finished = FALSE;
4844 }
4845 }
4846# endif
4847# ifdef FEAT_MOUSE_GPM
4848 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4849 {
4850 if (FD_ISSET(gpm_fd, &efds))
4851 gpm_close();
4852 else if (FD_ISSET(gpm_fd, &rfds))
4853 *check_for_gpm = 1;
4854 }
4855# endif
4856# ifdef USE_XSMP
4857 if (ret > 0 && xsmp_icefd != -1)
4858 {
4859 if (FD_ISSET(xsmp_icefd, &efds))
4860 {
4861 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004862 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004863 xsmp_close();
4864 if (--ret == 0)
4865 finished = FALSE; /* keep going if event was only one */
4866 }
4867 else if (FD_ISSET(xsmp_icefd, &rfds))
4868 {
4869 busy = TRUE;
4870 xsmp_handle_requests();
4871 busy = FALSE;
4872 if (--ret == 0)
4873 finished = FALSE; /* keep going if event was only one */
4874 }
4875 }
4876# endif
4877
4878#endif /* HAVE_SELECT */
4879
4880#ifdef MAY_LOOP
4881 if (finished || msec == 0)
4882 break;
4883
4884 /* We're going to loop around again, find out for how long */
4885 if (msec > 0)
4886 {
4887# ifdef USE_START_TV
4888 struct timeval mtv;
4889
4890 /* Compute remaining wait time. */
4891 gettimeofday(&mtv, NULL);
4892 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
4893 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
4894# else
4895 /* Guess we got interrupted halfway. */
4896 msec = msec / 2;
4897# endif
4898 if (msec <= 0)
4899 break; /* waited long enough */
4900 }
4901#endif
4902 }
4903
4904 return (ret > 0);
4905}
4906
4907#ifndef VMS
4908
4909#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004910/*
Bram Moolenaar02743632005-07-25 20:42:36 +00004911 * Expand a path into all matching files and/or directories. Handles "*",
4912 * "?", "[a-z]", "**", etc.
4913 * "path" has backslashes before chars that are not to be expanded.
4914 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004915 */
4916 int
4917mch_expandpath(gap, path, flags)
4918 garray_T *gap;
4919 char_u *path;
4920 int flags; /* EW_* flags */
4921{
Bram Moolenaar02743632005-07-25 20:42:36 +00004922 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004923}
4924#endif
4925
4926/*
4927 * mch_expand_wildcards() - this code does wild-card pattern matching using
4928 * the shell
4929 *
4930 * return OK for success, FAIL for error (you may lose some memory) and put
4931 * an error message in *file.
4932 *
4933 * num_pat is number of input patterns
4934 * pat is array of pointers to input patterns
4935 * num_file is pointer to number of matched file names
4936 * file is pointer to array of pointers to matched file names
4937 */
4938
4939#ifndef SEEK_SET
4940# define SEEK_SET 0
4941#endif
4942#ifndef SEEK_END
4943# define SEEK_END 2
4944#endif
4945
Bram Moolenaar5555acc2006-04-07 21:33:12 +00004946#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00004947
Bram Moolenaar071d4272004-06-13 20:20:40 +00004948/* ARGSUSED */
4949 int
4950mch_expand_wildcards(num_pat, pat, num_file, file, flags)
4951 int num_pat;
4952 char_u **pat;
4953 int *num_file;
4954 char_u ***file;
4955 int flags; /* EW_* flags */
4956{
4957 int i;
4958 size_t len;
4959 char_u *p;
4960 int dir;
4961#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00004962 /*
4963 * This is the OS/2 implementation.
4964 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004965# define EXPL_ALLOC_INC 16
4966 char_u **expl_files;
4967 size_t files_alloced, files_free;
4968 char_u *buf;
4969 int has_wildcard;
4970
4971 *num_file = 0; /* default: no files found */
4972 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
4973 files_free = EXPL_ALLOC_INC; /* how much space is not used */
4974 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
4975 if (*file == NULL)
4976 return FAIL;
4977
4978 for (; num_pat > 0; num_pat--, pat++)
4979 {
4980 expl_files = NULL;
4981 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
4982 /* expand environment var or home dir */
4983 buf = expand_env_save(*pat);
4984 else
4985 buf = vim_strsave(*pat);
4986 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00004987 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004988 if (has_wildcard) /* yes, so expand them */
4989 expl_files = (char_u **)_fnexplode(buf);
4990
4991 /*
4992 * return value of buf if no wildcards left,
4993 * OR if no match AND EW_NOTFOUND is set.
4994 */
4995 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
4996 || (expl_files == NULL && (flags & EW_NOTFOUND)))
4997 { /* simply save the current contents of *buf */
4998 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
4999 if (expl_files != NULL)
5000 {
5001 expl_files[0] = vim_strsave(buf);
5002 expl_files[1] = NULL;
5003 }
5004 }
5005 vim_free(buf);
5006
5007 /*
5008 * Count number of names resulting from expansion,
5009 * At the same time add a backslash to the end of names that happen to
5010 * be directories, and replace slashes with backslashes.
5011 */
5012 if (expl_files)
5013 {
5014 for (i = 0; (p = expl_files[i]) != NULL; i++)
5015 {
5016 dir = mch_isdir(p);
5017 /* If we don't want dirs and this is one, skip it */
5018 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5019 continue;
5020
Bram Moolenaara2031822006-03-07 22:29:51 +00005021 /* Skip files that are not executable if we check for that. */
5022 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
5023 continue;
5024
Bram Moolenaar071d4272004-06-13 20:20:40 +00005025 if (--files_free == 0)
5026 {
5027 /* need more room in table of pointers */
5028 files_alloced += EXPL_ALLOC_INC;
5029 *file = (char_u **)vim_realloc(*file,
5030 sizeof(char_u **) * files_alloced);
5031 if (*file == NULL)
5032 {
5033 EMSG(_(e_outofmem));
5034 *num_file = 0;
5035 return FAIL;
5036 }
5037 files_free = EXPL_ALLOC_INC;
5038 }
5039 slash_adjust(p);
5040 if (dir)
5041 {
5042 /* For a directory we add a '/', unless it's already
5043 * there. */
5044 len = STRLEN(p);
5045 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5046 {
5047 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005048 if (!after_pathsep((*file)[*num_file],
5049 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005050 {
5051 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005052 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005053 }
5054 }
5055 }
5056 else
5057 {
5058 (*file)[*num_file] = vim_strsave(p);
5059 }
5060
5061 /*
5062 * Error message already given by either alloc or vim_strsave.
5063 * Should return FAIL, but returning OK works also.
5064 */
5065 if ((*file)[*num_file] == NULL)
5066 break;
5067 (*num_file)++;
5068 }
5069 _fnexplodefree((char **)expl_files);
5070 }
5071 }
5072 return OK;
5073
5074#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005075 /*
5076 * This is the non-OS/2 implementation (really Unix).
5077 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005078 int j;
5079 char_u *tempname;
5080 char_u *command;
5081 FILE *fd;
5082 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005083#define STYLE_ECHO 0 /* use "echo", the default */
5084#define STYLE_GLOB 1 /* use "glob", for csh */
5085#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5086#define STYLE_PRINT 3 /* use "print -N", for zsh */
5087#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5088 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005089 int shell_style = STYLE_ECHO;
5090 int check_spaces;
5091 static int did_find_nul = FALSE;
5092 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005093 /* vimglob() function to define for Posix shell */
5094 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo -n \"$1\"; echo; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005095
5096 *num_file = 0; /* default: no files found */
5097 *file = NULL;
5098
5099 /*
5100 * If there are no wildcards, just copy the names to allocated memory.
5101 * Saves a lot of time, because we don't have to start a new shell.
5102 */
5103 if (!have_wildcard(num_pat, pat))
5104 return save_patterns(num_pat, pat, num_file, file);
5105
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005106# ifdef HAVE_SANDBOX
5107 /* Don't allow any shell command in the sandbox. */
5108 if (sandbox != 0 && check_secure())
5109 return FAIL;
5110# endif
5111
Bram Moolenaar071d4272004-06-13 20:20:40 +00005112 /*
5113 * Don't allow the use of backticks in secure and restricted mode.
5114 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005115 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005116 for (i = 0; i < num_pat; ++i)
5117 if (vim_strchr(pat[i], '`') != NULL
5118 && (check_restricted() || check_secure()))
5119 return FAIL;
5120
5121 /*
5122 * get a name for the temp file
5123 */
5124 if ((tempname = vim_tempname('o')) == NULL)
5125 {
5126 EMSG(_(e_notmp));
5127 return FAIL;
5128 }
5129
5130 /*
5131 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005132 * file.
5133 * STYLE_BT: NL separated
5134 * If expanding `cmd` execute it directly.
5135 * STYLE_GLOB: NUL separated
5136 * If we use *csh, "glob" will work better than "echo".
5137 * STYLE_PRINT: NL or NUL separated
5138 * If we use *zsh, "print -N" will work better than "glob".
5139 * STYLE_VIMGLOB: NL separated
5140 * If we use *sh*, we define "vimglob()".
5141 * STYLE_ECHO: space separated.
5142 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143 */
5144 if (num_pat == 1 && *pat[0] == '`'
5145 && (len = STRLEN(pat[0])) > 2
5146 && *(pat[0] + len - 1) == '`')
5147 shell_style = STYLE_BT;
5148 else if ((len = STRLEN(p_sh)) >= 3)
5149 {
5150 if (STRCMP(p_sh + len - 3, "csh") == 0)
5151 shell_style = STYLE_GLOB;
5152 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5153 shell_style = STYLE_PRINT;
5154 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005155 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5156 "sh") != NULL)
5157 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005158
Bram Moolenaarc7247912008-01-13 12:54:11 +00005159 /* Compute the length of the command. We need 2 extra bytes: for the
5160 * optional '&' and for the NUL.
5161 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005162 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005163 if (shell_style == STYLE_VIMGLOB)
5164 len += STRLEN(sh_vimglob_func);
5165
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005166 for (i = 0; i < num_pat; ++i)
5167 {
5168 /* Count the length of the patterns in the same way as they are put in
5169 * "command" below. */
5170#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005171 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005172#else
5173 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005174 for (j = 0; pat[i][j] != NUL; ++j)
5175 {
5176 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5177 ++len; /* may add a backslash */
5178 ++len;
5179 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005180#endif
5181 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005182 command = alloc(len);
5183 if (command == NULL)
5184 {
5185 /* out of memory */
5186 vim_free(tempname);
5187 return FAIL;
5188 }
5189
5190 /*
5191 * Build the shell command:
5192 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5193 * recognizes this).
5194 * - Add the shell command to print the expanded names.
5195 * - Add the temp file name.
5196 * - Add the file name patterns.
5197 */
5198 if (shell_style == STYLE_BT)
5199 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005200 /* change `command; command& ` to (command; command ) */
5201 STRCPY(command, "(");
5202 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005203 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005204 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005205 while (p > command && vim_iswhite(*p))
5206 --p;
5207 if (*p == '&') /* remove trailing '&' */
5208 {
5209 ampersent = TRUE;
5210 *p = ' ';
5211 }
5212 STRCAT(command, ">");
5213 }
5214 else
5215 {
5216 if (flags & EW_NOTFOUND)
5217 STRCPY(command, "set nonomatch; ");
5218 else
5219 STRCPY(command, "unset nonomatch; ");
5220 if (shell_style == STYLE_GLOB)
5221 STRCAT(command, "glob >");
5222 else if (shell_style == STYLE_PRINT)
5223 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005224 else if (shell_style == STYLE_VIMGLOB)
5225 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005226 else
5227 STRCAT(command, "echo >");
5228 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005229
Bram Moolenaar071d4272004-06-13 20:20:40 +00005230 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005231
Bram Moolenaar071d4272004-06-13 20:20:40 +00005232 if (shell_style != STYLE_BT)
5233 for (i = 0; i < num_pat; ++i)
5234 {
5235 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005236 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005237 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005238#ifdef USE_SYSTEM
5239 STRCAT(command, " \"");
5240 STRCAT(command, pat[i]);
5241 STRCAT(command, "\"");
5242#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005243 int intick = FALSE;
5244
Bram Moolenaar071d4272004-06-13 20:20:40 +00005245 p = command + STRLEN(command);
5246 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005247 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005248 {
5249 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005250 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005251 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5252 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005253 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005254 * backslash inside backticks, before a special character
5255 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005256 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005257 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5258 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005259 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005260 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005261 }
5262 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005263 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005264 /* Put a backslash before a special character, but not
5265 * when inside ``. */
5266 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005267
5268 /* Copy one character. */
5269 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005270 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005271 *p = NUL;
5272#endif
5273 }
5274 if (flags & EW_SILENT)
5275 show_shell_mess = FALSE;
5276 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00005277 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005278
5279 /*
5280 * Using zsh -G: If a pattern has no matches, it is just deleted from
5281 * the argument list, otherwise zsh gives an error message and doesn't
5282 * expand any other pattern.
5283 */
5284 if (shell_style == STYLE_PRINT)
5285 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5286
5287 /*
5288 * If we use -f then shell variables set in .cshrc won't get expanded.
5289 * vi can do it, so we will too, but it is only necessary if there is a "$"
5290 * in one of the patterns, otherwise we can still use the fast option.
5291 */
5292 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5293 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5294
5295 /*
5296 * execute the shell command
5297 */
5298 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5299
5300 /* When running in the background, give it some time to create the temp
5301 * file, but don't wait for it to finish. */
5302 if (ampersent)
5303 mch_delay(10L, TRUE);
5304
5305 extra_shell_arg = NULL; /* cleanup */
5306 show_shell_mess = TRUE;
5307 vim_free(command);
5308
Bram Moolenaarc7247912008-01-13 12:54:11 +00005309 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005310 {
5311 mch_remove(tempname);
5312 vim_free(tempname);
5313 /*
5314 * With interactive completion, the error message is not printed.
5315 * However with USE_SYSTEM, I don't know how to turn off error messages
5316 * from the shell, so screen may still get messed up -- webb.
5317 */
5318#ifndef USE_SYSTEM
5319 if (!(flags & EW_SILENT))
5320#endif
5321 {
5322 redraw_later_clear(); /* probably messed up screen */
5323 msg_putchar('\n'); /* clear bottom line quickly */
5324 cmdline_row = Rows - 1; /* continue on last line */
5325#ifdef USE_SYSTEM
5326 if (!(flags & EW_SILENT))
5327#endif
5328 {
5329 MSG(_(e_wildexpand));
5330 msg_start(); /* don't overwrite this message */
5331 }
5332 }
5333 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5334 * EW_NOTFOUND is given */
5335 if (shell_style == STYLE_BT)
5336 return FAIL;
5337 goto notfound;
5338 }
5339
5340 /*
5341 * read the names from the file into memory
5342 */
5343 fd = fopen((char *)tempname, READBIN);
5344 if (fd == NULL)
5345 {
5346 /* Something went wrong, perhaps a file name with a special char. */
5347 if (!(flags & EW_SILENT))
5348 {
5349 MSG(_(e_wildexpand));
5350 msg_start(); /* don't overwrite this message */
5351 }
5352 vim_free(tempname);
5353 goto notfound;
5354 }
5355 fseek(fd, 0L, SEEK_END);
5356 len = ftell(fd); /* get size of temp file */
5357 fseek(fd, 0L, SEEK_SET);
5358 buffer = alloc(len + 1);
5359 if (buffer == NULL)
5360 {
5361 /* out of memory */
5362 mch_remove(tempname);
5363 vim_free(tempname);
5364 fclose(fd);
5365 return FAIL;
5366 }
5367 i = fread((char *)buffer, 1, len, fd);
5368 fclose(fd);
5369 mch_remove(tempname);
5370 if (i != len)
5371 {
5372 /* unexpected read error */
5373 EMSG2(_(e_notread), tempname);
5374 vim_free(tempname);
5375 vim_free(buffer);
5376 return FAIL;
5377 }
5378 vim_free(tempname);
5379
Bram Moolenaarc7247912008-01-13 12:54:11 +00005380# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005381 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5382 p = buffer;
5383 for (i = 0; i < len; ++i)
5384 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5385 *p++ = buffer[i];
5386 len = p - buffer;
5387# endif
5388
5389
5390 /* file names are separated with Space */
5391 if (shell_style == STYLE_ECHO)
5392 {
5393 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5394 p = buffer;
5395 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5396 {
5397 while (*p != ' ' && *p != '\n')
5398 ++p;
5399 p = skipwhite(p); /* skip to next entry */
5400 }
5401 }
5402 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005403 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005404 {
5405 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5406 p = buffer;
5407 for (i = 0; *p != NUL; ++i) /* count number of entries */
5408 {
5409 while (*p != '\n' && *p != NUL)
5410 ++p;
5411 if (*p != NUL)
5412 ++p;
5413 p = skipwhite(p); /* skip leading white space */
5414 }
5415 }
5416 /* file names are separated with NUL */
5417 else
5418 {
5419 /*
5420 * Some versions of zsh use spaces instead of NULs to separate
5421 * results. Only do this when there is no NUL before the end of the
5422 * buffer, otherwise we would never be able to use file names with
5423 * embedded spaces when zsh does use NULs.
5424 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5425 * don't check for spaces again.
5426 */
5427 check_spaces = FALSE;
5428 if (shell_style == STYLE_PRINT && !did_find_nul)
5429 {
5430 /* If there is a NUL, set did_find_nul, else set check_spaces */
5431 if (len && (int)STRLEN(buffer) < len - 1)
5432 did_find_nul = TRUE;
5433 else
5434 check_spaces = TRUE;
5435 }
5436
5437 /*
5438 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5439 * already is one, for STYLE_GLOB it needs to be added.
5440 */
5441 if (len && buffer[len - 1] == NUL)
5442 --len;
5443 else
5444 buffer[len] = NUL;
5445 i = 0;
5446 for (p = buffer; p < buffer + len; ++p)
5447 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5448 {
5449 ++i;
5450 *p = NUL;
5451 }
5452 if (len)
5453 ++i; /* count last entry */
5454 }
5455 if (i == 0)
5456 {
5457 /*
5458 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5459 * /bin/sh will happily expand it to nothing rather than returning an
5460 * error; and hey, it's good to check anyway -- webb.
5461 */
5462 vim_free(buffer);
5463 goto notfound;
5464 }
5465 *num_file = i;
5466 *file = (char_u **)alloc(sizeof(char_u *) * i);
5467 if (*file == NULL)
5468 {
5469 /* out of memory */
5470 vim_free(buffer);
5471 return FAIL;
5472 }
5473
5474 /*
5475 * Isolate the individual file names.
5476 */
5477 p = buffer;
5478 for (i = 0; i < *num_file; ++i)
5479 {
5480 (*file)[i] = p;
5481 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005482 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
5483 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005484 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00005485 while (!(shell_style == STYLE_ECHO && *p == ' ')
5486 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005487 ++p;
5488 if (p == buffer + len) /* last entry */
5489 *p = NUL;
5490 else
5491 {
5492 *p++ = NUL;
5493 p = skipwhite(p); /* skip to next entry */
5494 }
5495 }
5496 else /* NUL separates */
5497 {
5498 while (*p && p < buffer + len) /* skip entry */
5499 ++p;
5500 ++p; /* skip NUL */
5501 }
5502 }
5503
5504 /*
5505 * Move the file names to allocated memory.
5506 */
5507 for (j = 0, i = 0; i < *num_file; ++i)
5508 {
5509 /* Require the files to exist. Helps when using /bin/sh */
5510 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5511 continue;
5512
5513 /* check if this entry should be included */
5514 dir = (mch_isdir((*file)[i]));
5515 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5516 continue;
5517
Bram Moolenaara2031822006-03-07 22:29:51 +00005518 /* Skip files that are not executable if we check for that. */
5519 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
5520 continue;
5521
Bram Moolenaar071d4272004-06-13 20:20:40 +00005522 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5523 if (p)
5524 {
5525 STRCPY(p, (*file)[i]);
5526 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00005527 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005528 (*file)[j++] = p;
5529 }
5530 }
5531 vim_free(buffer);
5532 *num_file = j;
5533
5534 if (*num_file == 0) /* rejected all entries */
5535 {
5536 vim_free(*file);
5537 *file = NULL;
5538 goto notfound;
5539 }
5540
5541 return OK;
5542
5543notfound:
5544 if (flags & EW_NOTFOUND)
5545 return save_patterns(num_pat, pat, num_file, file);
5546 return FAIL;
5547
5548#endif /* __EMX__ */
5549}
5550
5551#endif /* VMS */
5552
5553#ifndef __EMX__
5554 static int
5555save_patterns(num_pat, pat, num_file, file)
5556 int num_pat;
5557 char_u **pat;
5558 int *num_file;
5559 char_u ***file;
5560{
5561 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005562 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005563
5564 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5565 if (*file == NULL)
5566 return FAIL;
5567 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005568 {
5569 s = vim_strsave(pat[i]);
5570 if (s != NULL)
5571 /* Be compatible with expand_filename(): halve the number of
5572 * backslashes. */
5573 backslash_halve(s);
5574 (*file)[i] = s;
5575 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005576 *num_file = num_pat;
5577 return OK;
5578}
5579#endif
5580
5581
5582/*
5583 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5584 * expand.
5585 */
5586 int
5587mch_has_exp_wildcard(p)
5588 char_u *p;
5589{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005590 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005591 {
5592#ifndef OS2
5593 if (*p == '\\' && p[1] != NUL)
5594 ++p;
5595 else
5596#endif
5597 if (vim_strchr((char_u *)
5598#ifdef VMS
5599 "*?%"
5600#else
5601# ifdef OS2
5602 "*?"
5603# else
5604 "*?[{'"
5605# endif
5606#endif
5607 , *p) != NULL)
5608 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005609 }
5610 return FALSE;
5611}
5612
5613/*
5614 * Return TRUE if the string "p" contains a wildcard.
5615 * Don't recognize '~' at the end as a wildcard.
5616 */
5617 int
5618mch_has_wildcard(p)
5619 char_u *p;
5620{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005621 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005622 {
5623#ifndef OS2
5624 if (*p == '\\' && p[1] != NUL)
5625 ++p;
5626 else
5627#endif
5628 if (vim_strchr((char_u *)
5629#ifdef VMS
5630 "*?%$"
5631#else
5632# ifdef OS2
5633# ifdef VIM_BACKTICK
5634 "*?$`"
5635# else
5636 "*?$"
5637# endif
5638# else
5639 "*?[{`'$"
5640# endif
5641#endif
5642 , *p) != NULL
5643 || (*p == '~' && p[1] != NUL))
5644 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005645 }
5646 return FALSE;
5647}
5648
5649#ifndef __EMX__
5650 static int
5651have_wildcard(num, file)
5652 int num;
5653 char_u **file;
5654{
5655 int i;
5656
5657 for (i = 0; i < num; i++)
5658 if (mch_has_wildcard(file[i]))
5659 return 1;
5660 return 0;
5661}
5662
5663 static int
5664have_dollars(num, file)
5665 int num;
5666 char_u **file;
5667{
5668 int i;
5669
5670 for (i = 0; i < num; i++)
5671 if (vim_strchr(file[i], '$') != NULL)
5672 return TRUE;
5673 return FALSE;
5674}
5675#endif /* ifndef __EMX__ */
5676
5677#ifndef HAVE_RENAME
5678/*
5679 * Scaled-down version of rename(), which is missing in Xenix.
5680 * This version can only move regular files and will fail if the
5681 * destination exists.
5682 */
5683 int
5684mch_rename(src, dest)
5685 const char *src, *dest;
5686{
5687 struct stat st;
5688
5689 if (stat(dest, &st) >= 0) /* fail if destination exists */
5690 return -1;
5691 if (link(src, dest) != 0) /* link file to new name */
5692 return -1;
5693 if (mch_remove(src) == 0) /* delete link to old name */
5694 return 0;
5695 return -1;
5696}
5697#endif /* !HAVE_RENAME */
5698
5699#ifdef FEAT_MOUSE_GPM
5700/*
5701 * Initializes connection with gpm (if it isn't already opened)
5702 * Return 1 if succeeded (or connection already opened), 0 if failed
5703 */
5704 static int
5705gpm_open()
5706{
5707 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5708
5709 if (!gpm_flag)
5710 {
5711 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5712 gpm_connect.defaultMask = ~GPM_HARD;
5713 /* Default handling for mouse move*/
5714 gpm_connect.minMod = 0; /* Handle any modifier keys */
5715 gpm_connect.maxMod = 0xffff;
5716 if (Gpm_Open(&gpm_connect, 0) > 0)
5717 {
5718 /* gpm library tries to handling TSTP causes
5719 * problems. Anyways, we close connection to Gpm whenever
5720 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005721 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00005722 */
5723 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5724 return 1; /* succeed */
5725 }
5726 if (gpm_fd == -2)
5727 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5728 return 0;
5729 }
5730 return 1; /* already open */
5731}
5732
5733/*
5734 * Closes connection to gpm
Bram Moolenaar1a3d0862007-08-30 09:47:38 +00005735 * returns non-zero if connection successfully closed
Bram Moolenaar071d4272004-06-13 20:20:40 +00005736 */
5737 static void
5738gpm_close()
5739{
5740 if (gpm_flag && gpm_fd >= 0) /* if Open */
5741 Gpm_Close();
5742}
5743
5744/* Reads gpm event and adds special keys to input buf. Returns length of
5745 * generated key sequence.
5746 * This function is made after gui_send_mouse_event
5747 */
5748 static int
5749mch_gpm_process()
5750{
5751 int button;
5752 static Gpm_Event gpm_event;
5753 char_u string[6];
5754 int_u vim_modifiers;
5755 int row,col;
5756 unsigned char buttons_mask;
5757 unsigned char gpm_modifiers;
5758 static unsigned char old_buttons = 0;
5759
5760 Gpm_GetEvent(&gpm_event);
5761
5762#ifdef FEAT_GUI
5763 /* Don't put events in the input queue now. */
5764 if (hold_gui_events)
5765 return 0;
5766#endif
5767
5768 row = gpm_event.y - 1;
5769 col = gpm_event.x - 1;
5770
5771 string[0] = ESC; /* Our termcode */
5772 string[1] = 'M';
5773 string[2] = 'G';
5774 switch (GPM_BARE_EVENTS(gpm_event.type))
5775 {
5776 case GPM_DRAG:
5777 string[3] = MOUSE_DRAG;
5778 break;
5779 case GPM_DOWN:
5780 buttons_mask = gpm_event.buttons & ~old_buttons;
5781 old_buttons = gpm_event.buttons;
5782 switch (buttons_mask)
5783 {
5784 case GPM_B_LEFT:
5785 button = MOUSE_LEFT;
5786 break;
5787 case GPM_B_MIDDLE:
5788 button = MOUSE_MIDDLE;
5789 break;
5790 case GPM_B_RIGHT:
5791 button = MOUSE_RIGHT;
5792 break;
5793 default:
5794 return 0;
5795 /*Don't know what to do. Can more than one button be
5796 * reported in one event? */
5797 }
5798 string[3] = (char_u)(button | 0x20);
5799 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5800 break;
5801 case GPM_UP:
5802 string[3] = MOUSE_RELEASE;
5803 old_buttons &= ~gpm_event.buttons;
5804 break;
5805 default:
5806 return 0;
5807 }
5808 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5809 gpm_modifiers = gpm_event.modifiers;
5810 vim_modifiers = 0x0;
5811 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5812 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5813 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5814 */
5815 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5816 vim_modifiers |= MOUSE_SHIFT;
5817
5818 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5819 vim_modifiers |= MOUSE_CTRL;
5820 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5821 vim_modifiers |= MOUSE_ALT;
5822 string[3] |= vim_modifiers;
5823 string[4] = (char_u)(col + ' ' + 1);
5824 string[5] = (char_u)(row + ' ' + 1);
5825 add_to_input_buf(string, 6);
5826 return 6;
5827}
5828#endif /* FEAT_MOUSE_GPM */
5829
5830#if defined(FEAT_LIBCALL) || defined(PROTO)
5831typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
5832typedef char_u * (*INTPROCSTR)__ARGS((int));
5833typedef int (*STRPROCINT)__ARGS((char_u *));
5834typedef int (*INTPROCINT)__ARGS((int));
5835
5836/*
5837 * Call a DLL routine which takes either a string or int param
5838 * and returns an allocated string.
5839 */
5840 int
5841mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
5842 char_u *libname;
5843 char_u *funcname;
5844 char_u *argstring; /* NULL when using a argint */
5845 int argint;
5846 char_u **string_result;/* NULL when using number_result */
5847 int *number_result;
5848{
5849# if defined(USE_DLOPEN)
5850 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005851 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005852# else
5853 shl_t hinstLib;
5854# endif
5855 STRPROCSTR ProcAdd;
5856 INTPROCSTR ProcAddI;
5857 char_u *retval_str = NULL;
5858 int retval_int = 0;
5859 int success = FALSE;
5860
Bram Moolenaarb39ef122006-06-22 16:19:31 +00005861 /*
5862 * Get a handle to the DLL module.
5863 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005864# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00005865 /* First clear any error, it's not cleared by the dlopen() call. */
5866 (void)dlerror();
5867
Bram Moolenaar071d4272004-06-13 20:20:40 +00005868 hinstLib = dlopen((char *)libname, RTLD_LAZY
5869# ifdef RTLD_LOCAL
5870 | RTLD_LOCAL
5871# endif
5872 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005873 if (hinstLib == NULL)
5874 {
5875 /* "dlerr" must be used before dlclose() */
5876 dlerr = (char *)dlerror();
5877 if (dlerr != NULL)
5878 EMSG2(_("dlerror = \"%s\""), dlerr);
5879 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005880# else
5881 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
5882# endif
5883
5884 /* If the handle is valid, try to get the function address. */
5885 if (hinstLib != NULL)
5886 {
5887# ifdef HAVE_SETJMP_H
5888 /*
5889 * Catch a crash when calling the library function. For example when
5890 * using a number where a string pointer is expected.
5891 */
5892 mch_startjmp();
5893 if (SETJMP(lc_jump_env) != 0)
5894 {
5895 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00005896# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005897 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00005898# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005899 mch_didjmp();
5900 }
5901 else
5902# endif
5903 {
5904 retval_str = NULL;
5905 retval_int = 0;
5906
5907 if (argstring != NULL)
5908 {
5909# if defined(USE_DLOPEN)
5910 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005911 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005912# else
5913 if (shl_findsym(&hinstLib, (const char *)funcname,
5914 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
5915 ProcAdd = NULL;
5916# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005917 if ((success = (ProcAdd != NULL
5918# if defined(USE_DLOPEN)
5919 && dlerr == NULL
5920# endif
5921 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005922 {
5923 if (string_result == NULL)
5924 retval_int = ((STRPROCINT)ProcAdd)(argstring);
5925 else
5926 retval_str = (ProcAdd)(argstring);
5927 }
5928 }
5929 else
5930 {
5931# if defined(USE_DLOPEN)
5932 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005933 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005934# else
5935 if (shl_findsym(&hinstLib, (const char *)funcname,
5936 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
5937 ProcAddI = NULL;
5938# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005939 if ((success = (ProcAddI != NULL
5940# if defined(USE_DLOPEN)
5941 && dlerr == NULL
5942# endif
5943 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005944 {
5945 if (string_result == NULL)
5946 retval_int = ((INTPROCINT)ProcAddI)(argint);
5947 else
5948 retval_str = (ProcAddI)(argint);
5949 }
5950 }
5951
5952 /* Save the string before we free the library. */
5953 /* Assume that a "1" or "-1" result is an illegal pointer. */
5954 if (string_result == NULL)
5955 *number_result = retval_int;
5956 else if (retval_str != NULL
5957 && retval_str != (char_u *)1
5958 && retval_str != (char_u *)-1)
5959 *string_result = vim_strsave(retval_str);
5960 }
5961
5962# ifdef HAVE_SETJMP_H
5963 mch_endjmp();
5964# ifdef SIGHASARG
5965 if (lc_signal != 0)
5966 {
5967 int i;
5968
5969 /* try to find the name of this signal */
5970 for (i = 0; signal_info[i].sig != -1; i++)
5971 if (lc_signal == signal_info[i].sig)
5972 break;
5973 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
5974 }
5975# endif
5976# endif
5977
Bram Moolenaar071d4272004-06-13 20:20:40 +00005978# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005979 /* "dlerr" must be used before dlclose() */
5980 if (dlerr != NULL)
5981 EMSG2(_("dlerror = \"%s\""), dlerr);
5982
5983 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005984 (void)dlclose(hinstLib);
5985# else
5986 (void)shl_unload(hinstLib);
5987# endif
5988 }
5989
5990 if (!success)
5991 {
5992 EMSG2(_(e_libcall), funcname);
5993 return FAIL;
5994 }
5995
5996 return OK;
5997}
5998#endif
5999
6000#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6001static int xterm_trace = -1; /* default: disabled */
6002static int xterm_button;
6003
6004/*
6005 * Setup a dummy window for X selections in a terminal.
6006 */
6007 void
6008setup_term_clip()
6009{
6010 int z = 0;
6011 char *strp = "";
6012 Widget AppShell;
6013
6014 if (!x_connect_to_server())
6015 return;
6016
6017 open_app_context();
6018 if (app_context != NULL && xterm_Shell == (Widget)0)
6019 {
6020 int (*oldhandler)();
6021#if defined(HAVE_SETJMP_H)
6022 int (*oldIOhandler)();
6023#endif
6024# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6025 struct timeval start_tv;
6026
6027 if (p_verbose > 0)
6028 gettimeofday(&start_tv, NULL);
6029# endif
6030
6031 /* Ignore X errors while opening the display */
6032 oldhandler = XSetErrorHandler(x_error_check);
6033
6034#if defined(HAVE_SETJMP_H)
6035 /* Ignore X IO errors while opening the display */
6036 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6037 mch_startjmp();
6038 if (SETJMP(lc_jump_env) != 0)
6039 {
6040 mch_didjmp();
6041 xterm_dpy = NULL;
6042 }
6043 else
6044#endif
6045 {
6046 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6047 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6048#if defined(HAVE_SETJMP_H)
6049 mch_endjmp();
6050#endif
6051 }
6052
6053#if defined(HAVE_SETJMP_H)
6054 /* Now handle X IO errors normally. */
6055 (void)XSetIOErrorHandler(oldIOhandler);
6056#endif
6057 /* Now handle X errors normally. */
6058 (void)XSetErrorHandler(oldhandler);
6059
6060 if (xterm_dpy == NULL)
6061 {
6062 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006063 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006064 return;
6065 }
6066
6067 /* Catch terminating error of the X server connection. */
6068 (void)XSetIOErrorHandler(x_IOerror_handler);
6069
6070# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6071 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006072 {
6073 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006074 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006075 verbose_leave();
6076 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006077# endif
6078
6079 /* Create a Shell to make converters work. */
6080 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6081 applicationShellWidgetClass, xterm_dpy,
6082 NULL);
6083 if (AppShell == (Widget)0)
6084 return;
6085 xterm_Shell = XtVaCreatePopupShell("VIM",
6086 topLevelShellWidgetClass, AppShell,
6087 XtNmappedWhenManaged, 0,
6088 XtNwidth, 1,
6089 XtNheight, 1,
6090 NULL);
6091 if (xterm_Shell == (Widget)0)
6092 return;
6093
6094 x11_setup_atoms(xterm_dpy);
6095 if (x11_display == NULL)
6096 x11_display = xterm_dpy;
6097
6098 XtRealizeWidget(xterm_Shell);
6099 XSync(xterm_dpy, False);
6100 xterm_update();
6101 }
6102 if (xterm_Shell != (Widget)0)
6103 {
6104 clip_init(TRUE);
6105 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6106 x11_window = (Window)atol(strp);
6107 /* Check if $WINDOWID is valid. */
6108 if (test_x11_window(xterm_dpy) == FAIL)
6109 x11_window = 0;
6110 if (x11_window != 0)
6111 xterm_trace = 0;
6112 }
6113}
6114
6115 void
6116start_xterm_trace(button)
6117 int button;
6118{
6119 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6120 return;
6121 xterm_trace = 1;
6122 xterm_button = button;
6123 do_xterm_trace();
6124}
6125
6126
6127 void
6128stop_xterm_trace()
6129{
6130 if (xterm_trace < 0)
6131 return;
6132 xterm_trace = 0;
6133}
6134
6135/*
6136 * Query the xterm pointer and generate mouse termcodes if necessary
6137 * return TRUE if dragging is active, else FALSE
6138 */
6139 static int
6140do_xterm_trace()
6141{
6142 Window root, child;
6143 int root_x, root_y;
6144 int win_x, win_y;
6145 int row, col;
6146 int_u mask_return;
6147 char_u buf[50];
6148 char_u *strp;
6149 long got_hints;
6150 static char_u *mouse_code;
6151 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6152 static int prev_row = 0, prev_col = 0;
6153 static XSizeHints xterm_hints;
6154
6155 if (xterm_trace <= 0)
6156 return FALSE;
6157
6158 if (xterm_trace == 1)
6159 {
6160 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006161 * have changed recently. */
6162 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6163 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006164 || xterm_hints.width_inc <= 1
6165 || xterm_hints.height_inc <= 1)
6166 {
6167 xterm_trace = -1; /* Not enough data -- disable tracing */
6168 return FALSE;
6169 }
6170
6171 /* Rely on the same mouse code for the duration of this */
6172 mouse_code = find_termcode(mouse_name);
6173 prev_row = mouse_row;
6174 prev_row = mouse_col;
6175 xterm_trace = 2;
6176
6177 /* Find the offset of the chars, there might be a scrollbar on the
6178 * left of the window and/or a menu on the top (eterm etc.) */
6179 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6180 &win_x, &win_y, &mask_return);
6181 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6182 - (xterm_hints.height_inc / 2);
6183 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6184 xterm_hints.y = 2;
6185 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6186 - (xterm_hints.width_inc / 2);
6187 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6188 xterm_hints.x = 2;
6189 return TRUE;
6190 }
6191 if (mouse_code == NULL)
6192 {
6193 xterm_trace = 0;
6194 return FALSE;
6195 }
6196
6197 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6198 &win_x, &win_y, &mask_return);
6199
6200 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6201 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6202 if (row == prev_row && col == prev_col)
6203 return TRUE;
6204
6205 STRCPY(buf, mouse_code);
6206 strp = buf + STRLEN(buf);
6207 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6208 *strp++ = (char_u)(col + ' ' + 1);
6209 *strp++ = (char_u)(row + ' ' + 1);
6210 *strp = 0;
6211 add_to_input_buf(buf, STRLEN(buf));
6212
6213 prev_row = row;
6214 prev_col = col;
6215 return TRUE;
6216}
6217
6218# if defined(FEAT_GUI) || defined(PROTO)
6219/*
6220 * Destroy the display, window and app_context. Required for GTK.
6221 */
6222 void
6223clear_xterm_clip()
6224{
6225 if (xterm_Shell != (Widget)0)
6226 {
6227 XtDestroyWidget(xterm_Shell);
6228 xterm_Shell = (Widget)0;
6229 }
6230 if (xterm_dpy != NULL)
6231 {
6232#if 0
6233 /* Lesstif and Solaris crash here, lose some memory */
6234 XtCloseDisplay(xterm_dpy);
6235#endif
6236 if (x11_display == xterm_dpy)
6237 x11_display = NULL;
6238 xterm_dpy = NULL;
6239 }
6240#if 0
6241 if (app_context != (XtAppContext)NULL)
6242 {
6243 /* Lesstif and Solaris crash here, lose some memory */
6244 XtDestroyApplicationContext(app_context);
6245 app_context = (XtAppContext)NULL;
6246 }
6247#endif
6248}
6249# endif
6250
6251/*
6252 * Catch up with any queued X events. This may put keyboard input into the
6253 * input buffer, call resize call-backs, trigger timers etc. If there is
6254 * nothing in the X event queue (& no timers pending), then we return
6255 * immediately.
6256 */
6257 static void
6258xterm_update()
6259{
6260 XEvent event;
6261
6262 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6263 {
6264 XtAppNextEvent(app_context, &event);
6265#ifdef FEAT_CLIENTSERVER
6266 {
6267 XPropertyEvent *e = (XPropertyEvent *)&event;
6268
6269 if (e->type == PropertyNotify && e->window == commWindow
6270 && e->atom == commProperty && e->state == PropertyNewValue)
6271 serverEventProc(xterm_dpy, &event);
6272 }
6273#endif
6274 XtDispatchEvent(&event);
6275 }
6276}
6277
6278 int
6279clip_xterm_own_selection(cbd)
6280 VimClipboard *cbd;
6281{
6282 if (xterm_Shell != (Widget)0)
6283 return clip_x11_own_selection(xterm_Shell, cbd);
6284 return FAIL;
6285}
6286
6287 void
6288clip_xterm_lose_selection(cbd)
6289 VimClipboard *cbd;
6290{
6291 if (xterm_Shell != (Widget)0)
6292 clip_x11_lose_selection(xterm_Shell, cbd);
6293}
6294
6295 void
6296clip_xterm_request_selection(cbd)
6297 VimClipboard *cbd;
6298{
6299 if (xterm_Shell != (Widget)0)
6300 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6301}
6302
6303 void
6304clip_xterm_set_selection(cbd)
6305 VimClipboard *cbd;
6306{
6307 clip_x11_set_selection(cbd);
6308}
6309#endif
6310
6311
6312#if defined(USE_XSMP) || defined(PROTO)
6313/*
6314 * Code for X Session Management Protocol.
6315 */
6316static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6317static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6318static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6319static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6320static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6321
6322
6323# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6324static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6325
6326/*
6327 * This is our chance to ask the user if they want to save,
6328 * or abort the logout
6329 */
6330/*ARGSUSED*/
6331 static void
6332xsmp_handle_interaction(smc_conn, client_data)
6333 SmcConn smc_conn;
6334 SmPointer client_data;
6335{
6336 cmdmod_T save_cmdmod;
6337 int cancel_shutdown = False;
6338
6339 save_cmdmod = cmdmod;
6340 cmdmod.confirm = TRUE;
6341 if (check_changed_any(FALSE))
6342 /* Mustn't logout */
6343 cancel_shutdown = True;
6344 cmdmod = save_cmdmod;
6345 setcursor(); /* position cursor */
6346 out_flush();
6347
6348 /* Done interaction */
6349 SmcInteractDone(smc_conn, cancel_shutdown);
6350
6351 /* Finish off
6352 * Only end save-yourself here if we're not cancelling shutdown;
6353 * we'll get a cancelled callback later in which we'll end it.
6354 * Hopefully get around glitchy SMs (like GNOME-1)
6355 */
6356 if (!cancel_shutdown)
6357 {
6358 xsmp.save_yourself = False;
6359 SmcSaveYourselfDone(smc_conn, True);
6360 }
6361}
6362# endif
6363
6364/*
6365 * Callback that starts save-yourself.
6366 */
6367/*ARGSUSED*/
6368 static void
6369xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6370 shutdown, interact_style, fast)
6371 SmcConn smc_conn;
6372 SmPointer client_data;
6373 int save_type;
6374 Bool shutdown;
6375 int interact_style;
6376 Bool fast;
6377{
6378 /* Handle already being in saveyourself */
6379 if (xsmp.save_yourself)
6380 SmcSaveYourselfDone(smc_conn, True);
6381 xsmp.save_yourself = True;
6382 xsmp.shutdown = shutdown;
6383
6384 /* First up, preserve all files */
6385 out_flush();
6386 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6387
6388 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006389 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006390
6391# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6392 /* Now see if we can ask about unsaved files */
6393 if (shutdown && !fast && gui.in_use)
6394 /* Need to interact with user, but need SM's permission */
6395 SmcInteractRequest(smc_conn, SmDialogError,
6396 xsmp_handle_interaction, client_data);
6397 else
6398# endif
6399 {
6400 /* Can stop the cycle here */
6401 SmcSaveYourselfDone(smc_conn, True);
6402 xsmp.save_yourself = False;
6403 }
6404}
6405
6406
6407/*
6408 * Callback to warn us of imminent death.
6409 */
6410/*ARGSUSED*/
6411 static void
6412xsmp_die(smc_conn, client_data)
6413 SmcConn smc_conn;
6414 SmPointer client_data;
6415{
6416 xsmp_close();
6417
6418 /* quit quickly leaving swapfiles for modified buffers behind */
6419 getout_preserve_modified(0);
6420}
6421
6422
6423/*
6424 * Callback to tell us that save-yourself has completed.
6425 */
6426/*ARGSUSED*/
6427 static void
6428xsmp_save_complete(smc_conn, client_data)
6429 SmcConn smc_conn;
6430 SmPointer client_data;
6431{
6432 xsmp.save_yourself = False;
6433}
6434
6435
6436/*
6437 * Callback to tell us that an instigated shutdown was cancelled
6438 * (maybe even by us)
6439 */
6440/*ARGSUSED*/
6441 static void
6442xsmp_shutdown_cancelled(smc_conn, client_data)
6443 SmcConn smc_conn;
6444 SmPointer client_data;
6445{
6446 if (xsmp.save_yourself)
6447 SmcSaveYourselfDone(smc_conn, True);
6448 xsmp.save_yourself = False;
6449 xsmp.shutdown = False;
6450}
6451
6452
6453/*
6454 * Callback to tell us that a new ICE connection has been established.
6455 */
6456/*ARGSUSED*/
6457 static void
6458xsmp_ice_connection(iceConn, clientData, opening, watchData)
6459 IceConn iceConn;
6460 IcePointer clientData;
6461 Bool opening;
6462 IcePointer *watchData;
6463{
6464 /* Intercept creation of ICE connection fd */
6465 if (opening)
6466 {
6467 xsmp_icefd = IceConnectionNumber(iceConn);
6468 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6469 }
6470}
6471
6472
6473/* Handle any ICE processing that's required; return FAIL if SM lost */
6474 int
6475xsmp_handle_requests()
6476{
6477 Bool rep;
6478
6479 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6480 == IceProcessMessagesIOError)
6481 {
6482 /* Lost ICE */
6483 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006484 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006485 xsmp_close();
6486 return FAIL;
6487 }
6488 else
6489 return OK;
6490}
6491
6492static int dummy;
6493
6494/* Set up X Session Management Protocol */
6495 void
6496xsmp_init(void)
6497{
6498 char errorstring[80];
6499 char *clientid;
6500 SmcCallbacks smcallbacks;
6501#if 0
6502 SmPropValue smname;
6503 SmProp smnameprop;
6504 SmProp *smprops[1];
6505#endif
6506
6507 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006508 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006509
6510 xsmp.save_yourself = xsmp.shutdown = False;
6511
6512 /* Set up SM callbacks - must have all, even if they're not used */
6513 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6514 smcallbacks.save_yourself.client_data = NULL;
6515 smcallbacks.die.callback = xsmp_die;
6516 smcallbacks.die.client_data = NULL;
6517 smcallbacks.save_complete.callback = xsmp_save_complete;
6518 smcallbacks.save_complete.client_data = NULL;
6519 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6520 smcallbacks.shutdown_cancelled.client_data = NULL;
6521
6522 /* Set up a watch on ICE connection creations. The "dummy" argument is
6523 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6524 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6525 {
6526 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006527 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006528 return;
6529 }
6530
6531 /* Create an SM connection */
6532 xsmp.smcconn = SmcOpenConnection(
6533 NULL,
6534 NULL,
6535 SmProtoMajor,
6536 SmProtoMinor,
6537 SmcSaveYourselfProcMask | SmcDieProcMask
6538 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6539 &smcallbacks,
6540 NULL,
6541 &clientid,
6542 sizeof(errorstring),
6543 errorstring);
6544 if (xsmp.smcconn == NULL)
6545 {
6546 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00006547
Bram Moolenaar071d4272004-06-13 20:20:40 +00006548 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006549 {
6550 vim_snprintf(errorreport, sizeof(errorreport),
6551 _("XSMP SmcOpenConnection failed: %s"), errorstring);
6552 verb_msg((char_u *)errorreport);
6553 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006554 return;
6555 }
6556 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6557
6558#if 0
6559 /* ID ourselves */
6560 smname.value = "vim";
6561 smname.length = 3;
6562 smnameprop.name = "SmProgram";
6563 smnameprop.type = "SmARRAY8";
6564 smnameprop.num_vals = 1;
6565 smnameprop.vals = &smname;
6566
6567 smprops[0] = &smnameprop;
6568 SmcSetProperties(xsmp.smcconn, 1, smprops);
6569#endif
6570}
6571
6572
6573/* Shut down XSMP comms. */
6574 void
6575xsmp_close()
6576{
6577 if (xsmp_icefd != -1)
6578 {
6579 SmcCloseConnection(xsmp.smcconn, 0, NULL);
6580 xsmp_icefd = -1;
6581 }
6582}
6583#endif /* USE_XSMP */
6584
6585
6586#ifdef EBCDIC
6587/* Translate character to its CTRL- value */
6588char CtrlTable[] =
6589{
6590/* 00 - 5E */
6591 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6592 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6593 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6594 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6595 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6596 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6597/* ^ */ 0x1E,
6598/* - */ 0x1F,
6599/* 61 - 6C */
6600 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6601/* _ */ 0x1F,
6602/* 6E - 80 */
6603 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6604/* a */ 0x01,
6605/* b */ 0x02,
6606/* c */ 0x03,
6607/* d */ 0x37,
6608/* e */ 0x2D,
6609/* f */ 0x2E,
6610/* g */ 0x2F,
6611/* h */ 0x16,
6612/* i */ 0x05,
6613/* 8A - 90 */
6614 0, 0, 0, 0, 0, 0, 0,
6615/* j */ 0x15,
6616/* k */ 0x0B,
6617/* l */ 0x0C,
6618/* m */ 0x0D,
6619/* n */ 0x0E,
6620/* o */ 0x0F,
6621/* p */ 0x10,
6622/* q */ 0x11,
6623/* r */ 0x12,
6624/* 9A - A1 */
6625 0, 0, 0, 0, 0, 0, 0, 0,
6626/* s */ 0x13,
6627/* t */ 0x3C,
6628/* u */ 0x3D,
6629/* v */ 0x32,
6630/* w */ 0x26,
6631/* x */ 0x18,
6632/* y */ 0x19,
6633/* z */ 0x3F,
6634/* AA - AC */
6635 0, 0, 0,
6636/* [ */ 0x27,
6637/* AE - BC */
6638 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6639/* ] */ 0x1D,
6640/* BE - C0 */ 0, 0, 0,
6641/* A */ 0x01,
6642/* B */ 0x02,
6643/* C */ 0x03,
6644/* D */ 0x37,
6645/* E */ 0x2D,
6646/* F */ 0x2E,
6647/* G */ 0x2F,
6648/* H */ 0x16,
6649/* I */ 0x05,
6650/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6651/* J */ 0x15,
6652/* K */ 0x0B,
6653/* L */ 0x0C,
6654/* M */ 0x0D,
6655/* N */ 0x0E,
6656/* O */ 0x0F,
6657/* P */ 0x10,
6658/* Q */ 0x11,
6659/* R */ 0x12,
6660/* DA - DF */ 0, 0, 0, 0, 0, 0,
6661/* \ */ 0x1C,
6662/* E1 */ 0,
6663/* S */ 0x13,
6664/* T */ 0x3C,
6665/* U */ 0x3D,
6666/* V */ 0x32,
6667/* W */ 0x26,
6668/* X */ 0x18,
6669/* Y */ 0x19,
6670/* Z */ 0x3F,
6671/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6672 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6673};
6674
6675char MetaCharTable[]=
6676{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6677 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6678 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6679 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6680 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6681};
6682
6683
6684/* TODO: Use characters NOT numbers!!! */
6685char CtrlCharTable[]=
6686{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6687 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6688 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6689 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6690 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6691};
6692
6693
6694#endif