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