blob: ef73270da924c31079891a0b899db68f0b6aee69 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* vi:set ts=8 sts=4 sw=4:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * OS/2 port by Paul Slootman
5 * VMS merge by Zoltan Arpadffy
6 *
7 * Do ":help uganda" in Vim to read copying and usage conditions.
8 * Do ":help credits" in Vim to see a list of people who contributed.
9 * See README.txt for an overview of the Vim source code.
10 */
11
12/*
13 * os_unix.c -- code for all flavors of Unix (BSD, SYSV, SVR4, POSIX, ...)
14 * Also for OS/2, using the excellent EMX package!!!
15 * Also for BeOS and Atari MiNT.
16 *
17 * A lot of this file was originally written by Juergen Weigert and later
18 * changed beyond recognition.
19 */
20
21/*
22 * Some systems have a prototype for select() that has (int *) instead of
23 * (fd_set *), which is wrong. This define removes that prototype. We define
24 * our own prototype below.
25 * Don't use it for the Mac, it causes a warning for precompiled headers.
26 * TODO: use a configure check for precompiled headers?
27 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000028#if !defined(__APPLE__) && !defined(__TANDEM)
Bram Moolenaar071d4272004-06-13 20:20:40 +000029# define select select_declared_wrong
30#endif
31
32#include "vim.h"
33
Bram Moolenaar325b7a22004-07-05 15:58:32 +000034#ifdef FEAT_MZSCHEME
35# include "if_mzsch.h"
36#endif
37
Bram Moolenaar071d4272004-06-13 20:20:40 +000038#include "os_unixx.h" /* unix includes for os_unix.c only */
39
40#ifdef USE_XSMP
41# include <X11/SM/SMlib.h>
42#endif
43
Bram Moolenaar588ebeb2008-05-07 17:09:24 +000044#ifdef HAVE_SELINUX
45# include <selinux/selinux.h>
46static int selinux_enabled = -1;
47#endif
48
Bram Moolenaar071d4272004-06-13 20:20:40 +000049/*
50 * Use this prototype for select, some include files have a wrong prototype
51 */
Bram Moolenaar311d9822007-02-27 15:48:28 +000052#ifndef __TANDEM
53# undef select
54# ifdef __BEOS__
55# define select beos_select
56# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000057#endif
58
Bram Moolenaara2442432007-04-26 14:26:37 +000059#ifdef __CYGWIN__
60# ifndef WIN32
61# include <sys/cygwin.h> /* for cygwin_conv_to_posix_path() */
62# endif
63#endif
64
Bram Moolenaar071d4272004-06-13 20:20:40 +000065#if defined(HAVE_SELECT)
66extern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
67#endif
68
69#ifdef FEAT_MOUSE_GPM
70# include <gpm.h>
71/* <linux/keyboard.h> contains defines conflicting with "keymap.h",
72 * I just copied relevant defines here. A cleaner solution would be to put gpm
73 * code into separate file and include there linux/keyboard.h
74 */
75/* #include <linux/keyboard.h> */
76# define KG_SHIFT 0
77# define KG_CTRL 2
78# define KG_ALT 3
79# define KG_ALTGR 1
80# define KG_SHIFTL 4
81# define KG_SHIFTR 5
82# define KG_CTRLL 6
83# define KG_CTRLR 7
84# define KG_CAPSSHIFT 8
85
86static void gpm_close __ARGS((void));
87static int gpm_open __ARGS((void));
88static int mch_gpm_process __ARGS((void));
89#endif
90
Bram Moolenaar3577c6f2008-06-24 21:16:56 +000091#ifdef FEAT_SYSMOUSE
92# include <sys/consio.h>
93# include <sys/fbio.h>
94
95static int sysmouse_open __ARGS((void));
96static void sysmouse_close __ARGS((void));
97static RETSIGTYPE sig_sysmouse __ARGS(SIGPROTOARG);
98#endif
99
Bram Moolenaar071d4272004-06-13 20:20:40 +0000100/*
101 * end of autoconf section. To be extended...
102 */
103
104/* Are the following #ifdefs still required? And why? Is that for X11? */
105
106#if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
107# ifdef SIGWINCH
108# undef SIGWINCH
109# endif
110# ifdef TIOCGWINSZ
111# undef TIOCGWINSZ
112# endif
113#endif
114
115#if defined(SIGWINDOW) && !defined(SIGWINCH) /* hpux 9.01 has it */
116# define SIGWINCH SIGWINDOW
117#endif
118
119#ifdef FEAT_X11
120# include <X11/Xlib.h>
121# include <X11/Xutil.h>
122# include <X11/Xatom.h>
123# ifdef FEAT_XCLIPBOARD
124# include <X11/Intrinsic.h>
125# include <X11/Shell.h>
126# include <X11/StringDefs.h>
127static Widget xterm_Shell = (Widget)0;
128static void xterm_update __ARGS((void));
129# endif
130
131# if defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE)
132Window x11_window = 0;
133# endif
134Display *x11_display = NULL;
135
136# ifdef FEAT_TITLE
137static int get_x11_windis __ARGS((void));
138static void set_x11_title __ARGS((char_u *));
139static void set_x11_icon __ARGS((char_u *));
140# endif
141#endif
142
143#ifdef FEAT_TITLE
144static int get_x11_title __ARGS((int));
145static int get_x11_icon __ARGS((int));
146
147static char_u *oldtitle = NULL;
148static int did_set_title = FALSE;
149static char_u *oldicon = NULL;
150static int did_set_icon = FALSE;
151#endif
152
153static void may_core_dump __ARGS((void));
154
155static int WaitForChar __ARGS((long));
156#if defined(__BEOS__)
157int RealWaitForChar __ARGS((int, long, int *));
158#else
159static int RealWaitForChar __ARGS((int, long, int *));
160#endif
161
162#ifdef FEAT_XCLIPBOARD
163static int do_xterm_trace __ARGS((void));
Bram Moolenaarcf851ce2005-06-16 21:52:47 +0000164# define XT_TRACE_DELAY 50 /* delay for xterm tracing */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165#endif
166
167static void handle_resize __ARGS((void));
168
169#if defined(SIGWINCH)
170static RETSIGTYPE sig_winch __ARGS(SIGPROTOARG);
171#endif
172#if defined(SIGINT)
173static RETSIGTYPE catch_sigint __ARGS(SIGPROTOARG);
174#endif
175#if defined(SIGPWR)
176static RETSIGTYPE catch_sigpwr __ARGS(SIGPROTOARG);
177#endif
178#if defined(SIGALRM) && defined(FEAT_X11) \
179 && defined(FEAT_TITLE) && !defined(FEAT_GUI_GTK)
180# define SET_SIG_ALARM
181static RETSIGTYPE sig_alarm __ARGS(SIGPROTOARG);
182static int sig_alarm_called;
183#endif
184static RETSIGTYPE deathtrap __ARGS(SIGPROTOARG);
185
Bram Moolenaardf177f62005-02-22 08:39:57 +0000186static void catch_int_signal __ARGS((void));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000187static void set_signals __ARGS((void));
188static void catch_signals __ARGS((RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)()));
189#ifndef __EMX__
190static int have_wildcard __ARGS((int, char_u **));
191static int have_dollars __ARGS((int, char_u **));
192#endif
193
Bram Moolenaar071d4272004-06-13 20:20:40 +0000194#ifndef __EMX__
195static int save_patterns __ARGS((int num_pat, char_u **pat, int *num_file, char_u ***file));
196#endif
197
198#ifndef SIG_ERR
199# define SIG_ERR ((RETSIGTYPE (*)())-1)
200#endif
201
202static int do_resize = FALSE;
203#ifndef __EMX__
204static char_u *extra_shell_arg = NULL;
205static int show_shell_mess = TRUE;
206#endif
207static int deadly_signal = 0; /* The signal we caught */
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000208static int in_mch_delay = FALSE; /* sleeping in mch_delay() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000209
210static int curr_tmode = TMODE_COOK; /* contains current terminal mode */
211
212#ifdef USE_XSMP
213typedef struct
214{
215 SmcConn smcconn; /* The SM connection ID */
216 IceConn iceconn; /* The ICE connection ID */
Bram Moolenaare8208012008-06-20 09:59:25 +0000217 char *clientid; /* The client ID for the current smc session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000218 Bool save_yourself; /* If we're in the middle of a save_yourself */
219 Bool shutdown; /* If we're in shutdown mode */
220} xsmp_config_T;
221
222static xsmp_config_T xsmp;
223#endif
224
225#ifdef SYS_SIGLIST_DECLARED
226/*
227 * I have seen
228 * extern char *_sys_siglist[NSIG];
229 * on Irix, Linux, NetBSD and Solaris. It contains a nice list of strings
230 * that describe the signals. That is nearly what we want here. But
231 * autoconf does only check for sys_siglist (without the underscore), I
232 * do not want to change everything today.... jw.
233 * This is why AC_DECL_SYS_SIGLIST is commented out in configure.in
234 */
235#endif
236
237static struct signalinfo
238{
239 int sig; /* Signal number, eg. SIGSEGV etc */
240 char *name; /* Signal name (not char_u!). */
241 char deadly; /* Catch as a deadly signal? */
242} signal_info[] =
243{
244#ifdef SIGHUP
245 {SIGHUP, "HUP", TRUE},
246#endif
247#ifdef SIGQUIT
248 {SIGQUIT, "QUIT", TRUE},
249#endif
250#ifdef SIGILL
251 {SIGILL, "ILL", TRUE},
252#endif
253#ifdef SIGTRAP
254 {SIGTRAP, "TRAP", TRUE},
255#endif
256#ifdef SIGABRT
257 {SIGABRT, "ABRT", TRUE},
258#endif
259#ifdef SIGEMT
260 {SIGEMT, "EMT", TRUE},
261#endif
262#ifdef SIGFPE
263 {SIGFPE, "FPE", TRUE},
264#endif
265#ifdef SIGBUS
266 {SIGBUS, "BUS", TRUE},
267#endif
268#ifdef SIGSEGV
269 {SIGSEGV, "SEGV", TRUE},
270#endif
271#ifdef SIGSYS
272 {SIGSYS, "SYS", TRUE},
273#endif
274#ifdef SIGALRM
275 {SIGALRM, "ALRM", FALSE}, /* Perl's alarm() can trigger it */
276#endif
277#ifdef SIGTERM
278 {SIGTERM, "TERM", TRUE},
279#endif
280#ifdef SIGVTALRM
281 {SIGVTALRM, "VTALRM", TRUE},
282#endif
Bram Moolenaar02f07e02008-03-12 12:17:28 +0000283#if defined(SIGPROF) && !defined(FEAT_MZSCHEME) && !defined(WE_ARE_PROFILING)
284 /* MzScheme uses SIGPROF for its own needs; On Linux with profiling
285 * this makes Vim exit. WE_ARE_PROFILING is defined in Makefile. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000286 {SIGPROF, "PROF", TRUE},
287#endif
288#ifdef SIGXCPU
289 {SIGXCPU, "XCPU", TRUE},
290#endif
291#ifdef SIGXFSZ
292 {SIGXFSZ, "XFSZ", TRUE},
293#endif
294#ifdef SIGUSR1
295 {SIGUSR1, "USR1", TRUE},
296#endif
Bram Moolenaar3577c6f2008-06-24 21:16:56 +0000297#if defined(SIGUSR2) && !defined(FEAT_SYSMOUSE)
298 /* Used for sysmouse handling */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000299 {SIGUSR2, "USR2", TRUE},
300#endif
301#ifdef SIGINT
302 {SIGINT, "INT", FALSE},
303#endif
304#ifdef SIGWINCH
305 {SIGWINCH, "WINCH", FALSE},
306#endif
307#ifdef SIGTSTP
308 {SIGTSTP, "TSTP", FALSE},
309#endif
310#ifdef SIGPIPE
311 {SIGPIPE, "PIPE", FALSE},
312#endif
313 {-1, "Unknown!", FALSE}
314};
315
316 void
317mch_write(s, len)
318 char_u *s;
319 int len;
320{
321 write(1, (char *)s, len);
322 if (p_wd) /* Unix is too fast, slow down a bit more */
323 RealWaitForChar(read_cmd_fd, p_wd, NULL);
324}
325
326/*
Bram Moolenaarc2a27c32007-12-01 16:19:33 +0000327 * mch_inchar(): low level input function.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000328 * Get a characters from the keyboard.
329 * Return the number of characters that are available.
330 * If wtime == 0 do not wait for characters.
331 * If wtime == n wait a short time for characters.
332 * If wtime == -1 wait forever for characters.
333 */
334 int
335mch_inchar(buf, maxlen, wtime, tb_change_cnt)
336 char_u *buf;
337 int maxlen;
338 long wtime; /* don't use "time", MIPS cannot handle it */
339 int tb_change_cnt;
340{
341 int len;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342
343 /* Check if window changed size while we were busy, perhaps the ":set
344 * columns=99" command was used. */
345 while (do_resize)
346 handle_resize();
347
348 if (wtime >= 0)
349 {
350 while (WaitForChar(wtime) == 0) /* no character available */
351 {
352 if (!do_resize) /* return if not interrupted by resize */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354 handle_resize();
355 }
356 }
357 else /* wtime == -1 */
358 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000359 /*
360 * If there is no character available within 'updatetime' seconds
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000361 * flush all the swap files to disk.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000362 * Also done when interrupted by SIGWINCH.
363 */
364 if (WaitForChar(p_ut) == 0)
365 {
366#ifdef FEAT_AUTOCMD
Bram Moolenaard35f9712005-12-18 22:02:33 +0000367 if (trigger_cursorhold() && maxlen >= 3
368 && !typebuf_changed(tb_change_cnt))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000369 {
Bram Moolenaar4317d9b2005-03-18 20:25:31 +0000370 buf[0] = K_SPECIAL;
371 buf[1] = KS_EXTRA;
372 buf[2] = (int)KE_CURSORHOLD;
373 return 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375#endif
Bram Moolenaard4098f52005-06-27 22:37:13 +0000376 before_blocking();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377 }
378 }
379
380 for (;;) /* repeat until we got a character */
381 {
382 while (do_resize) /* window changed size */
383 handle_resize();
384 /*
385 * we want to be interrupted by the winch signal
386 */
387 WaitForChar(-1L);
388 if (do_resize) /* interrupted by SIGWINCH signal */
389 continue;
390
391 /* If input was put directly in typeahead buffer bail out here. */
392 if (typebuf_changed(tb_change_cnt))
393 return 0;
394
395 /*
396 * For some terminals we only get one character at a time.
397 * We want the get all available characters, so we could keep on
398 * trying until none is available
399 * For some other terminals this is quite slow, that's why we don't do
400 * it.
401 */
402 len = read_from_input_buf(buf, (long)maxlen);
403 if (len > 0)
404 {
405#ifdef OS2
406 int i;
407
408 for (i = 0; i < len; i++)
409 if (buf[i] == 0)
410 buf[i] = K_NUL;
411#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412 return len;
413 }
414 }
415}
416
417 static void
418handle_resize()
419{
420 do_resize = FALSE;
421 shell_resized();
422}
423
424/*
425 * return non-zero if a character is available
426 */
427 int
428mch_char_avail()
429{
430 return WaitForChar(0L);
431}
432
433#if defined(HAVE_TOTAL_MEM) || defined(PROTO)
434# ifdef HAVE_SYS_RESOURCE_H
435# include <sys/resource.h>
436# endif
437# if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL)
438# include <sys/sysctl.h>
439# endif
440# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
441# include <sys/sysinfo.h>
442# endif
443
444/*
Bram Moolenaar914572a2007-05-01 11:37:47 +0000445 * Return total amount of memory available in Kbyte.
446 * Doesn't change when memory has been allocated.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000447 */
448/* ARGSUSED */
449 long_u
450mch_total_mem(special)
451 int special;
452{
453# ifdef __EMX__
Bram Moolenaar914572a2007-05-01 11:37:47 +0000454 return ulimit(3, 0L) >> 10; /* always 32MB? */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000455# else
456 long_u mem = 0;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000457 long_u shiftright = 10; /* how much to shift "mem" right for Kbyte */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458
459# ifdef HAVE_SYSCTL
460 int mib[2], physmem;
461 size_t len;
462
463 /* BSD way of getting the amount of RAM available. */
464 mib[0] = CTL_HW;
465 mib[1] = HW_USERMEM;
466 len = sizeof(physmem);
467 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == 0)
468 mem = (long_u)physmem;
469# endif
470
471# if defined(HAVE_SYS_SYSINFO_H) && defined(HAVE_SYSINFO)
472 if (mem == 0)
473 {
474 struct sysinfo sinfo;
475
476 /* Linux way of getting amount of RAM available */
477 if (sysinfo(&sinfo) == 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000478 {
479# ifdef HAVE_SYSINFO_MEM_UNIT
480 /* avoid overflow as much as possible */
481 while (shiftright > 0 && (sinfo.mem_unit & 1) == 0)
482 {
483 sinfo.mem_unit = sinfo.mem_unit >> 1;
484 --shiftright;
485 }
486 mem = sinfo.totalram * sinfo.mem_unit;
487# else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488 mem = sinfo.totalram;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000489# endif
490 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000491 }
492# endif
493
494# ifdef HAVE_SYSCONF
495 if (mem == 0)
496 {
497 long pagesize, pagecount;
498
499 /* Solaris way of getting amount of RAM available */
500 pagesize = sysconf(_SC_PAGESIZE);
501 pagecount = sysconf(_SC_PHYS_PAGES);
502 if (pagesize > 0 && pagecount > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000503 {
504 /* avoid overflow as much as possible */
505 while (shiftright > 0 && (pagesize & 1) == 0)
506 {
Bram Moolenaar3d27a452007-05-10 17:44:18 +0000507 pagesize = (long_u)pagesize >> 1;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000508 --shiftright;
509 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000511 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000512 }
513# endif
514
515 /* Return the minimum of the physical memory and the user limit, because
516 * using more than the user limit may cause Vim to be terminated. */
517# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
518 {
519 struct rlimit rlp;
520
521 if (getrlimit(RLIMIT_DATA, &rlp) == 0
522 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
523# ifdef RLIM_INFINITY
524 && rlp.rlim_cur != RLIM_INFINITY
525# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000526 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000527 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000528 {
529 mem = (long_u)rlp.rlim_cur;
530 shiftright = 10;
531 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532 }
533# endif
534
535 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000536 return mem >> shiftright;
537 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000538# endif
539}
540#endif
541
542 void
543mch_delay(msec, ignoreinput)
544 long msec;
545 int ignoreinput;
546{
547 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000548#ifdef FEAT_MZSCHEME
549 long total = msec; /* remember original value */
550#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551
552 if (ignoreinput)
553 {
554 /* Go to cooked mode without echo, to allow SIGINT interrupting us
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000555 * here. But we don't want QUIT to kill us (CTRL-\ used in a
556 * shell may produce SIGQUIT). */
557 in_mch_delay = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000558 old_tmode = curr_tmode;
559 if (curr_tmode == TMODE_RAW)
560 settmode(TMODE_SLEEP);
561
562 /*
563 * Everybody sleeps in a different way...
564 * Prefer nanosleep(), some versions of usleep() can only sleep up to
565 * one second.
566 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000567#ifdef FEAT_MZSCHEME
568 do
569 {
570 /* if total is large enough, wait by portions in p_mzq */
571 if (total > p_mzq)
572 msec = p_mzq;
573 else
574 msec = total;
575 total -= msec;
576#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000577#ifdef HAVE_NANOSLEEP
578 {
579 struct timespec ts;
580
581 ts.tv_sec = msec / 1000;
582 ts.tv_nsec = (msec % 1000) * 1000000;
583 (void)nanosleep(&ts, NULL);
584 }
585#else
586# ifdef HAVE_USLEEP
587 while (msec >= 1000)
588 {
589 usleep((unsigned int)(999 * 1000));
590 msec -= 999;
591 }
592 usleep((unsigned int)(msec * 1000));
593# else
594# ifndef HAVE_SELECT
595 poll(NULL, 0, (int)msec);
596# else
597# ifdef __EMX__
598 _sleep2(msec);
599# else
600 {
601 struct timeval tv;
602
603 tv.tv_sec = msec / 1000;
604 tv.tv_usec = (msec % 1000) * 1000;
605 /*
606 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
607 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
608 */
609 select(0, NULL, NULL, NULL, &tv);
610 }
611# endif /* __EMX__ */
612# endif /* HAVE_SELECT */
613# endif /* HAVE_NANOSLEEP */
614#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000615#ifdef FEAT_MZSCHEME
616 }
617 while (total > 0);
618#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000619
620 settmode(old_tmode);
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000621 in_mch_delay = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 }
623 else
624 WaitForChar(msec);
625}
626
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000627#if 0 /* disabled, no longer needed now that regmatch() is not recursive */
628# if defined(HAVE_GETRLIMIT)
629# define HAVE_STACK_LIMIT
630# endif
631#endif
632
633#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
635# define HAVE_CHECK_STACK_GROWTH
636/*
637 * Support for checking for an almost-out-of-stack-space situation.
638 */
639
640/*
641 * Return a pointer to an item on the stack. Used to find out if the stack
642 * grows up or down.
643 */
644static void check_stack_growth __ARGS((char *p));
645static int stack_grows_downwards;
646
647/*
648 * Find out if the stack grows upwards or downwards.
649 * "p" points to a variable on the stack of the caller.
650 */
651 static void
652check_stack_growth(p)
653 char *p;
654{
655 int i;
656
657 stack_grows_downwards = (p > (char *)&i);
658}
659#endif
660
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000661#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000662static char *stack_limit = NULL;
663
664#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
665# include <pthread.h>
666# include <pthread_np.h>
667#endif
668
669/*
670 * Find out until how var the stack can grow without getting into trouble.
671 * Called when starting up and when switching to the signal stack in
672 * deathtrap().
673 */
674 static void
675get_stack_limit()
676{
677 struct rlimit rlp;
678 int i;
679 long lim;
680
681 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
682 * limit doesn't fit in a long (rlim_cur might be "long long"). */
683 if (getrlimit(RLIMIT_STACK, &rlp) == 0
684 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
685# ifdef RLIM_INFINITY
686 && rlp.rlim_cur != RLIM_INFINITY
687# endif
688 )
689 {
690 lim = (long)rlp.rlim_cur;
691#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
692 {
693 pthread_attr_t attr;
694 size_t size;
695
696 /* On FreeBSD the initial thread always has a fixed stack size, no
697 * matter what the limits are set to. Normally it's 1 Mbyte. */
698 pthread_attr_init(&attr);
699 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
700 {
701 pthread_attr_getstacksize(&attr, &size);
702 if (lim > (long)size)
703 lim = (long)size;
704 }
705 pthread_attr_destroy(&attr);
706 }
707#endif
708 if (stack_grows_downwards)
709 {
710 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
711 if (stack_limit >= (char *)&i)
712 /* overflow, set to 1/16 of current stack position */
713 stack_limit = (char *)((long)&i / 16L);
714 }
715 else
716 {
717 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
718 if (stack_limit <= (char *)&i)
719 stack_limit = NULL; /* overflow */
720 }
721 }
722}
723
724/*
725 * Return FAIL when running out of stack space.
726 * "p" must point to any variable local to the caller that's on the stack.
727 */
728 int
729mch_stackcheck(p)
730 char *p;
731{
732 if (stack_limit != NULL)
733 {
734 if (stack_grows_downwards)
735 {
736 if (p < stack_limit)
737 return FAIL;
738 }
739 else if (p > stack_limit)
740 return FAIL;
741 }
742 return OK;
743}
744#endif
745
746#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
747/*
748 * Support for using the signal stack.
749 * This helps when we run out of stack space, which causes a SIGSEGV. The
750 * signal handler then must run on another stack, since the normal stack is
751 * completely full.
752 */
753
754#ifndef SIGSTKSZ
755# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
756#endif
757
758# ifdef HAVE_SIGALTSTACK
759static stack_t sigstk; /* for sigaltstack() */
760# else
761static struct sigstack sigstk; /* for sigstack() */
762# endif
763
764static void init_signal_stack __ARGS((void));
765static char *signal_stack;
766
767 static void
768init_signal_stack()
769{
770 if (signal_stack != NULL)
771 {
772# ifdef HAVE_SIGALTSTACK
Bram Moolenaar1a3d0862007-08-30 09:47:38 +0000773# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
774 || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
776 * "struct sigaltstack" needs to be declared. */
777 extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
778# endif
779
780# ifdef HAVE_SS_BASE
781 sigstk.ss_base = signal_stack;
782# else
783 sigstk.ss_sp = signal_stack;
784# endif
785 sigstk.ss_size = SIGSTKSZ;
786 sigstk.ss_flags = 0;
787 (void)sigaltstack(&sigstk, NULL);
788# else
789 sigstk.ss_sp = signal_stack;
790 if (stack_grows_downwards)
791 sigstk.ss_sp += SIGSTKSZ - 1;
792 sigstk.ss_onstack = 0;
793 (void)sigstack(&sigstk, NULL);
794# endif
795 }
796}
797#endif
798
799/*
800 * We need correct potatotypes for a signal function, otherwise mean compilers
801 * will barf when the second argument to signal() is ``wrong''.
802 * Let me try it with a few tricky defines from my own osdef.h (jw).
803 */
804#if defined(SIGWINCH)
805/* ARGSUSED */
806 static RETSIGTYPE
807sig_winch SIGDEFARG(sigarg)
808{
809 /* this is not required on all systems, but it doesn't hurt anybody */
810 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
811 do_resize = TRUE;
812 SIGRETURN;
813}
814#endif
815
816#if defined(SIGINT)
817/* ARGSUSED */
818 static RETSIGTYPE
819catch_sigint SIGDEFARG(sigarg)
820{
821 /* this is not required on all systems, but it doesn't hurt anybody */
822 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
823 got_int = TRUE;
824 SIGRETURN;
825}
826#endif
827
828#if defined(SIGPWR)
829/* ARGSUSED */
830 static RETSIGTYPE
831catch_sigpwr SIGDEFARG(sigarg)
832{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000833 /* this is not required on all systems, but it doesn't hurt anybody */
834 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 /*
836 * I'm not sure we get the SIGPWR signal when the system is really going
837 * down or when the batteries are almost empty. Just preserve the swap
838 * files and don't exit, that can't do any harm.
839 */
840 ml_sync_all(FALSE, FALSE);
841 SIGRETURN;
842}
843#endif
844
845#ifdef SET_SIG_ALARM
846/*
847 * signal function for alarm().
848 */
849/* ARGSUSED */
850 static RETSIGTYPE
851sig_alarm SIGDEFARG(sigarg)
852{
853 /* doesn't do anything, just to break a system call */
854 sig_alarm_called = TRUE;
855 SIGRETURN;
856}
857#endif
858
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000859#if (defined(HAVE_SETJMP_H) \
860 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
861 || defined(FEAT_LIBCALL))) \
862 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863/*
864 * A simplistic version of setjmp() that only allows one level of using.
865 * Don't call twice before calling mch_endjmp()!.
866 * Usage:
867 * mch_startjmp();
868 * if (SETJMP(lc_jump_env) != 0)
869 * {
870 * mch_didjmp();
871 * EMSG("crash!");
872 * }
873 * else
874 * {
875 * do_the_work;
876 * mch_endjmp();
877 * }
878 * Note: Can't move SETJMP() here, because a function calling setjmp() must
879 * not return before the saved environment is used.
880 * Returns OK for normal return, FAIL when the protected code caused a
881 * problem and LONGJMP() was used.
882 */
883 void
884mch_startjmp()
885{
886#ifdef SIGHASARG
887 lc_signal = 0;
888#endif
889 lc_active = TRUE;
890}
891
892 void
893mch_endjmp()
894{
895 lc_active = FALSE;
896}
897
898 void
899mch_didjmp()
900{
901# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
902 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
903 * otherwise catching the signal only works once. */
904 init_signal_stack();
905# endif
906}
907#endif
908
909/*
910 * This function handles deadly signals.
911 * It tries to preserve any swap file and exit properly.
912 * (partly from Elvis).
913 */
914 static RETSIGTYPE
915deathtrap SIGDEFARG(sigarg)
916{
917 static int entered = 0; /* count the number of times we got here.
918 Note: when memory has been corrupted
919 this may get an arbitrary value! */
920#ifdef SIGHASARG
921 int i;
922#endif
923
924#if defined(HAVE_SETJMP_H)
925 /*
926 * Catch a crash in protected code.
927 * Restores the environment saved in lc_jump_env, which looks like
928 * SETJMP() returns 1.
929 */
930 if (lc_active)
931 {
932# if defined(SIGHASARG)
933 lc_signal = sigarg;
934# endif
935 lc_active = FALSE; /* don't jump again */
936 LONGJMP(lc_jump_env, 1);
937 /* NOTREACHED */
938 }
939#endif
940
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000941#ifdef SIGHASARG
Bram Moolenaarae0f2ca2008-02-10 21:25:55 +0000942# ifdef SIGQUIT
943 /* While in mch_delay() we go to cooked mode to allow a CTRL-C to
944 * interrupt us. But in cooked mode we may also get SIGQUIT, e.g., when
945 * pressing CTRL-\, but we don't want Vim to exit then. */
946 if (in_mch_delay && sigarg == SIGQUIT)
947 SIGRETURN;
948# endif
949
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000950 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
951 * here. This avoids that a non-reentrant function is interrupted, e.g.,
952 * free(). Calling free() again may then cause a crash. */
953 if (entered == 0
954 && (0
955# ifdef SIGHUP
956 || sigarg == SIGHUP
957# endif
958# ifdef SIGQUIT
959 || sigarg == SIGQUIT
960# endif
961# ifdef SIGTERM
962 || sigarg == SIGTERM
963# endif
964# ifdef SIGPWR
965 || sigarg == SIGPWR
966# endif
967# ifdef SIGUSR1
968 || sigarg == SIGUSR1
969# endif
970# ifdef SIGUSR2
971 || sigarg == SIGUSR2
972# endif
973 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +0000974 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000975 SIGRETURN;
976#endif
977
Bram Moolenaar071d4272004-06-13 20:20:40 +0000978 /* Remember how often we have been called. */
979 ++entered;
980
981#ifdef FEAT_EVAL
982 /* Set the v:dying variable. */
983 set_vim_var_nr(VV_DYING, (long)entered);
984#endif
985
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000986#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +0000987 /* Since we are now using the signal stack, need to reset the stack
988 * limit. Otherwise using a regexp will fail. */
989 get_stack_limit();
990#endif
991
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +0000992#if 0
993 /* This is for opening gdb the moment Vim crashes.
994 * You need to manually adjust the file name and Vim executable name.
995 * Suggested by SungHyun Nam. */
996 {
997# define VI_GDB_FILE "/tmp/vimgdb"
998# define VIM_NAME "/usr/bin/vim"
999 FILE *fp = fopen(VI_GDB_FILE, "w");
1000 if (fp)
1001 {
1002 fprintf(fp,
1003 "file %s\n"
1004 "attach %d\n"
1005 "set height 1000\n"
1006 "bt full\n"
1007 , VIM_NAME, getpid());
1008 fclose(fp);
1009 system("xterm -e gdb -x "VI_GDB_FILE);
1010 unlink(VI_GDB_FILE);
1011 }
1012 }
1013#endif
1014
Bram Moolenaar071d4272004-06-13 20:20:40 +00001015#ifdef SIGHASARG
1016 /* try to find the name of this signal */
1017 for (i = 0; signal_info[i].sig != -1; i++)
1018 if (sigarg == signal_info[i].sig)
1019 break;
1020 deadly_signal = sigarg;
1021#endif
1022
1023 full_screen = FALSE; /* don't write message to the GUI, it might be
1024 * part of the problem... */
1025 /*
1026 * If something goes wrong after entering here, we may get here again.
1027 * When this happens, give a message and try to exit nicely (resetting the
1028 * terminal mode, etc.)
1029 * When this happens twice, just exit, don't even try to give a message,
1030 * stack may be corrupt or something weird.
1031 * When this still happens again (or memory was corrupted in such a way
1032 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1033 */
1034 if (entered >= 3)
1035 {
1036 reset_signals(); /* don't catch any signals anymore */
1037 may_core_dump();
1038 if (entered >= 4)
1039 _exit(8);
1040 exit(7);
1041 }
1042 if (entered == 2)
1043 {
1044 OUT_STR(_("Vim: Double signal, exiting\n"));
1045 out_flush();
1046 getout(1);
1047 }
1048
1049#ifdef SIGHASARG
1050 sprintf((char *)IObuff, _("Vim: Caught deadly signal %s\n"),
1051 signal_info[i].name);
1052#else
1053 sprintf((char *)IObuff, _("Vim: Caught deadly signal\n"));
1054#endif
1055 preserve_exit(); /* preserve files and exit */
1056
Bram Moolenaar009b2592004-10-24 19:18:58 +00001057#ifdef NBDEBUG
1058 reset_signals();
1059 may_core_dump();
1060 abort();
1061#endif
1062
Bram Moolenaar071d4272004-06-13 20:20:40 +00001063 SIGRETURN;
1064}
1065
1066#ifdef _REENTRANT
1067/*
1068 * On Solaris with multi-threading, suspending might not work immediately.
1069 * Catch the SIGCONT signal, which will be used as an indication whether the
1070 * suspending has been done or not.
1071 */
1072static int sigcont_received;
1073static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1074
1075/*
1076 * signal handler for SIGCONT
1077 */
1078/* ARGSUSED */
1079 static RETSIGTYPE
1080sigcont_handler SIGDEFARG(sigarg)
1081{
1082 sigcont_received = TRUE;
1083 SIGRETURN;
1084}
1085#endif
1086
1087/*
1088 * If the machine has job control, use it to suspend the program,
1089 * otherwise fake it by starting a new shell.
1090 */
1091 void
1092mch_suspend()
1093{
1094 /* BeOS does have SIGTSTP, but it doesn't work. */
1095#if defined(SIGTSTP) && !defined(__BEOS__)
1096 out_flush(); /* needed to make cursor visible on some systems */
1097 settmode(TMODE_COOK);
1098 out_flush(); /* needed to disable mouse on some systems */
1099
1100# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1101 /* Since we are going to sleep, we can't respond to requests for the X
1102 * selections. Lose them, otherwise other applications will hang. But
1103 * first copy the text to cut buffer 0. */
1104 if (clip_star.owned || clip_plus.owned)
1105 {
1106 x11_export_final_selection();
1107 if (clip_star.owned)
1108 clip_lose_selection(&clip_star);
1109 if (clip_plus.owned)
1110 clip_lose_selection(&clip_plus);
1111 if (x11_display != NULL)
1112 XFlush(x11_display);
1113 }
1114# endif
1115
1116# ifdef _REENTRANT
1117 sigcont_received = FALSE;
1118# endif
1119 kill(0, SIGTSTP); /* send ourselves a STOP signal */
1120# ifdef _REENTRANT
1121 /* When we didn't suspend immediately in the kill(), do it now. Happens
1122 * on multi-threaded Solaris. */
1123 if (!sigcont_received)
1124 pause();
1125# endif
1126
1127# ifdef FEAT_TITLE
1128 /*
1129 * Set oldtitle to NULL, so the current title is obtained again.
1130 */
1131 vim_free(oldtitle);
1132 oldtitle = NULL;
1133# endif
1134 settmode(TMODE_RAW);
1135 need_check_timestamps = TRUE;
1136 did_check_timestamps = FALSE;
1137#else
1138 suspend_shell();
1139#endif
1140}
1141
1142 void
1143mch_init()
1144{
1145 Columns = 80;
1146 Rows = 24;
1147
1148 out_flush();
1149 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001150
Bram Moolenaar56718732006-03-15 22:53:57 +00001151#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001152 mac_conv_init();
1153#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001154}
1155
1156 static void
1157set_signals()
1158{
1159#if defined(SIGWINCH)
1160 /*
1161 * WINDOW CHANGE signal is handled with sig_winch().
1162 */
1163 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1164#endif
1165
1166 /*
1167 * We want the STOP signal to work, to make mch_suspend() work.
1168 * For "rvim" the STOP signal is ignored.
1169 */
1170#ifdef SIGTSTP
1171 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1172#endif
1173#ifdef _REENTRANT
1174 signal(SIGCONT, sigcont_handler);
1175#endif
1176
1177 /*
1178 * We want to ignore breaking of PIPEs.
1179 */
1180#ifdef SIGPIPE
1181 signal(SIGPIPE, SIG_IGN);
1182#endif
1183
Bram Moolenaar071d4272004-06-13 20:20:40 +00001184#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001185 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186#endif
1187
1188 /*
1189 * Ignore alarm signals (Perl's alarm() generates it).
1190 */
1191#ifdef SIGALRM
1192 signal(SIGALRM, SIG_IGN);
1193#endif
1194
1195 /*
1196 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1197 * work will be lost.
1198 */
1199#ifdef SIGPWR
1200 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1201#endif
1202
1203 /*
1204 * Arrange for other signals to gracefully shutdown Vim.
1205 */
1206 catch_signals(deathtrap, SIG_ERR);
1207
1208#if defined(FEAT_GUI) && defined(SIGHUP)
1209 /*
1210 * When the GUI is running, ignore the hangup signal.
1211 */
1212 if (gui.in_use)
1213 signal(SIGHUP, SIG_IGN);
1214#endif
1215}
1216
Bram Moolenaardf177f62005-02-22 08:39:57 +00001217#if defined(SIGINT) || defined(PROTO)
1218/*
1219 * Catch CTRL-C (only works while in Cooked mode).
1220 */
1221 static void
1222catch_int_signal()
1223{
1224 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1225}
1226#endif
1227
Bram Moolenaar071d4272004-06-13 20:20:40 +00001228 void
1229reset_signals()
1230{
1231 catch_signals(SIG_DFL, SIG_DFL);
1232#ifdef _REENTRANT
1233 /* SIGCONT isn't in the list, because its default action is ignore */
1234 signal(SIGCONT, SIG_DFL);
1235#endif
1236}
1237
1238 static void
1239catch_signals(func_deadly, func_other)
1240 RETSIGTYPE (*func_deadly)();
1241 RETSIGTYPE (*func_other)();
1242{
1243 int i;
1244
1245 for (i = 0; signal_info[i].sig != -1; i++)
1246 if (signal_info[i].deadly)
1247 {
1248#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1249 struct sigaction sa;
1250
1251 /* Setup to use the alternate stack for the signal function. */
1252 sa.sa_handler = func_deadly;
1253 sigemptyset(&sa.sa_mask);
1254# if defined(__linux__) && defined(_REENTRANT)
1255 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1256 * thread handling in combination with using the alternate stack:
1257 * pthread library functions try to use the stack pointer to
1258 * identify the current thread, causing a SEGV signal, which
1259 * recursively calls deathtrap() and hangs. */
1260 sa.sa_flags = 0;
1261# else
1262 sa.sa_flags = SA_ONSTACK;
1263# endif
1264 sigaction(signal_info[i].sig, &sa, NULL);
1265#else
1266# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1267 struct sigvec sv;
1268
1269 /* Setup to use the alternate stack for the signal function. */
1270 sv.sv_handler = func_deadly;
1271 sv.sv_mask = 0;
1272 sv.sv_flags = SV_ONSTACK;
1273 sigvec(signal_info[i].sig, &sv, NULL);
1274# else
1275 signal(signal_info[i].sig, func_deadly);
1276# endif
1277#endif
1278 }
1279 else if (func_other != SIG_ERR)
1280 signal(signal_info[i].sig, func_other);
1281}
1282
1283/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001284 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001285 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1286 * return TRUE
1287 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1288 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
1289 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001290 * Returns TRUE when Vim should exit.
1291 */
1292 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001293vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001294 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001295{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001296 static int got_signal = 0;
1297 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001298
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001299 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001300 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001301 case SIGNAL_BLOCK: blocked = TRUE;
1302 break;
1303
1304 case SIGNAL_UNBLOCK: blocked = FALSE;
1305 if (got_signal != 0)
1306 {
1307 kill(getpid(), got_signal);
1308 got_signal = 0;
1309 }
1310 break;
1311
1312 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001313 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001314 got_signal = sig;
1315#ifdef SIGPWR
1316 if (sig != SIGPWR)
1317#endif
1318 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001319 break;
1320 }
1321 return FALSE;
1322}
1323
1324/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001325 * Check_win checks whether we have an interactive stdout.
1326 */
1327/* ARGSUSED */
1328 int
1329mch_check_win(argc, argv)
1330 int argc;
1331 char **argv;
1332{
1333#ifdef OS2
1334 /*
1335 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1336 * name, mostly it's just "vim" and found in the path, which is unusable.
1337 */
1338 if (mch_isFullName(argv[0]))
1339 exe_name = vim_strsave((char_u *)argv[0]);
1340#endif
1341 if (isatty(1))
1342 return OK;
1343 return FAIL;
1344}
1345
1346/*
1347 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1348 */
1349 int
1350mch_input_isatty()
1351{
1352 if (isatty(read_cmd_fd))
1353 return TRUE;
1354 return FALSE;
1355}
1356
1357#ifdef FEAT_X11
1358
1359# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1360 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1361
1362static void xopen_message __ARGS((struct timeval *tvp));
1363
1364/*
1365 * Give a message about the elapsed time for opening the X window.
1366 */
1367 static void
1368xopen_message(tvp)
1369 struct timeval *tvp; /* must contain start time */
1370{
1371 struct timeval end_tv;
1372
1373 /* Compute elapsed time. */
1374 gettimeofday(&end_tv, NULL);
1375 smsg((char_u *)_("Opening the X display took %ld msec"),
1376 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001377 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001378}
1379# endif
1380#endif
1381
1382#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1383/*
1384 * A few functions shared by X11 title and clipboard code.
1385 */
1386static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1387static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1388static int x_connect_to_server __ARGS((void));
1389static int test_x11_window __ARGS((Display *dpy));
1390
1391static int got_x_error = FALSE;
1392
1393/*
1394 * X Error handler, otherwise X just exits! (very rude) -- webb
1395 */
1396 static int
1397x_error_handler(dpy, error_event)
1398 Display *dpy;
1399 XErrorEvent *error_event;
1400{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001401 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001402 STRCAT(IObuff, _("\nVim: Got X error\n"));
1403
1404 /* We cannot print a message and continue, because no X calls are allowed
1405 * here (causes my system to hang). Silently continuing might be an
1406 * alternative... */
1407 preserve_exit(); /* preserve files and exit */
1408
1409 return 0; /* NOTREACHED */
1410}
1411
1412/*
1413 * Another X Error handler, just used to check for errors.
1414 */
1415/* ARGSUSED */
1416 static int
1417x_error_check(dpy, error_event)
1418 Display *dpy;
1419 XErrorEvent *error_event;
1420{
1421 got_x_error = TRUE;
1422 return 0;
1423}
1424
1425#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1426# if defined(HAVE_SETJMP_H)
1427/*
1428 * An X IO Error handler, used to catch error while opening the display.
1429 */
1430static int x_IOerror_check __ARGS((Display *dpy));
1431
1432/* ARGSUSED */
1433 static int
1434x_IOerror_check(dpy)
1435 Display *dpy;
1436{
1437 /* This function should not return, it causes exit(). Longjump instead. */
1438 LONGJMP(lc_jump_env, 1);
1439 /*NOTREACHED*/
1440 return 0;
1441}
1442# endif
1443
1444/*
1445 * An X IO Error handler, used to catch terminal errors.
1446 */
1447static int x_IOerror_handler __ARGS((Display *dpy));
1448
1449/* ARGSUSED */
1450 static int
1451x_IOerror_handler(dpy)
1452 Display *dpy;
1453{
1454 xterm_dpy = NULL;
1455 x11_window = 0;
1456 x11_display = NULL;
1457 xterm_Shell = (Widget)0;
1458
1459 /* This function should not return, it causes exit(). Longjump instead. */
1460 LONGJMP(x_jump_env, 1);
1461 /*NOTREACHED*/
1462 return 0;
1463}
1464#endif
1465
1466/*
1467 * Return TRUE when connection to the X server is desired.
1468 */
1469 static int
1470x_connect_to_server()
1471{
1472 regmatch_T regmatch;
1473
1474#if defined(FEAT_CLIENTSERVER)
1475 if (x_force_connect)
1476 return TRUE;
1477#endif
1478 if (x_no_connect)
1479 return FALSE;
1480
1481 /* Check for a match with "exclude:" from 'clipboard'. */
1482 if (clip_exclude_prog != NULL)
1483 {
1484 regmatch.rm_ic = FALSE; /* Don't ignore case */
1485 regmatch.regprog = clip_exclude_prog;
1486 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1487 return FALSE;
1488 }
1489 return TRUE;
1490}
1491
1492/*
1493 * Test if "dpy" and x11_window are valid by getting the window title.
1494 * I don't actually want it yet, so there may be a simpler call to use, but
1495 * this will cause the error handler x_error_check() to be called if anything
1496 * is wrong, such as the window pointer being invalid (as can happen when the
1497 * user changes his DISPLAY, but not his WINDOWID) -- webb
1498 */
1499 static int
1500test_x11_window(dpy)
1501 Display *dpy;
1502{
1503 int (*old_handler)();
1504 XTextProperty text_prop;
1505
1506 old_handler = XSetErrorHandler(x_error_check);
1507 got_x_error = FALSE;
1508 if (XGetWMName(dpy, x11_window, &text_prop))
1509 XFree((void *)text_prop.value);
1510 XSync(dpy, False);
1511 (void)XSetErrorHandler(old_handler);
1512
1513 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001514 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001515
1516 return (got_x_error ? FAIL : OK);
1517}
1518#endif
1519
1520#ifdef FEAT_TITLE
1521
1522#ifdef FEAT_X11
1523
1524static int get_x11_thing __ARGS((int get_title, int test_only));
1525
1526/*
1527 * try to get x11 window and display
1528 *
1529 * return FAIL for failure, OK otherwise
1530 */
1531 static int
1532get_x11_windis()
1533{
1534 char *winid;
1535 static int result = -1;
1536#define XD_NONE 0 /* x11_display not set here */
1537#define XD_HERE 1 /* x11_display opened here */
1538#define XD_GUI 2 /* x11_display used from gui.dpy */
1539#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1540 static int x11_display_from = XD_NONE;
1541 static int did_set_error_handler = FALSE;
1542
1543 if (!did_set_error_handler)
1544 {
1545 /* X just exits if it finds an error otherwise! */
1546 (void)XSetErrorHandler(x_error_handler);
1547 did_set_error_handler = TRUE;
1548 }
1549
Bram Moolenaar9372a112005-12-06 19:59:18 +00001550#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001551 if (gui.in_use)
1552 {
1553 /*
1554 * If the X11 display was opened here before, for the window where Vim
1555 * was started, close that one now to avoid a memory leak.
1556 */
1557 if (x11_display_from == XD_HERE && x11_display != NULL)
1558 {
1559 XCloseDisplay(x11_display);
1560 x11_display_from = XD_NONE;
1561 }
1562 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1563 {
1564 x11_display_from = XD_GUI;
1565 return OK;
1566 }
1567 x11_display = NULL;
1568 return FAIL;
1569 }
1570 else if (x11_display_from == XD_GUI)
1571 {
1572 /* GUI must have stopped somehow, clear x11_display */
1573 x11_window = 0;
1574 x11_display = NULL;
1575 x11_display_from = XD_NONE;
1576 }
1577#endif
1578
1579 /* When started with the "-X" argument, don't try connecting. */
1580 if (!x_connect_to_server())
1581 return FAIL;
1582
1583 /*
1584 * If WINDOWID not set, should try another method to find out
1585 * what the current window number is. The only code I know for
1586 * this is very complicated.
1587 * We assume that zero is invalid for WINDOWID.
1588 */
1589 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1590 x11_window = (Window)atol(winid);
1591
1592#ifdef FEAT_XCLIPBOARD
1593 if (xterm_dpy != NULL && x11_window != 0)
1594 {
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00001595 /* We may have checked it already, but Gnome terminal can move us to
1596 * another window, so we need to check every time. */
1597 if (x11_display_from != XD_XTERM)
1598 {
1599 /*
1600 * If the X11 display was opened here before, for the window where
1601 * Vim was started, close that one now to avoid a memory leak.
1602 */
1603 if (x11_display_from == XD_HERE && x11_display != NULL)
1604 XCloseDisplay(x11_display);
1605 x11_display = xterm_dpy;
1606 x11_display_from = XD_XTERM;
1607 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001608 if (test_x11_window(x11_display) == FAIL)
1609 {
1610 /* probably bad $WINDOWID */
1611 x11_window = 0;
1612 x11_display = NULL;
1613 x11_display_from = XD_NONE;
1614 return FAIL;
1615 }
1616 return OK;
1617 }
1618#endif
1619
1620 if (x11_window == 0 || x11_display == NULL)
1621 result = -1;
1622
1623 if (result != -1) /* Have already been here and set this */
1624 return result; /* Don't do all these X calls again */
1625
1626 if (x11_window != 0 && x11_display == NULL)
1627 {
1628#ifdef SET_SIG_ALARM
1629 RETSIGTYPE (*sig_save)();
1630#endif
1631#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1632 struct timeval start_tv;
1633
1634 if (p_verbose > 0)
1635 gettimeofday(&start_tv, NULL);
1636#endif
1637
1638#ifdef SET_SIG_ALARM
1639 /*
1640 * Opening the Display may hang if the DISPLAY setting is wrong, or
1641 * the network connection is bad. Set an alarm timer to get out.
1642 */
1643 sig_alarm_called = FALSE;
1644 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1645 (RETSIGTYPE (*)())sig_alarm);
1646 alarm(2);
1647#endif
1648 x11_display = XOpenDisplay(NULL);
1649
1650#ifdef SET_SIG_ALARM
1651 alarm(0);
1652 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1653 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001654 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001655#endif
1656 if (x11_display != NULL)
1657 {
1658# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1659 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001660 {
1661 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001662 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001663 verbose_leave();
1664 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001665# endif
1666 if (test_x11_window(x11_display) == FAIL)
1667 {
1668 /* Maybe window id is bad */
1669 x11_window = 0;
1670 XCloseDisplay(x11_display);
1671 x11_display = NULL;
1672 }
1673 else
1674 x11_display_from = XD_HERE;
1675 }
1676 }
1677 if (x11_window == 0 || x11_display == NULL)
1678 return (result = FAIL);
1679 return (result = OK);
1680}
1681
1682/*
1683 * Determine original x11 Window Title
1684 */
1685 static int
1686get_x11_title(test_only)
1687 int test_only;
1688{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001689 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001690}
1691
1692/*
1693 * Determine original x11 Window icon
1694 */
1695 static int
1696get_x11_icon(test_only)
1697 int test_only;
1698{
1699 int retval = FALSE;
1700
1701 retval = get_x11_thing(FALSE, test_only);
1702
1703 /* could not get old icon, use terminal name */
1704 if (oldicon == NULL && !test_only)
1705 {
1706 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1707 oldicon = T_NAME + 8;
1708 else
1709 oldicon = T_NAME;
1710 }
1711
1712 return retval;
1713}
1714
1715 static int
1716get_x11_thing(get_title, test_only)
1717 int get_title; /* get title string */
1718 int test_only;
1719{
1720 XTextProperty text_prop;
1721 int retval = FALSE;
1722 Status status;
1723
1724 if (get_x11_windis() == OK)
1725 {
1726 /* Get window/icon name if any */
1727 if (get_title)
1728 status = XGetWMName(x11_display, x11_window, &text_prop);
1729 else
1730 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1731
1732 /*
1733 * If terminal is xterm, then x11_window may be a child window of the
1734 * outer xterm window that actually contains the window/icon name, so
1735 * keep traversing up the tree until a window with a title/icon is
1736 * found.
1737 */
1738 /* Previously this was only done for xterm and alikes. I don't see a
1739 * reason why it would fail for other terminal emulators.
1740 * if (term_is_xterm) */
1741 {
1742 Window root;
1743 Window parent;
1744 Window win = x11_window;
1745 Window *children;
1746 unsigned int num_children;
1747
1748 while (!status || text_prop.value == NULL)
1749 {
1750 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1751 &num_children))
1752 break;
1753 if (children)
1754 XFree((void *)children);
1755 if (parent == root || parent == 0)
1756 break;
1757
1758 win = parent;
1759 if (get_title)
1760 status = XGetWMName(x11_display, win, &text_prop);
1761 else
1762 status = XGetWMIconName(x11_display, win, &text_prop);
1763 }
1764 }
1765 if (status && text_prop.value != NULL)
1766 {
1767 retval = TRUE;
1768 if (!test_only)
1769 {
1770#ifdef FEAT_XFONTSET
1771 if (text_prop.encoding == XA_STRING)
1772 {
1773#endif
1774 if (get_title)
1775 oldtitle = vim_strsave((char_u *)text_prop.value);
1776 else
1777 oldicon = vim_strsave((char_u *)text_prop.value);
1778#ifdef FEAT_XFONTSET
1779 }
1780 else
1781 {
1782 char **cl;
1783 Status transform_status;
1784 int n = 0;
1785
1786 transform_status = XmbTextPropertyToTextList(x11_display,
1787 &text_prop,
1788 &cl, &n);
1789 if (transform_status >= Success && n > 0 && cl[0])
1790 {
1791 if (get_title)
1792 oldtitle = vim_strsave((char_u *) cl[0]);
1793 else
1794 oldicon = vim_strsave((char_u *) cl[0]);
1795 XFreeStringList(cl);
1796 }
1797 else
1798 {
1799 if (get_title)
1800 oldtitle = vim_strsave((char_u *)text_prop.value);
1801 else
1802 oldicon = vim_strsave((char_u *)text_prop.value);
1803 }
1804 }
1805#endif
1806 }
1807 XFree((void *)text_prop.value);
1808 }
1809 }
1810 return retval;
1811}
1812
1813/* Are Xutf8 functions available? Avoid error from old compilers. */
1814#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1815# if X_HAVE_UTF8_STRING
1816# define USE_UTF8_STRING
1817# endif
1818#endif
1819
1820/*
1821 * Set x11 Window Title
1822 *
1823 * get_x11_windis() must be called before this and have returned OK
1824 */
1825 static void
1826set_x11_title(title)
1827 char_u *title;
1828{
1829 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1830 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1831 * supported everywhere and STRING doesn't work for multi-byte titles.
1832 */
1833#ifdef USE_UTF8_STRING
1834 if (enc_utf8)
1835 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1836 NULL, NULL, 0, NULL, NULL, NULL);
1837 else
1838#endif
1839 {
1840#if XtSpecificationRelease >= 4
1841# ifdef FEAT_XFONTSET
1842 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1843 NULL, NULL, 0, NULL, NULL, NULL);
1844# else
1845 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001846 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001847
1848 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001849 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001850 XSetWMProperties(x11_display, x11_window, &text_prop,
1851 NULL, NULL, 0, NULL, NULL, NULL);
1852# endif
1853#else
1854 XStoreName(x11_display, x11_window, (char *)title);
1855#endif
1856 }
1857 XFlush(x11_display);
1858}
1859
1860/*
1861 * Set x11 Window icon
1862 *
1863 * get_x11_windis() must be called before this and have returned OK
1864 */
1865 static void
1866set_x11_icon(icon)
1867 char_u *icon;
1868{
1869 /* See above for comments about using X*SetWMProperties(). */
1870#ifdef USE_UTF8_STRING
1871 if (enc_utf8)
1872 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1873 NULL, 0, NULL, NULL, NULL);
1874 else
1875#endif
1876 {
1877#if XtSpecificationRelease >= 4
1878# ifdef FEAT_XFONTSET
1879 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1880 NULL, 0, NULL, NULL, NULL);
1881# else
1882 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001883 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001884
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001885 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
1887 NULL, 0, NULL, NULL, NULL);
1888# endif
1889#else
1890 XSetIconName(x11_display, x11_window, (char *)icon);
1891#endif
1892 }
1893 XFlush(x11_display);
1894}
1895
1896#else /* FEAT_X11 */
1897
1898/*ARGSUSED*/
1899 static int
1900get_x11_title(test_only)
1901 int test_only;
1902{
1903 return FALSE;
1904}
1905
1906 static int
1907get_x11_icon(test_only)
1908 int test_only;
1909{
1910 if (!test_only)
1911 {
1912 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1913 oldicon = T_NAME + 8;
1914 else
1915 oldicon = T_NAME;
1916 }
1917 return FALSE;
1918}
1919
1920#endif /* FEAT_X11 */
1921
1922 int
1923mch_can_restore_title()
1924{
1925 return get_x11_title(TRUE);
1926}
1927
1928 int
1929mch_can_restore_icon()
1930{
1931 return get_x11_icon(TRUE);
1932}
1933
1934/*
1935 * Set the window title and icon.
1936 */
1937 void
1938mch_settitle(title, icon)
1939 char_u *title;
1940 char_u *icon;
1941{
1942 int type = 0;
1943 static int recursive = 0;
1944
1945 if (T_NAME == NULL) /* no terminal name (yet) */
1946 return;
1947 if (title == NULL && icon == NULL) /* nothing to do */
1948 return;
1949
1950 /* When one of the X11 functions causes a deadly signal, we get here again
1951 * recursively. Avoid hanging then (something is probably locked). */
1952 if (recursive)
1953 return;
1954 ++recursive;
1955
1956 /*
1957 * if the window ID and the display is known, we may use X11 calls
1958 */
1959#ifdef FEAT_X11
1960 if (get_x11_windis() == OK)
1961 type = 1;
1962#else
1963# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
1964 if (gui.in_use)
1965 type = 1;
1966# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001967#endif
1968
1969 /*
1970 * Note: if "t_TS" is set, title is set with escape sequence rather
1971 * than x11 calls, because the x11 calls don't always work
1972 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001973 if ((type || *T_TS != NUL) && title != NULL)
1974 {
1975 if (oldtitle == NULL
1976#ifdef FEAT_GUI
1977 && !gui.in_use
1978#endif
1979 ) /* first call but not in GUI, save title */
1980 (void)get_x11_title(FALSE);
1981
1982 if (*T_TS != NUL) /* it's OK if t_fs is empty */
1983 term_settitle(title);
1984#ifdef FEAT_X11
1985 else
1986# ifdef FEAT_GUI_GTK
1987 if (!gui.in_use) /* don't do this if GTK+ is running */
1988# endif
1989 set_x11_title(title); /* x11 */
1990#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00001991#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001992 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
1993 else
1994 gui_mch_settitle(title, icon);
1995#endif
1996 did_set_title = TRUE;
1997 }
1998
1999 if ((type || *T_CIS != NUL) && icon != NULL)
2000 {
2001 if (oldicon == NULL
2002#ifdef FEAT_GUI
2003 && !gui.in_use
2004#endif
2005 ) /* first call, save icon */
2006 get_x11_icon(FALSE);
2007
2008 if (*T_CIS != NUL)
2009 {
2010 out_str(T_CIS); /* set icon start */
2011 out_str_nf(icon);
2012 out_str(T_CIE); /* set icon end */
2013 out_flush();
2014 }
2015#ifdef FEAT_X11
2016 else
2017# ifdef FEAT_GUI_GTK
2018 if (!gui.in_use) /* don't do this if GTK+ is running */
2019# endif
2020 set_x11_icon(icon); /* x11 */
2021#endif
2022 did_set_icon = TRUE;
2023 }
2024 --recursive;
2025}
2026
2027/*
2028 * Restore the window/icon title.
2029 * "which" is one of:
2030 * 1 only restore title
2031 * 2 only restore icon
2032 * 3 restore title and icon
2033 */
2034 void
2035mch_restore_title(which)
2036 int which;
2037{
2038 /* only restore the title or icon when it has been set */
2039 mch_settitle(((which & 1) && did_set_title) ?
2040 (oldtitle ? oldtitle : p_titleold) : NULL,
2041 ((which & 2) && did_set_icon) ? oldicon : NULL);
2042}
2043
2044#endif /* FEAT_TITLE */
2045
2046/*
2047 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002048 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002049 */
2050 int
2051vim_is_xterm(name)
2052 char_u *name;
2053{
2054 if (name == NULL)
2055 return FALSE;
2056 return (STRNICMP(name, "xterm", 5) == 0
2057 || STRNICMP(name, "nxterm", 6) == 0
2058 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002059 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002060 || STRNICMP(name, "rxvt", 4) == 0
2061 || STRCMP(name, "builtin_xterm") == 0);
2062}
2063
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002064#if defined(FEAT_MOUSE_XTERM) || defined(PROTO)
2065/*
2066 * Return TRUE if "name" appears to be that of a terminal
2067 * known to support the xterm-style mouse protocol.
2068 * Relies on term_is_xterm having been set to its correct value.
2069 */
2070 int
2071use_xterm_like_mouse(name)
2072 char_u *name;
2073{
2074 return (name != NULL
2075 && (term_is_xterm || STRNICMP(name, "screen", 6) == 0));
2076}
2077#endif
2078
Bram Moolenaar071d4272004-06-13 20:20:40 +00002079#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2080/*
2081 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2082 * Return 1 for "xterm".
2083 * Return 2 for "xterm2".
2084 */
2085 int
2086use_xterm_mouse()
2087{
2088 if (ttym_flags == TTYM_XTERM2)
2089 return 2;
2090 if (ttym_flags == TTYM_XTERM)
2091 return 1;
2092 return 0;
2093}
2094#endif
2095
2096 int
2097vim_is_iris(name)
2098 char_u *name;
2099{
2100 if (name == NULL)
2101 return FALSE;
2102 return (STRNICMP(name, "iris-ansi", 9) == 0
2103 || STRCMP(name, "builtin_iris-ansi") == 0);
2104}
2105
2106 int
2107vim_is_vt300(name)
2108 char_u *name;
2109{
2110 if (name == NULL)
2111 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002112 /* catch VT100 - VT5xx */
2113 return ((STRNICMP(name, "vt", 2) == 0
2114 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002115 || STRCMP(name, "builtin_vt320") == 0);
2116}
2117
2118/*
2119 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2120 * This should include all windowed terminal emulators.
2121 */
2122 int
2123vim_is_fastterm(name)
2124 char_u *name;
2125{
2126 if (name == NULL)
2127 return FALSE;
2128 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2129 return TRUE;
2130 return ( STRNICMP(name, "hpterm", 6) == 0
2131 || STRNICMP(name, "sun-cmd", 7) == 0
2132 || STRNICMP(name, "screen", 6) == 0
2133 || STRNICMP(name, "dtterm", 6) == 0);
2134}
2135
2136/*
2137 * Insert user name in s[len].
2138 * Return OK if a name found.
2139 */
2140 int
2141mch_get_user_name(s, len)
2142 char_u *s;
2143 int len;
2144{
2145#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002146 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002147 return OK;
2148#else
2149 return mch_get_uname(getuid(), s, len);
2150#endif
2151}
2152
2153/*
2154 * Insert user name for "uid" in s[len].
2155 * Return OK if a name found.
2156 */
2157 int
2158mch_get_uname(uid, s, len)
2159 uid_t uid;
2160 char_u *s;
2161 int len;
2162{
2163#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2164 struct passwd *pw;
2165
2166 if ((pw = getpwuid(uid)) != NULL
2167 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2168 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002169 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002170 return OK;
2171 }
2172#endif
2173 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2174 return FAIL; /* a number is not a name */
2175}
2176
2177/*
2178 * Insert host name is s[len].
2179 */
2180
2181#ifdef HAVE_SYS_UTSNAME_H
2182 void
2183mch_get_host_name(s, len)
2184 char_u *s;
2185 int len;
2186{
2187 struct utsname vutsname;
2188
2189 if (uname(&vutsname) < 0)
2190 *s = NUL;
2191 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002192 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002193}
2194#else /* HAVE_SYS_UTSNAME_H */
2195
2196# ifdef HAVE_SYS_SYSTEMINFO_H
2197# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2198# endif
2199
2200 void
2201mch_get_host_name(s, len)
2202 char_u *s;
2203 int len;
2204{
2205# ifdef VAXC
2206 vaxc$gethostname((char *)s, len);
2207# else
2208 gethostname((char *)s, len);
2209# endif
2210 s[len - 1] = NUL; /* make sure it's terminated */
2211}
2212#endif /* HAVE_SYS_UTSNAME_H */
2213
2214/*
2215 * return process ID
2216 */
2217 long
2218mch_get_pid()
2219{
2220 return (long)getpid();
2221}
2222
2223#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2224static char *strerror __ARGS((int));
2225
2226 static char *
2227strerror(err)
2228 int err;
2229{
2230 extern int sys_nerr;
2231 extern char *sys_errlist[];
2232 static char er[20];
2233
2234 if (err > 0 && err < sys_nerr)
2235 return (sys_errlist[err]);
2236 sprintf(er, "Error %d", err);
2237 return er;
2238}
2239#endif
2240
2241/*
2242 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2243 * Return OK for success, FAIL for failure.
2244 */
2245 int
2246mch_dirname(buf, len)
2247 char_u *buf;
2248 int len;
2249{
2250#if defined(USE_GETCWD)
2251 if (getcwd((char *)buf, len) == NULL)
2252 {
2253 STRCPY(buf, strerror(errno));
2254 return FAIL;
2255 }
2256 return OK;
2257#else
2258 return (getwd((char *)buf) != NULL ? OK : FAIL);
2259#endif
2260}
2261
2262#if defined(OS2) || defined(PROTO)
2263/*
2264 * Replace all slashes by backslashes.
2265 * When 'shellslash' set do it the other way around.
2266 */
2267 void
2268slash_adjust(p)
2269 char_u *p;
2270{
2271 while (*p)
2272 {
2273 if (*p == psepcN)
2274 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002275 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 }
2277}
2278#endif
2279
2280/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002281 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 *
2283 * return FAIL for failure, OK for success
2284 */
2285 int
2286mch_FullName(fname, buf, len, force)
2287 char_u *fname, *buf;
2288 int len;
2289 int force; /* also expand when already absolute path */
2290{
2291 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002292#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002293 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002294#endif
2295#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002296 int fd = -1;
2297 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002298#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002299 char_u olddir[MAXPATHL];
2300 char_u *p;
2301 int retval = OK;
Bram Moolenaarbf820722008-06-21 11:12:49 +00002302#ifdef __CYGWIN__
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00002303 char_u posix_fname[MAXPATHL]; /* Cygwin docs mention MAX_PATH, but
2304 it's not always defined */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002305#endif
2306
Bram Moolenaar38323e42007-03-06 19:22:53 +00002307#ifdef VMS
2308 fname = vms_fixfilename(fname);
2309#endif
2310
Bram Moolenaara2442432007-04-26 14:26:37 +00002311#ifdef __CYGWIN__
2312 /*
2313 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2314 */
Bram Moolenaarbf820722008-06-21 11:12:49 +00002315 cygwin_conv_to_posix_path(fname, posix_fname);
2316 fname = posix_fname;
Bram Moolenaara2442432007-04-26 14:26:37 +00002317#endif
2318
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319 /* expand it if forced or not an absolute path */
2320 if (force || !mch_isFullName(fname))
2321 {
2322 /*
2323 * If the file name has a path, change to that directory for a moment,
2324 * and then do the getwd() (and get back to where we were).
2325 * This will get the correct path name with "../" things.
2326 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002327#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328 only_drive = 0;
2329 if (((p = vim_strrchr(fname, '/')) != NULL)
2330 || ((p = vim_strrchr(fname, '\\')) != NULL)
2331 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002332#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002334#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002335 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002336#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002337 /*
2338 * Use fchdir() if possible, it's said to be faster and more
2339 * reliable. But on SunOS 4 it might not work. Check this by
2340 * doing a fchdir() right now.
2341 */
2342 if (!dont_fchdir)
2343 {
2344 fd = open(".", O_RDONLY | O_EXTRA, 0);
2345 if (fd >= 0 && fchdir(fd) < 0)
2346 {
2347 close(fd);
2348 fd = -1;
2349 dont_fchdir = TRUE; /* don't try again */
2350 }
2351 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002352#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002353
2354 /* Only change directory when we are sure we can return to where
2355 * we are now. After doing "su" chdir(".") might not work. */
2356 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002357#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002358 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002359#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 (mch_dirname(olddir, MAXPATHL) == FAIL
2361 || mch_chdir((char *)olddir) != 0))
2362 {
2363 p = NULL; /* can't get current dir: don't chdir */
2364 retval = FAIL;
2365 }
2366 else
2367 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002368#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369 /*
2370 * compensate for case where ':' from "D:" was the only
2371 * path separator detected in the file name; the _next_
2372 * character has to be removed, and then restored later.
2373 */
2374 if (only_drive)
2375 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002376#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377 /* The directory is copied into buf[], to be able to remove
2378 * the file name without changing it (could be a string in
2379 * read-only memory) */
2380 if (p - fname >= len)
2381 retval = FAIL;
2382 else
2383 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002384 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 if (mch_chdir((char *)buf))
2386 retval = FAIL;
2387 else
2388 fname = p + 1;
2389 *buf = NUL;
2390 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002391#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002392 if (only_drive)
2393 {
2394 p--;
2395 if (retval != FAIL)
2396 fname--;
2397 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002398#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002399 }
2400 }
2401 if (mch_dirname(buf, len) == FAIL)
2402 {
2403 retval = FAIL;
2404 *buf = NUL;
2405 }
2406 if (p != NULL)
2407 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002408#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002409 if (fd >= 0)
2410 {
2411 l = fchdir(fd);
2412 close(fd);
2413 }
2414 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002415#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002416 l = mch_chdir((char *)olddir);
2417 if (l != 0)
2418 EMSG(_(e_prev_dir));
2419 }
2420
2421 l = STRLEN(buf);
2422 if (l >= len)
2423 retval = FAIL;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002424#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002425 else
2426 {
2427 if (l > 0 && buf[l - 1] != '/' && *fname != NUL
2428 && STRCMP(fname, ".") != 0)
2429 STRCAT(buf, "/");
2430 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002431#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002432 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002433
Bram Moolenaar071d4272004-06-13 20:20:40 +00002434 /* Catch file names which are too long. */
2435 if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len)
2436 return FAIL;
2437
2438 /* Do not append ".", "/dir/." is equal to "/dir". */
2439 if (STRCMP(fname, ".") != 0)
2440 STRCAT(buf, fname);
2441
2442 return OK;
2443}
2444
2445/*
2446 * Return TRUE if "fname" does not depend on the current directory.
2447 */
2448 int
2449mch_isFullName(fname)
2450 char_u *fname;
2451{
2452#ifdef __EMX__
2453 return _fnisabs(fname);
2454#else
2455# ifdef VMS
2456 return ( fname[0] == '/' || fname[0] == '.' ||
2457 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2458 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2459 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2460# else
2461 return (*fname == '/' || *fname == '~');
2462# endif
2463#endif
2464}
2465
Bram Moolenaar24552be2005-12-10 20:17:30 +00002466#if defined(USE_FNAME_CASE) || defined(PROTO)
2467/*
2468 * Set the case of the file name, if it already exists. This will cause the
2469 * file name to remain exactly the same.
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00002470 * Only required for file systems where case is ignored and preserved.
Bram Moolenaar24552be2005-12-10 20:17:30 +00002471 */
2472/*ARGSUSED*/
2473 void
2474fname_case(name, len)
2475 char_u *name;
2476 int len; /* buffer size, only used when name gets longer */
2477{
2478 struct stat st;
2479 char_u *slash, *tail;
2480 DIR *dirp;
2481 struct dirent *dp;
2482
2483 if (lstat((char *)name, &st) >= 0)
2484 {
2485 /* Open the directory where the file is located. */
2486 slash = vim_strrchr(name, '/');
2487 if (slash == NULL)
2488 {
2489 dirp = opendir(".");
2490 tail = name;
2491 }
2492 else
2493 {
2494 *slash = NUL;
2495 dirp = opendir((char *)name);
2496 *slash = '/';
2497 tail = slash + 1;
2498 }
2499
2500 if (dirp != NULL)
2501 {
2502 while ((dp = readdir(dirp)) != NULL)
2503 {
2504 /* Only accept names that differ in case and are the same byte
2505 * length. TODO: accept different length name. */
2506 if (STRICMP(tail, dp->d_name) == 0
2507 && STRLEN(tail) == STRLEN(dp->d_name))
2508 {
2509 char_u newname[MAXPATHL + 1];
2510 struct stat st2;
2511
2512 /* Verify the inode is equal. */
2513 vim_strncpy(newname, name, MAXPATHL);
2514 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2515 MAXPATHL - (tail - name));
2516 if (lstat((char *)newname, &st2) >= 0
2517 && st.st_ino == st2.st_ino
2518 && st.st_dev == st2.st_dev)
2519 {
2520 STRCPY(tail, dp->d_name);
2521 break;
2522 }
2523 }
2524 }
2525
2526 closedir(dirp);
2527 }
2528 }
2529}
2530#endif
2531
Bram Moolenaar071d4272004-06-13 20:20:40 +00002532/*
2533 * Get file permissions for 'name'.
2534 * Returns -1 when it doesn't exist.
2535 */
2536 long
2537mch_getperm(name)
2538 char_u *name;
2539{
2540 struct stat statb;
2541
2542 /* Keep the #ifdef outside of stat(), it may be a macro. */
2543#ifdef VMS
2544 if (stat((char *)vms_fixfilename(name), &statb))
2545#else
2546 if (stat((char *)name, &statb))
2547#endif
2548 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002549#ifdef __INTERIX
2550 /* The top bit makes the value negative, which means the file doesn't
2551 * exist. Remove the bit, we don't use it. */
2552 return statb.st_mode & ~S_ADDACE;
2553#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002554 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002555#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002556}
2557
2558/*
2559 * set file permission for 'name' to 'perm'
2560 *
2561 * return FAIL for failure, OK otherwise
2562 */
2563 int
2564mch_setperm(name, perm)
2565 char_u *name;
2566 long perm;
2567{
2568 return (chmod((char *)
2569#ifdef VMS
2570 vms_fixfilename(name),
2571#else
2572 name,
2573#endif
2574 (mode_t)perm) == 0 ? OK : FAIL);
2575}
2576
2577#if defined(HAVE_ACL) || defined(PROTO)
2578# ifdef HAVE_SYS_ACL_H
2579# include <sys/acl.h>
2580# endif
2581# ifdef HAVE_SYS_ACCESS_H
2582# include <sys/access.h>
2583# endif
2584
2585# ifdef HAVE_SOLARIS_ACL
2586typedef struct vim_acl_solaris_T {
2587 int acl_cnt;
2588 aclent_t *acl_entry;
2589} vim_acl_solaris_T;
2590# endif
2591
Bram Moolenaar588ebeb2008-05-07 17:09:24 +00002592#if defined(HAVE_SELINUX) || defined(PROTO)
2593/*
2594 * Copy security info from "from_file" to "to_file".
2595 */
2596 void
2597mch_copy_sec(from_file, to_file)
2598 char_u *from_file;
2599 char_u *to_file;
2600{
2601 if (from_file == NULL)
2602 return;
2603
2604 if (selinux_enabled == -1)
2605 selinux_enabled = is_selinux_enabled();
2606
2607 if (selinux_enabled > 0)
2608 {
2609 security_context_t from_context = NULL;
2610 security_context_t to_context = NULL;
2611
2612 if (getfilecon((char *)from_file, &from_context) < 0)
2613 {
2614 /* If the filesystem doesn't support extended attributes,
2615 the original had no special security context and the
2616 target cannot have one either. */
2617 if (errno == EOPNOTSUPP)
2618 return;
2619
2620 MSG_PUTS(_("\nCould not get security context for "));
2621 msg_outtrans(from_file);
2622 msg_putchar('\n');
2623 return;
2624 }
2625 if (getfilecon((char *)to_file, &to_context) < 0)
2626 {
2627 MSG_PUTS(_("\nCould not get security context for "));
2628 msg_outtrans(to_file);
2629 msg_putchar('\n');
2630 freecon (from_context);
2631 return ;
2632 }
2633 if (strcmp(from_context, to_context) != 0)
2634 {
2635 if (setfilecon((char *)to_file, from_context) < 0)
2636 {
2637 MSG_PUTS(_("\nCould not set security context for "));
2638 msg_outtrans(to_file);
2639 msg_putchar('\n');
2640 }
2641 }
2642 freecon(to_context);
2643 freecon(from_context);
2644 }
2645}
2646#endif /* HAVE_SELINUX */
2647
Bram Moolenaar071d4272004-06-13 20:20:40 +00002648/*
2649 * Return a pointer to the ACL of file "fname" in allocated memory.
2650 * Return NULL if the ACL is not available for whatever reason.
2651 */
2652 vim_acl_T
2653mch_get_acl(fname)
2654 char_u *fname;
2655{
2656 vim_acl_T ret = NULL;
2657#ifdef HAVE_POSIX_ACL
2658 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2659#else
2660#ifdef HAVE_SOLARIS_ACL
2661 vim_acl_solaris_T *aclent;
2662
2663 aclent = malloc(sizeof(vim_acl_solaris_T));
2664 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2665 {
2666 free(aclent);
2667 return NULL;
2668 }
2669 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2670 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2671 {
2672 free(aclent->acl_entry);
2673 free(aclent);
2674 return NULL;
2675 }
2676 ret = (vim_acl_T)aclent;
2677#else
2678#if defined(HAVE_AIX_ACL)
2679 int aclsize;
2680 struct acl *aclent;
2681
2682 aclsize = sizeof(struct acl);
2683 aclent = malloc(aclsize);
2684 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2685 {
2686 if (errno == ENOSPC)
2687 {
2688 aclsize = aclent->acl_len;
2689 aclent = realloc(aclent, aclsize);
2690 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2691 {
2692 free(aclent);
2693 return NULL;
2694 }
2695 }
2696 else
2697 {
2698 free(aclent);
2699 return NULL;
2700 }
2701 }
2702 ret = (vim_acl_T)aclent;
2703#endif /* HAVE_AIX_ACL */
2704#endif /* HAVE_SOLARIS_ACL */
2705#endif /* HAVE_POSIX_ACL */
2706 return ret;
2707}
2708
2709/*
2710 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2711 */
2712 void
2713mch_set_acl(fname, aclent)
2714 char_u *fname;
2715 vim_acl_T aclent;
2716{
2717 if (aclent == NULL)
2718 return;
2719#ifdef HAVE_POSIX_ACL
2720 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2721#else
2722#ifdef HAVE_SOLARIS_ACL
2723 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2724 ((vim_acl_solaris_T *)aclent)->acl_entry);
2725#else
2726#ifdef HAVE_AIX_ACL
2727 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2728#endif /* HAVE_AIX_ACL */
2729#endif /* HAVE_SOLARIS_ACL */
2730#endif /* HAVE_POSIX_ACL */
2731}
2732
2733 void
2734mch_free_acl(aclent)
2735 vim_acl_T aclent;
2736{
2737 if (aclent == NULL)
2738 return;
2739#ifdef HAVE_POSIX_ACL
2740 acl_free((acl_t)aclent);
2741#else
2742#ifdef HAVE_SOLARIS_ACL
2743 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2744 free(aclent);
2745#else
2746#ifdef HAVE_AIX_ACL
2747 free(aclent);
2748#endif /* HAVE_AIX_ACL */
2749#endif /* HAVE_SOLARIS_ACL */
2750#endif /* HAVE_POSIX_ACL */
2751}
2752#endif
2753
2754/*
2755 * Set hidden flag for "name".
2756 */
2757/* ARGSUSED */
2758 void
2759mch_hide(name)
2760 char_u *name;
2761{
2762 /* can't hide a file */
2763}
2764
2765/*
2766 * return TRUE if "name" is a directory
2767 * return FALSE if "name" is not a directory
2768 * return FALSE for error
2769 */
2770 int
2771mch_isdir(name)
2772 char_u *name;
2773{
2774 struct stat statb;
2775
2776 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2777 return FALSE;
2778 if (stat((char *)name, &statb))
2779 return FALSE;
2780#ifdef _POSIX_SOURCE
2781 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2782#else
2783 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2784#endif
2785}
2786
Bram Moolenaar071d4272004-06-13 20:20:40 +00002787static int executable_file __ARGS((char_u *name));
2788
2789/*
2790 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2791 */
2792 static int
2793executable_file(name)
2794 char_u *name;
2795{
2796 struct stat st;
2797
2798 if (stat((char *)name, &st))
2799 return 0;
2800 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2801}
2802
2803/*
2804 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2805 * Return -1 if unknown.
2806 */
2807 int
2808mch_can_exe(name)
2809 char_u *name;
2810{
2811 char_u *buf;
2812 char_u *p, *e;
2813 int retval;
2814
2815 /* If it's an absolute or relative path don't need to use $PATH. */
2816 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2817 || (name[1] == '.' && name[2] == '/'))))
2818 return executable_file(name);
2819
2820 p = (char_u *)getenv("PATH");
2821 if (p == NULL || *p == NUL)
2822 return -1;
2823 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2824 if (buf == NULL)
2825 return -1;
2826
2827 /*
2828 * Walk through all entries in $PATH to check if "name" exists there and
2829 * is an executable file.
2830 */
2831 for (;;)
2832 {
2833 e = (char_u *)strchr((char *)p, ':');
2834 if (e == NULL)
2835 e = p + STRLEN(p);
2836 if (e - p <= 1) /* empty entry means current dir */
2837 STRCPY(buf, "./");
2838 else
2839 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002840 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002841 add_pathsep(buf);
2842 }
2843 STRCAT(buf, name);
2844 retval = executable_file(buf);
2845 if (retval == 1)
2846 break;
2847
2848 if (*e != ':')
2849 break;
2850 p = e + 1;
2851 }
2852
2853 vim_free(buf);
2854 return retval;
2855}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002856
2857/*
2858 * Check what "name" is:
2859 * NODE_NORMAL: file or directory (or doesn't exist)
2860 * NODE_WRITABLE: writable device, socket, fifo, etc.
2861 * NODE_OTHER: non-writable things
2862 */
2863 int
2864mch_nodetype(name)
2865 char_u *name;
2866{
2867 struct stat st;
2868
2869 if (stat((char *)name, &st))
2870 return NODE_NORMAL;
2871 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2872 return NODE_NORMAL;
2873#ifndef OS2
2874 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2875 return NODE_OTHER;
2876#endif
2877 /* Everything else is writable? */
2878 return NODE_WRITABLE;
2879}
2880
2881 void
2882mch_early_init()
2883{
2884#ifdef HAVE_CHECK_STACK_GROWTH
2885 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002886
Bram Moolenaar071d4272004-06-13 20:20:40 +00002887 check_stack_growth((char *)&i);
2888
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002889# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002890 get_stack_limit();
2891# endif
2892
2893#endif
2894
2895 /*
2896 * Setup an alternative stack for signals. Helps to catch signals when
2897 * running out of stack space.
2898 * Use of sigaltstack() is preferred, it's more portable.
2899 * Ignore any errors.
2900 */
2901#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2902 signal_stack = malloc(SIGSTKSZ);
2903 init_signal_stack();
2904#endif
2905}
2906
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002907#if defined(EXITFREE) || defined(PROTO)
2908 void
2909mch_free_mem()
2910{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002911# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2912 if (clip_star.owned)
2913 clip_lose_selection(&clip_star);
2914 if (clip_plus.owned)
2915 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002916# endif
Bram Moolenaare8208012008-06-20 09:59:25 +00002917# if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002918 if (xterm_Shell != (Widget)0)
2919 XtDestroyWidget(xterm_Shell);
Bram Moolenaare8208012008-06-20 09:59:25 +00002920# ifndef LESSTIF_VERSION
2921 /* Lesstif crashes here, lose some memory */
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002922 if (xterm_dpy != NULL)
2923 XtCloseDisplay(xterm_dpy);
2924 if (app_context != (XtAppContext)NULL)
Bram Moolenaare8208012008-06-20 09:59:25 +00002925 {
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002926 XtDestroyApplicationContext(app_context);
Bram Moolenaare8208012008-06-20 09:59:25 +00002927# ifdef FEAT_X11
2928 x11_display = NULL; /* freed by XtDestroyApplicationContext() */
2929# endif
2930 }
2931# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002932# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002933# ifdef FEAT_X11
Bram Moolenaare8208012008-06-20 09:59:25 +00002934 if (x11_display != NULL
2935# ifdef FEAT_XCLIPBOARD
2936 && x11_display != xterm_dpy
2937# endif
2938 )
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002939 XCloseDisplay(x11_display);
2940# endif
2941# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2942 vim_free(signal_stack);
2943 signal_stack = NULL;
2944# endif
2945# ifdef FEAT_TITLE
2946 vim_free(oldtitle);
2947 vim_free(oldicon);
2948# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002949}
2950#endif
2951
Bram Moolenaar071d4272004-06-13 20:20:40 +00002952static void exit_scroll __ARGS((void));
2953
2954/*
2955 * Output a newline when exiting.
2956 * Make sure the newline goes to the same stream as the text.
2957 */
2958 static void
2959exit_scroll()
2960{
Bram Moolenaardf177f62005-02-22 08:39:57 +00002961 if (silent_mode)
2962 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002963 if (newline_on_exit || msg_didout)
2964 {
2965 if (msg_use_printf())
2966 {
2967 if (info_message)
2968 mch_msg("\n");
2969 else
2970 mch_errmsg("\r\n");
2971 }
2972 else
2973 out_char('\n');
2974 }
2975 else
2976 {
2977 restore_cterm_colors(); /* get original colors back */
2978 msg_clr_eos_force(); /* clear the rest of the display */
2979 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
2980 }
2981}
2982
2983 void
2984mch_exit(r)
2985 int r;
2986{
2987 exiting = TRUE;
2988
2989#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
2990 x11_export_final_selection();
2991#endif
2992
2993#ifdef FEAT_GUI
2994 if (!gui.in_use)
2995#endif
2996 {
2997 settmode(TMODE_COOK);
2998#ifdef FEAT_TITLE
2999 mch_restore_title(3); /* restore xterm title and icon name */
3000#endif
3001 /*
3002 * When t_ti is not empty but it doesn't cause swapping terminal
3003 * pages, need to output a newline when msg_didout is set. But when
3004 * t_ti does swap pages it should not go to the shell page. Do this
3005 * before stoptermcap().
3006 */
3007 if (swapping_screen() && !newline_on_exit)
3008 exit_scroll();
3009
3010 /* Stop termcap: May need to check for T_CRV response, which
3011 * requires RAW mode. */
3012 stoptermcap();
3013
3014 /*
3015 * A newline is only required after a message in the alternate screen.
3016 * This is set to TRUE by wait_return().
3017 */
3018 if (!swapping_screen() || newline_on_exit)
3019 exit_scroll();
3020
3021 /* Cursor may have been switched off without calling starttermcap()
3022 * when doing "vim -u vimrc" and vimrc contains ":q". */
3023 if (full_screen)
3024 cursor_on();
3025 }
3026 out_flush();
3027 ml_close_all(TRUE); /* remove all memfiles */
3028 may_core_dump();
3029#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003030 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003031 gui_exit(r);
3032#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003033
Bram Moolenaar56718732006-03-15 22:53:57 +00003034#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00003035 mac_conv_cleanup();
3036#endif
3037
Bram Moolenaar071d4272004-06-13 20:20:40 +00003038#ifdef __QNX__
3039 /* A core dump won't be created if the signal handler
3040 * doesn't return, so we can't call exit() */
3041 if (deadly_signal != 0)
3042 return;
3043#endif
3044
Bram Moolenaar009b2592004-10-24 19:18:58 +00003045#ifdef FEAT_NETBEANS_INTG
3046 if (usingNetbeans)
3047 netbeans_send_disconnect();
3048#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00003049
3050#ifdef EXITFREE
3051 free_all_mem();
3052#endif
3053
Bram Moolenaar071d4272004-06-13 20:20:40 +00003054 exit(r);
3055}
3056
3057 static void
3058may_core_dump()
3059{
3060 if (deadly_signal != 0)
3061 {
3062 signal(deadly_signal, SIG_DFL);
3063 kill(getpid(), deadly_signal); /* Die using the signal we caught */
3064 }
3065}
3066
3067#ifndef VMS
3068
3069 void
3070mch_settmode(tmode)
3071 int tmode;
3072{
3073 static int first = TRUE;
3074
3075 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3076#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3077 /*
3078 * for "new" tty systems
3079 */
3080# ifdef HAVE_TERMIOS_H
3081 static struct termios told;
3082 struct termios tnew;
3083# else
3084 static struct termio told;
3085 struct termio tnew;
3086# endif
3087
3088 if (first)
3089 {
3090 first = FALSE;
3091# if defined(HAVE_TERMIOS_H)
3092 tcgetattr(read_cmd_fd, &told);
3093# else
3094 ioctl(read_cmd_fd, TCGETA, &told);
3095# endif
3096 }
3097
3098 tnew = told;
3099 if (tmode == TMODE_RAW)
3100 {
3101 /*
3102 * ~ICRNL enables typing ^V^M
3103 */
3104 tnew.c_iflag &= ~ICRNL;
3105 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
3106# if defined(IEXTEN) && !defined(__MINT__)
3107 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
3108 /* but it breaks function keys on MINT */
3109# endif
3110 );
3111# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
3112 tnew.c_oflag &= ~ONLCR;
3113# endif
3114 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3115 tnew.c_cc[VTIME] = 0; /* don't wait */
3116 }
3117 else if (tmode == TMODE_SLEEP)
3118 tnew.c_lflag &= ~(ECHO);
3119
3120# if defined(HAVE_TERMIOS_H)
3121 {
3122 int n = 10;
3123
3124 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3125 * few times. */
3126 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3127 && errno == EINTR && n > 0)
3128 --n;
3129 }
3130# else
3131 ioctl(read_cmd_fd, TCSETA, &tnew);
3132# endif
3133
3134#else
3135
3136 /*
3137 * for "old" tty systems
3138 */
3139# ifndef TIOCSETN
3140# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3141# endif
3142 static struct sgttyb ttybold;
3143 struct sgttyb ttybnew;
3144
3145 if (first)
3146 {
3147 first = FALSE;
3148 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3149 }
3150
3151 ttybnew = ttybold;
3152 if (tmode == TMODE_RAW)
3153 {
3154 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3155 ttybnew.sg_flags |= RAW;
3156 }
3157 else if (tmode == TMODE_SLEEP)
3158 ttybnew.sg_flags &= ~(ECHO);
3159 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3160#endif
3161 curr_tmode = tmode;
3162}
3163
3164/*
3165 * Try to get the code for "t_kb" from the stty setting
3166 *
3167 * Even if termcap claims a backspace key, the user's setting *should*
3168 * prevail. stty knows more about reality than termcap does, and if
3169 * somebody's usual erase key is DEL (which, for most BSD users, it will
3170 * be), they're going to get really annoyed if their erase key starts
3171 * doing forward deletes for no reason. (Eric Fischer)
3172 */
3173 void
3174get_stty()
3175{
3176 char_u buf[2];
3177 char_u *p;
3178
3179 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3180#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3181 /* for "new" tty systems */
3182# ifdef HAVE_TERMIOS_H
3183 struct termios keys;
3184# else
3185 struct termio keys;
3186# endif
3187
3188# if defined(HAVE_TERMIOS_H)
3189 if (tcgetattr(read_cmd_fd, &keys) != -1)
3190# else
3191 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3192# endif
3193 {
3194 buf[0] = keys.c_cc[VERASE];
3195 intr_char = keys.c_cc[VINTR];
3196#else
3197 /* for "old" tty systems */
3198 struct sgttyb keys;
3199
3200 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3201 {
3202 buf[0] = keys.sg_erase;
3203 intr_char = keys.sg_kill;
3204#endif
3205 buf[1] = NUL;
3206 add_termcode((char_u *)"kb", buf, FALSE);
3207
3208 /*
3209 * If <BS> and <DEL> are now the same, redefine <DEL>.
3210 */
3211 p = find_termcode((char_u *)"kD");
3212 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3213 do_fixdel(NULL);
3214 }
3215#if 0
3216 } /* to keep cindent happy */
3217#endif
3218}
3219
3220#endif /* VMS */
3221
3222#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3223/*
3224 * Set mouse clicks on or off.
3225 */
3226 void
3227mch_setmouse(on)
3228 int on;
3229{
3230 static int ison = FALSE;
3231 int xterm_mouse_vers;
3232
3233 if (on == ison) /* return quickly if nothing to do */
3234 return;
3235
3236 xterm_mouse_vers = use_xterm_mouse();
3237 if (xterm_mouse_vers > 0)
3238 {
3239 if (on) /* enable mouse events, use mouse tracking if available */
3240 out_str_nf((char_u *)
3241 (xterm_mouse_vers > 1
3242 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3243 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3244 else /* disable mouse events, could probably always send the same */
3245 out_str_nf((char_u *)
3246 (xterm_mouse_vers > 1
3247 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3248 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3249 ison = on;
3250 }
3251
3252# ifdef FEAT_MOUSE_DEC
3253 else if (ttym_flags == TTYM_DEC)
3254 {
3255 if (on) /* enable mouse events */
3256 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3257 else /* disable mouse events */
3258 out_str_nf((char_u *)"\033['z");
3259 ison = on;
3260 }
3261# endif
3262
3263# ifdef FEAT_MOUSE_GPM
3264 else
3265 {
3266 if (on)
3267 {
3268 if (gpm_open())
3269 ison = TRUE;
3270 }
3271 else
3272 {
3273 gpm_close();
3274 ison = FALSE;
3275 }
3276 }
3277# endif
3278
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003279# ifdef FEAT_SYSMOUSE
3280 else
3281 {
3282 if (on)
3283 {
3284 if (sysmouse_open() == OK)
3285 ison = TRUE;
3286 }
3287 else
3288 {
3289 sysmouse_close();
3290 ison = FALSE;
3291 }
3292 }
3293# endif
3294
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295# ifdef FEAT_MOUSE_JSB
3296 else
3297 {
3298 if (on)
3299 {
3300 /* D - Enable Mouse up/down messages
3301 * L - Enable Left Button Reporting
3302 * M - Enable Middle Button Reporting
3303 * R - Enable Right Button Reporting
3304 * K - Enable SHIFT and CTRL key Reporting
3305 * + - Enable Advanced messaging of mouse moves and up/down messages
3306 * Q - Quiet No Ack
3307 * # - Numeric value of mouse pointer required
3308 * 0 = Multiview 2000 cursor, used as standard
3309 * 1 = Windows Arrow
3310 * 2 = Windows I Beam
3311 * 3 = Windows Hour Glass
3312 * 4 = Windows Cross Hair
3313 * 5 = Windows UP Arrow
3314 */
3315#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3316 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3317 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3318#else
3319 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3320 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3321#endif
3322 ison = TRUE;
3323 }
3324 else
3325 {
3326 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3327 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3328 ison = FALSE;
3329 }
3330 }
3331# endif
3332# ifdef FEAT_MOUSE_PTERM
3333 else
3334 {
3335 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3336 if (on)
3337 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3338 else
3339 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3340 ison = on;
3341 }
3342# endif
3343}
3344
3345/*
3346 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3347 */
3348 void
3349check_mouse_termcode()
3350{
3351# ifdef FEAT_MOUSE_XTERM
3352 if (use_xterm_mouse()
3353# ifdef FEAT_GUI
3354 && !gui.in_use
3355# endif
3356 )
3357 {
3358 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003359 ? IF_EB("\233M", CSI_STR "M")
3360 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003361 if (*p_mouse != NUL)
3362 {
3363 /* force mouse off and maybe on to send possibly new mouse
3364 * activation sequence to the xterm, with(out) drag tracing. */
3365 mch_setmouse(FALSE);
3366 setmouse();
3367 }
3368 }
3369 else
3370 del_mouse_termcode(KS_MOUSE);
3371# endif
3372
3373# ifdef FEAT_MOUSE_GPM
3374 if (!use_xterm_mouse()
3375# ifdef FEAT_GUI
3376 && !gui.in_use
3377# endif
3378 )
3379 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3380# endif
3381
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00003382# ifdef FEAT_SYSMOUSE
3383 if (!use_xterm_mouse()
3384# ifdef FEAT_GUI
3385 && !gui.in_use
3386# endif
3387 )
3388 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MS", ESC_STR "MS"));
3389# endif
3390
Bram Moolenaar071d4272004-06-13 20:20:40 +00003391# ifdef FEAT_MOUSE_JSB
3392 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3393 if (!use_xterm_mouse()
3394# ifdef FEAT_GUI
3395 && !gui.in_use
3396# endif
3397 )
3398 set_mouse_termcode(KS_JSBTERM_MOUSE,
3399 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3400 else
3401 del_mouse_termcode(KS_JSBTERM_MOUSE);
3402# endif
3403
3404# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003405 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003406 * define it in the GUI or when using an xterm. */
3407 if (!use_xterm_mouse()
3408# ifdef FEAT_GUI
3409 && !gui.in_use
3410# endif
3411 )
3412 set_mouse_termcode(KS_NETTERM_MOUSE,
3413 (char_u *)IF_EB("\033}", ESC_STR "}"));
3414 else
3415 del_mouse_termcode(KS_NETTERM_MOUSE);
3416# endif
3417
3418# ifdef FEAT_MOUSE_DEC
3419 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3420 if (!use_xterm_mouse()
3421# ifdef FEAT_GUI
3422 && !gui.in_use
3423# endif
3424 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003425 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3426 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003427 else
3428 del_mouse_termcode(KS_DEC_MOUSE);
3429# endif
3430# ifdef FEAT_MOUSE_PTERM
3431 /* same as the dec mouse */
3432 if (!use_xterm_mouse()
3433# ifdef FEAT_GUI
3434 && !gui.in_use
3435# endif
3436 )
3437 set_mouse_termcode(KS_PTERM_MOUSE,
3438 (char_u *) IF_EB("\033[", ESC_STR "["));
3439 else
3440 del_mouse_termcode(KS_PTERM_MOUSE);
3441# endif
3442}
3443#endif
3444
3445/*
3446 * set screen mode, always fails.
3447 */
3448/* ARGSUSED */
3449 int
3450mch_screenmode(arg)
3451 char_u *arg;
3452{
3453 EMSG(_(e_screenmode));
3454 return FAIL;
3455}
3456
3457#ifndef VMS
3458
3459/*
3460 * Try to get the current window size:
3461 * 1. with an ioctl(), most accurate method
3462 * 2. from the environment variables LINES and COLUMNS
3463 * 3. from the termcap
3464 * 4. keep using the old values
3465 * Return OK when size could be determined, FAIL otherwise.
3466 */
3467 int
3468mch_get_shellsize()
3469{
3470 long rows = 0;
3471 long columns = 0;
3472 char_u *p;
3473
3474 /*
3475 * For OS/2 use _scrsize().
3476 */
3477# ifdef __EMX__
3478 {
3479 int s[2];
3480
3481 _scrsize(s);
3482 columns = s[0];
3483 rows = s[1];
3484 }
3485# endif
3486
3487 /*
3488 * 1. try using an ioctl. It is the most accurate method.
3489 *
3490 * Try using TIOCGWINSZ first, some systems that have it also define
3491 * TIOCGSIZE but don't have a struct ttysize.
3492 */
3493# ifdef TIOCGWINSZ
3494 {
3495 struct winsize ws;
3496 int fd = 1;
3497
3498 /* When stdout is not a tty, use stdin for the ioctl(). */
3499 if (!isatty(fd) && isatty(read_cmd_fd))
3500 fd = read_cmd_fd;
3501 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3502 {
3503 columns = ws.ws_col;
3504 rows = ws.ws_row;
3505 }
3506 }
3507# else /* TIOCGWINSZ */
3508# ifdef TIOCGSIZE
3509 {
3510 struct ttysize ts;
3511 int fd = 1;
3512
3513 /* When stdout is not a tty, use stdin for the ioctl(). */
3514 if (!isatty(fd) && isatty(read_cmd_fd))
3515 fd = read_cmd_fd;
3516 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3517 {
3518 columns = ts.ts_cols;
3519 rows = ts.ts_lines;
3520 }
3521 }
3522# endif /* TIOCGSIZE */
3523# endif /* TIOCGWINSZ */
3524
3525 /*
3526 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003527 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3528 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003529 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003530 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531 {
3532 if ((p = (char_u *)getenv("LINES")))
3533 rows = atoi((char *)p);
3534 if ((p = (char_u *)getenv("COLUMNS")))
3535 columns = atoi((char *)p);
3536 }
3537
3538#ifdef HAVE_TGETENT
3539 /*
3540 * 3. try reading "co" and "li" entries from termcap
3541 */
3542 if (columns == 0 || rows == 0)
3543 getlinecol(&columns, &rows);
3544#endif
3545
3546 /*
3547 * 4. If everything fails, use the old values
3548 */
3549 if (columns <= 0 || rows <= 0)
3550 return FAIL;
3551
3552 Rows = rows;
3553 Columns = columns;
3554 return OK;
3555}
3556
3557/*
3558 * Try to set the window size to Rows and Columns.
3559 */
3560 void
3561mch_set_shellsize()
3562{
3563 if (*T_CWS)
3564 {
3565 /*
3566 * NOTE: if you get an error here that term_set_winsize() is
3567 * undefined, check the output of configure. It could probably not
3568 * find a ncurses, termcap or termlib library.
3569 */
3570 term_set_winsize((int)Rows, (int)Columns);
3571 out_flush();
3572 screen_start(); /* don't know where cursor is now */
3573 }
3574}
3575
3576#endif /* VMS */
3577
3578/*
3579 * Rows and/or Columns has changed.
3580 */
3581 void
3582mch_new_shellsize()
3583{
3584 /* Nothing to do. */
3585}
3586
Bram Moolenaardf177f62005-02-22 08:39:57 +00003587#ifndef USE_SYSTEM
3588static void append_ga_line __ARGS((garray_T *gap));
3589
3590/*
3591 * Append the text in "gap" below the cursor line and clear "gap".
3592 */
3593 static void
3594append_ga_line(gap)
3595 garray_T *gap;
3596{
3597 /* Remove trailing CR. */
3598 if (gap->ga_len > 0
3599 && !curbuf->b_p_bin
3600 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3601 --gap->ga_len;
3602 ga_append(gap, NUL);
3603 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3604 gap->ga_len = 0;
3605}
3606#endif
3607
Bram Moolenaar071d4272004-06-13 20:20:40 +00003608 int
3609mch_call_shell(cmd, options)
3610 char_u *cmd;
3611 int options; /* SHELL_*, see vim.h */
3612{
3613#ifdef VMS
3614 char *ifn = NULL;
3615 char *ofn = NULL;
3616#endif
3617 int tmode = cur_tmode;
3618#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3619 int x;
3620# ifndef __EMX__
3621 char_u *newcmd; /* only needed for unix */
3622# else
3623 /*
3624 * Set the preferred shell in the EMXSHELL environment variable (but
3625 * only if it is different from what is already in the environment).
3626 * Emx then takes care of whether to use "/c" or "-c" in an
3627 * intelligent way. Simply pass the whole thing to emx's system() call.
3628 * Emx also starts an interactive shell if system() is passed an empty
3629 * string.
3630 */
3631 char_u *p, *old;
3632
3633 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3634 {
3635 /* should check HAVE_SETENV, but I know we don't have it. */
3636 p = alloc(10 + strlen(p_sh));
3637 if (p)
3638 {
3639 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3640 putenv((char *)p); /* don't free the pointer! */
3641 }
3642 }
3643# endif
3644
3645 out_flush();
3646
3647 if (options & SHELL_COOKED)
3648 settmode(TMODE_COOK); /* set to normal mode */
3649
3650# ifdef __EMX__
3651 if (cmd == NULL)
3652 x = system(""); /* this starts an interactive shell in emx */
3653 else
3654 x = system((char *)cmd);
3655 /* system() returns -1 when error occurs in starting shell */
3656 if (x == -1 && !emsg_silent)
3657 {
3658 MSG_PUTS(_("\nCannot execute shell "));
3659 msg_outtrans(p_sh);
3660 msg_putchar('\n');
3661 }
3662# else /* not __EMX__ */
3663 if (cmd == NULL)
3664 x = system((char *)p_sh);
3665 else
3666 {
3667# ifdef VMS
3668 if (ofn = strchr((char *)cmd, '>'))
3669 *ofn++ = '\0';
3670 if (ifn = strchr((char *)cmd, '<'))
3671 {
3672 char *p;
3673
3674 *ifn++ = '\0';
3675 p = strchr(ifn,' '); /* chop off any trailing spaces */
3676 if (p)
3677 *p = '\0';
3678 }
3679 if (ofn)
3680 x = vms_sys((char *)cmd, ofn, ifn);
3681 else
3682 x = system((char *)cmd);
3683# else
3684 newcmd = lalloc(STRLEN(p_sh)
3685 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3686 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3687 if (newcmd == NULL)
3688 x = 0;
3689 else
3690 {
3691 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3692 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3693 (char *)p_shcf,
3694 (char *)cmd);
3695 x = system((char *)newcmd);
3696 vim_free(newcmd);
3697 }
3698# endif
3699 }
3700# ifdef VMS
3701 x = vms_sys_status(x);
3702# endif
3703 if (emsg_silent)
3704 ;
3705 else if (x == 127)
3706 MSG_PUTS(_("\nCannot execute shell sh\n"));
3707# endif /* __EMX__ */
3708 else if (x && !(options & SHELL_SILENT))
3709 {
3710 MSG_PUTS(_("\nshell returned "));
3711 msg_outnum((long)x);
3712 msg_putchar('\n');
3713 }
3714
3715 if (tmode == TMODE_RAW)
3716 settmode(TMODE_RAW); /* set to raw mode */
3717# ifdef FEAT_TITLE
3718 resettitle();
3719# endif
3720 return x;
3721
3722#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3723
Bram Moolenaardf177f62005-02-22 08:39:57 +00003724# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3725 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003726
3727 char_u *newcmd = NULL;
3728 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003729 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003730 pid_t wait_pid = 0;
3731# ifdef HAVE_UNION_WAIT
3732 union wait status;
3733# else
3734 int status = -1;
3735# endif
3736 int retval = -1;
3737 char **argv = NULL;
3738 int argc;
3739 int i;
3740 char_u *p;
3741 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003742 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003743# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003744 int pty_slave_fd = -1;
3745 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003746# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003747 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003748 int fd_fromshell[2];
3749 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003750# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003752# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753 static char envbuf_Rows[20];
3754 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003756 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003757
3758 out_flush();
3759 if (options & SHELL_COOKED)
3760 settmode(TMODE_COOK); /* set to normal mode */
3761
Bram Moolenaar071d4272004-06-13 20:20:40 +00003762 newcmd = vim_strsave(p_sh);
3763 if (newcmd == NULL) /* out of memory */
3764 goto error;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003765
3766 /*
3767 * Do this loop twice:
3768 * 1: find number of arguments
3769 * 2: separate them and build argv[]
3770 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771 for (i = 0; i < 2; ++i)
3772 {
3773 p = newcmd;
3774 inquote = FALSE;
3775 argc = 0;
3776 for (;;)
3777 {
3778 if (i == 1)
3779 argv[argc] = (char *)p;
3780 ++argc;
3781 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3782 {
3783 if (*p == '"')
3784 inquote = !inquote;
3785 ++p;
3786 }
3787 if (*p == NUL)
3788 break;
3789 if (i == 1)
3790 *p++ = NUL;
3791 p = skipwhite(p);
3792 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003793 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794 {
3795 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3796 if (argv == NULL) /* out of memory */
3797 goto error;
3798 }
3799 }
3800 if (cmd != NULL)
3801 {
3802 if (extra_shell_arg != NULL)
3803 argv[argc++] = (char *)extra_shell_arg;
3804 argv[argc++] = (char *)p_shcf;
3805 argv[argc++] = (char *)cmd;
3806 }
3807 argv[argc] = NULL;
3808
Bram Moolenaar071d4272004-06-13 20:20:40 +00003809 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003810 * For the GUI, when writing the output into the buffer and when reading
3811 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3812 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003813 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003814 if ((options & (SHELL_READ|SHELL_WRITE))
3815# ifdef FEAT_GUI
3816 || (gui.in_use && show_shell_mess)
3817# endif
3818 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003820# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003821 /*
3822 * Try to open a master pty.
3823 * If this works, open the slave pty.
3824 * If the slave can't be opened, close the master pty.
3825 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003826 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003827 {
3828 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3829 if (pty_master_fd >= 0 && ((pty_slave_fd =
3830 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3831 {
3832 close(pty_master_fd);
3833 pty_master_fd = -1;
3834 }
3835 }
3836 /*
3837 * If not opening a pty or it didn't work, try using pipes.
3838 */
3839 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003840# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003841 {
3842 pipe_error = (pipe(fd_toshell) < 0);
3843 if (!pipe_error) /* pipe create OK */
3844 {
3845 pipe_error = (pipe(fd_fromshell) < 0);
3846 if (pipe_error) /* pipe create failed */
3847 {
3848 close(fd_toshell[0]);
3849 close(fd_toshell[1]);
3850 }
3851 }
3852 if (pipe_error)
3853 {
3854 MSG_PUTS(_("\nCannot create pipes\n"));
3855 out_flush();
3856 }
3857 }
3858 }
3859
3860 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003861 {
3862# ifdef __BEOS__
3863 beos_cleanup_read_thread();
3864# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003865
Bram Moolenaar071d4272004-06-13 20:20:40 +00003866 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3867 {
3868 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003869 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003870# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003871 || (gui.in_use && show_shell_mess)
3872# endif
3873 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003874 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003875# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003876 if (pty_master_fd >= 0) /* close the pseudo tty */
3877 {
3878 close(pty_master_fd);
3879 close(pty_slave_fd);
3880 }
3881 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003882# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003883 {
3884 close(fd_toshell[0]);
3885 close(fd_toshell[1]);
3886 close(fd_fromshell[0]);
3887 close(fd_fromshell[1]);
3888 }
3889 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003890 }
3891 else if (pid == 0) /* child */
3892 {
3893 reset_signals(); /* handle signals normally */
3894
3895 if (!show_shell_mess || (options & SHELL_EXPAND))
3896 {
3897 int fd;
3898
3899 /*
3900 * Don't want to show any message from the shell. Can't just
3901 * close stdout and stderr though, because some systems will
3902 * break if you try to write to them after that, so we must
3903 * use dup() to replace them with something else -- webb
3904 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3905 * waiting for input.
3906 */
3907 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3908 fclose(stdin);
3909 fclose(stdout);
3910 fclose(stderr);
3911
3912 /*
3913 * If any of these open()'s and dup()'s fail, we just continue
3914 * anyway. It's not fatal, and on most systems it will make
3915 * no difference at all. On a few it will cause the execvp()
3916 * to exit with a non-zero status even when the completion
3917 * could be done, which is nothing too serious. If the open()
3918 * or dup() failed we'd just do the same thing ourselves
3919 * anyway -- webb
3920 */
3921 if (fd >= 0)
3922 {
3923 dup(fd); /* To replace stdin (file descriptor 0) */
3924 dup(fd); /* To replace stdout (file descriptor 1) */
3925 dup(fd); /* To replace stderr (file descriptor 2) */
3926
3927 /* Don't need this now that we've duplicated it */
3928 close(fd);
3929 }
3930 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003931 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003932# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003933 || gui.in_use
3934# endif
3935 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003936 {
3937
Bram Moolenaardf177f62005-02-22 08:39:57 +00003938# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003939 /* Create our own process group, so that the child and all its
3940 * children can be kill()ed. Don't do this when using pipes,
3941 * because stdin is not a tty, we would loose /dev/tty. */
3942 if (p_stmp)
3943 (void)setsid();
Bram Moolenaardf177f62005-02-22 08:39:57 +00003944# endif
3945# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003946 if (pty_slave_fd >= 0)
3947 {
3948 /* push stream discipline modules */
3949 if (options & SHELL_COOKED)
3950 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003951# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003952 /* Try to become controlling tty (probably doesn't work,
3953 * unless run by root) */
3954 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003956 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003957# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003958 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003959# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003960 setenv("TERM", "dumb", 1);
3961 sprintf((char *)envbuf, "%ld", Rows);
3962 setenv("ROWS", (char *)envbuf, 1);
3963 sprintf((char *)envbuf, "%ld", Rows);
3964 setenv("LINES", (char *)envbuf, 1);
3965 sprintf((char *)envbuf, "%ld", Columns);
3966 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003967# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003968 /*
3969 * Putenv does not copy the string, it has to remain valid.
3970 * Use a static array to avoid loosing allocated memory.
3971 */
3972 putenv("TERM=dumb");
3973 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
3974 putenv(envbuf_Rows);
3975 sprintf(envbuf_Rows, "LINES=%ld", Rows);
3976 putenv(envbuf_Rows);
3977 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
3978 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003979# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003980
Bram Moolenaara5792f52005-11-23 21:25:05 +00003981 /*
3982 * stderr is only redirected when using the GUI, so that a
3983 * program like gpg can still access the terminal to get a
3984 * passphrase using stderr.
3985 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003986# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003987 if (pty_master_fd >= 0)
3988 {
3989 close(pty_master_fd); /* close master side of pty */
3990
3991 /* set up stdin/stdout/stderr for the child */
3992 close(0);
3993 dup(pty_slave_fd);
3994 close(1);
3995 dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003996 if (gui.in_use)
3997 {
3998 close(2);
3999 dup(pty_slave_fd);
4000 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004001
4002 close(pty_slave_fd); /* has been dupped, close it now */
4003 }
4004 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004005# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004006 {
4007 /* set up stdin for the child */
4008 close(fd_toshell[1]);
4009 close(0);
4010 dup(fd_toshell[0]);
4011 close(fd_toshell[0]);
4012
4013 /* set up stdout for the child */
4014 close(fd_fromshell[0]);
4015 close(1);
4016 dup(fd_fromshell[1]);
4017 close(fd_fromshell[1]);
4018
Bram Moolenaara5792f52005-11-23 21:25:05 +00004019# ifdef FEAT_GUI
4020 if (gui.in_use)
4021 {
4022 /* set up stderr for the child */
4023 close(2);
4024 dup(1);
4025 }
4026# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027 }
4028 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004029
Bram Moolenaar071d4272004-06-13 20:20:40 +00004030 /*
4031 * There is no type cast for the argv, because the type may be
4032 * different on different machines. This may cause a warning
4033 * message with strict compilers, don't worry about it.
4034 * Call _exit() instead of exit() to avoid closing the connection
4035 * to the X server (esp. with GTK, which uses atexit()).
4036 */
4037 execvp(argv[0], argv);
4038 _exit(EXEC_FAILED); /* exec failed, return failure code */
4039 }
4040 else /* parent */
4041 {
4042 /*
4043 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004044 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004045 */
4046 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004047 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004048
4049 /*
4050 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004051 * This is also used to pipe stdin/stdout to/from the external
4052 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004053 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004054 if ((options & (SHELL_READ|SHELL_WRITE))
4055# ifdef FEAT_GUI
4056 || (gui.in_use && show_shell_mess)
4057# endif
4058 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004059 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004060# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004061 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00004062# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004063 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004064# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004065 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
4066 int ta_len = 0; /* valid bytes in ta_buf[] */
4067 int len;
4068 int p_more_save;
4069 int old_State;
4070 int c;
4071 int toshell_fd;
4072 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004073 garray_T ga;
4074 int noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004075
Bram Moolenaardf177f62005-02-22 08:39:57 +00004076# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00004077 if (pty_master_fd >= 0)
4078 {
4079 close(pty_slave_fd); /* close slave side of pty */
4080 fromshell_fd = pty_master_fd;
4081 toshell_fd = dup(pty_master_fd);
4082 }
4083 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00004084# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085 {
4086 close(fd_toshell[0]);
4087 close(fd_fromshell[1]);
4088 toshell_fd = fd_toshell[1];
4089 fromshell_fd = fd_fromshell[0];
4090 }
4091
4092 /*
4093 * Write to the child if there are typed characters.
4094 * Read from the child if there are characters available.
4095 * Repeat the reading a few times if more characters are
4096 * available. Need to check for typed keys now and then, but
4097 * not too often (delays when no chars are available).
4098 * This loop is quit if no characters can be read from the pty
4099 * (WaitForChar detected special condition), or there are no
4100 * characters available and the child has exited.
4101 * Only check if the child has exited when there is no more
4102 * output. The child may exit before all the output has
4103 * been printed.
4104 *
4105 * Currently this busy loops!
4106 * This can probably dead-lock when the write blocks!
4107 */
4108 p_more_save = p_more;
4109 p_more = FALSE;
4110 old_State = State;
4111 State = EXTERNCMD; /* don't redraw at window resize */
4112
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004113 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004114 {
4115 /* Fork a process that will write the lines to the
4116 * external program. */
4117 if ((wpid = fork()) == -1)
4118 {
4119 MSG_PUTS(_("\nCannot fork\n"));
4120 }
4121 else if (wpid == 0)
4122 {
4123 linenr_T lnum = curbuf->b_op_start.lnum;
4124 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004125 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004126 char_u *s;
4127 size_t l;
4128
4129 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00004130 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004131 for (;;)
4132 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004133 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004134 if (l == 0)
4135 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00004136 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004137 /* NL -> NUL translation */
4138 len = write(toshell_fd, "", (size_t)1);
4139 else
4140 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004141 s = vim_strchr(lp + written, NL);
4142 len = write(toshell_fd, (char *)lp + written,
4143 s == NULL ? l : s - (lp + written));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004144 }
4145 if (len == l)
4146 {
4147 /* Finished a line, add a NL, unless this line
4148 * should not have one. */
4149 if (lnum != curbuf->b_op_end.lnum
4150 || !curbuf->b_p_bin
4151 || (lnum != write_no_eol_lnum
4152 && (lnum !=
4153 curbuf->b_ml.ml_line_count
4154 || curbuf->b_p_eol)))
4155 write(toshell_fd, "\n", (size_t)1);
4156 ++lnum;
4157 if (lnum > curbuf->b_op_end.lnum)
4158 {
4159 /* finished all the lines, close pipe */
4160 close(toshell_fd);
4161 toshell_fd = -1;
4162 break;
4163 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004164 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004165 written = 0;
4166 }
4167 else if (len > 0)
4168 written += len;
4169 }
4170 _exit(0);
4171 }
4172 else
4173 {
4174 close(toshell_fd);
4175 toshell_fd = -1;
4176 }
4177 }
4178
4179 if (options & SHELL_READ)
4180 ga_init2(&ga, 1, BUFLEN);
4181
4182 noread_cnt = 0;
4183
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184 for (;;)
4185 {
4186 /*
4187 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004188 * if there are any.
4189 * Don't do this if we are expanding wild cards (would eat
4190 * typeahead).
4191 * Don't do this when filtering and terminal is in cooked
4192 * mode, the shell command will handle the I/O. Avoids
4193 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004194 * Don't get characters when the child has already
4195 * finished (wait_pid == 0).
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004196 * Don't get extra characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004197 * Don't read characters unless we didn't get output for a
4198 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004199 */
4200 len = 0;
4201 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004202 && ((options &
4203 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4204 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
4205#ifdef FEAT_GUI
4206 || gui.in_use
4207#endif
4208 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004209 && wait_pid == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004210 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00004211 || (noread_cnt > 4
4212 && (len = ui_inchar(ta_buf,
4213 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004214 {
4215 /*
4216 * For pipes:
4217 * Check for CTRL-C: send interrupt signal to child.
4218 * Check for CTRL-D: EOF, close pipe to child.
4219 */
4220 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4221 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004222# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004223 /*
4224 * Send SIGINT to the child's group or all
4225 * processes in our group.
4226 */
4227 if (ta_buf[ta_len] == Ctrl_C
4228 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004229 {
4230# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004231 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004232# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004233 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004234# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004235 if (wpid > 0)
4236 kill(wpid, SIGINT);
4237 }
4238# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004239 if (pty_master_fd < 0 && toshell_fd >= 0
4240 && ta_buf[ta_len] == Ctrl_D)
4241 {
4242 close(toshell_fd);
4243 toshell_fd = -1;
4244 }
4245 }
4246
4247 /* replace K_BS by <BS> and K_DEL by <DEL> */
4248 for (i = ta_len; i < ta_len + len; ++i)
4249 {
4250 if (ta_buf[i] == CSI && len - i > 2)
4251 {
4252 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4253 if (c == K_DEL || c == K_KDEL || c == K_BS)
4254 {
4255 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4256 (size_t)(len - i - 2));
4257 if (c == K_DEL || c == K_KDEL)
4258 ta_buf[i] = DEL;
4259 else
4260 ta_buf[i] = Ctrl_H;
4261 len -= 2;
4262 }
4263 }
4264 else if (ta_buf[i] == '\r')
4265 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004266# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004267 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004268 i += (*mb_ptr2len)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004269# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004270 }
4271
4272 /*
4273 * For pipes: echo the typed characters.
4274 * For a pty this does not seem to work.
4275 */
4276 if (pty_master_fd < 0)
4277 {
4278 for (i = ta_len; i < ta_len + len; ++i)
4279 {
4280 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4281 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004282# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004283 else if (has_mbyte)
4284 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004285 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004286
4287 msg_outtrans_len(ta_buf + i, l);
4288 i += l - 1;
4289 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004290# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004291 else
4292 msg_outtrans_len(ta_buf + i, 1);
4293 }
4294 windgoto(msg_row, msg_col);
4295 out_flush();
4296 }
4297
4298 ta_len += len;
4299
4300 /*
4301 * Write the characters to the child, unless EOF has
4302 * been typed for pipes. Write one character at a
4303 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004304 * When writing buffer lines, drop the typed
4305 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004306 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004307 if (options & SHELL_WRITE)
4308 ta_len = 0;
4309 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004310 {
4311 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4312 if (len > 0)
4313 {
4314 ta_len -= len;
4315 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004316 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004317 }
4318 }
4319 }
4320
Bram Moolenaardf177f62005-02-22 08:39:57 +00004321 if (got_int)
4322 {
4323 /* CTRL-C sends a signal to the child, we ignore it
4324 * ourselves */
4325# ifdef HAVE_SETSID
4326 kill(-pid, SIGINT);
4327# else
4328 kill(0, SIGINT);
4329# endif
4330 if (wpid > 0)
4331 kill(wpid, SIGINT);
4332 got_int = FALSE;
4333 }
4334
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335 /*
4336 * Check if the child has any characters to be printed.
4337 * Read them and write them to our window. Repeat this as
4338 * long as there is something to do, avoid the 10ms wait
4339 * for mch_inchar(), or sending typeahead characters to
4340 * the external process.
4341 * TODO: This should handle escape sequences, compatible
4342 * to some terminal (vt52?).
4343 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004344 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4346 {
4347 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004348# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004349 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004350# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004351 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004352# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004353 );
4354 if (len <= 0) /* end of file or error */
4355 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004356
4357 noread_cnt = 0;
4358 if (options & SHELL_READ)
4359 {
4360 /* Do NUL -> NL translation, append NL separated
4361 * lines to the current buffer. */
4362 for (i = 0; i < len; ++i)
4363 {
4364 if (buffer[i] == NL)
4365 append_ga_line(&ga);
4366 else if (buffer[i] == NUL)
4367 ga_append(&ga, NL);
4368 else
4369 ga_append(&ga, buffer[i]);
4370 }
4371 }
4372# ifdef FEAT_MBYTE
4373 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374 {
4375 int l;
4376
Bram Moolenaardf177f62005-02-22 08:39:57 +00004377 len += buffer_off;
4378 buffer[len] = NUL;
4379
Bram Moolenaar071d4272004-06-13 20:20:40 +00004380 /* Check if the last character in buffer[] is
4381 * incomplete, keep these bytes for the next
4382 * round. */
4383 for (p = buffer; p < buffer + len; p += l)
4384 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004385 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004386 if (l == 0)
4387 l = 1; /* NUL byte? */
4388 else if (MB_BYTE2LEN(*p) != l)
4389 break;
4390 }
4391 if (p == buffer) /* no complete character */
4392 {
4393 /* avoid getting stuck at an illegal byte */
4394 if (len >= 12)
4395 ++p;
4396 else
4397 {
4398 buffer_off = len;
4399 continue;
4400 }
4401 }
4402 c = *p;
4403 *p = NUL;
4404 msg_puts(buffer);
4405 if (p < buffer + len)
4406 {
4407 *p = c;
4408 buffer_off = (buffer + len) - p;
4409 mch_memmove(buffer, p, buffer_off);
4410 continue;
4411 }
4412 buffer_off = 0;
4413 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004414# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004415 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004416 {
4417 buffer[len] = NUL;
4418 msg_puts(buffer);
4419 }
4420
4421 windgoto(msg_row, msg_col);
4422 cursor_on();
4423 out_flush();
4424 if (got_int)
4425 break;
4426 }
4427
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004428 /* If we already detected the child has finished break the
4429 * loop now. */
4430 if (wait_pid == pid)
4431 break;
4432
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433 /*
4434 * Check if the child still exists, before checking for
4435 * typed characters (otherwise we would loose typeahead).
4436 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004437# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004438 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004439# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004440 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004441# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004442 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4443 || (wait_pid == pid && WIFEXITED(status)))
4444 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004445 /* Don't break the loop yet, try reading more
4446 * characters from "fromshell_fd" first. When using
4447 * pipes there might still be something to read and
4448 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004450 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004451 else
4452 wait_pid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004453 }
4454finished:
4455 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004456 if (options & SHELL_READ)
4457 {
4458 if (ga.ga_len > 0)
4459 {
4460 append_ga_line(&ga);
4461 /* remember that the NL was missing */
4462 write_no_eol_lnum = curwin->w_cursor.lnum;
4463 }
4464 else
4465 write_no_eol_lnum = 0;
4466 ga_clear(&ga);
4467 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004468
Bram Moolenaar071d4272004-06-13 20:20:40 +00004469 /*
4470 * Give all typeahead that wasn't used back to ui_inchar().
4471 */
4472 if (ta_len)
4473 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004474 State = old_State;
4475 if (toshell_fd >= 0)
4476 close(toshell_fd);
4477 close(fromshell_fd);
4478 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004479
4480 /*
4481 * Wait until our child has exited.
4482 * Ignore wait() returning pids of other children and returning
4483 * because of some signal like SIGWINCH.
4484 * Don't wait if wait_pid was already set above, indicating the
4485 * child already exited.
4486 */
4487 while (wait_pid != pid)
4488 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004489# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004490 /* Ugly hack: when compiled with Python threads are probably
4491 * used, in which case wait() sometimes hangs for no obvious
4492 * reason. Use waitpid() instead and loop (like the GUI). */
4493# ifdef __NeXT__
4494 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4495# else
4496 wait_pid = waitpid(pid, &status, WNOHANG);
4497# endif
4498 if (wait_pid == 0)
4499 {
4500 /* Wait for 1/100 sec before trying again. */
4501 mch_delay(10L, TRUE);
4502 continue;
4503 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004504# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004505 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004506# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004507 if (wait_pid <= 0
4508# ifdef ECHILD
4509 && errno == ECHILD
4510# endif
4511 )
4512 break;
4513 }
4514
Bram Moolenaardf177f62005-02-22 08:39:57 +00004515 /* Make sure the child that writes to the external program is
4516 * dead. */
4517 if (wpid > 0)
4518 kill(wpid, SIGKILL);
4519
Bram Moolenaar071d4272004-06-13 20:20:40 +00004520 /*
4521 * Set to raw mode right now, otherwise a CTRL-C after
4522 * catch_signals() will kill Vim.
4523 */
4524 if (tmode == TMODE_RAW)
4525 settmode(TMODE_RAW);
4526 did_settmode = TRUE;
4527 set_signals();
4528
4529 if (WIFEXITED(status))
4530 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004531 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532 retval = WEXITSTATUS(status);
4533 if (retval && !emsg_silent)
4534 {
4535 if (retval == EXEC_FAILED)
4536 {
4537 MSG_PUTS(_("\nCannot execute shell "));
4538 msg_outtrans(p_sh);
4539 msg_putchar('\n');
4540 }
4541 else if (!(options & SHELL_SILENT))
4542 {
4543 MSG_PUTS(_("\nshell returned "));
4544 msg_outnum((long)retval);
4545 msg_putchar('\n');
4546 }
4547 }
4548 }
4549 else
4550 MSG_PUTS(_("\nCommand terminated\n"));
4551 }
4552 }
4553 vim_free(argv);
4554
4555error:
4556 if (!did_settmode)
4557 if (tmode == TMODE_RAW)
4558 settmode(TMODE_RAW); /* set to raw mode */
4559# ifdef FEAT_TITLE
4560 resettitle();
4561# endif
4562 vim_free(newcmd);
4563
4564 return retval;
4565
4566#endif /* USE_SYSTEM */
4567}
4568
4569/*
4570 * Check for CTRL-C typed by reading all available characters.
4571 * In cooked mode we should get SIGINT, no need to check.
4572 */
4573 void
4574mch_breakcheck()
4575{
4576 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4577 fill_input_buf(FALSE);
4578}
4579
4580/*
4581 * Wait "msec" msec until a character is available from the keyboard or from
4582 * inbuf[]. msec == -1 will block forever.
4583 * When a GUI is being used, this will never get called -- webb
4584 */
4585 static int
4586WaitForChar(msec)
4587 long msec;
4588{
4589#ifdef FEAT_MOUSE_GPM
4590 int gpm_process_wanted;
4591#endif
4592#ifdef FEAT_XCLIPBOARD
4593 int rest;
4594#endif
4595 int avail;
4596
4597 if (input_available()) /* something in inbuf[] */
4598 return 1;
4599
4600#if defined(FEAT_MOUSE_DEC)
4601 /* May need to query the mouse position. */
4602 if (WantQueryMouse)
4603 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004604 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4606 }
4607#endif
4608
4609 /*
4610 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4611 * events. This is a bit complicated, because they might both be defined.
4612 */
4613#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4614# ifdef FEAT_XCLIPBOARD
4615 rest = 0;
4616 if (do_xterm_trace())
4617 rest = msec;
4618# endif
4619 do
4620 {
4621# ifdef FEAT_XCLIPBOARD
4622 if (rest != 0)
4623 {
4624 msec = XT_TRACE_DELAY;
4625 if (rest >= 0 && rest < XT_TRACE_DELAY)
4626 msec = rest;
4627 if (rest >= 0)
4628 rest -= msec;
4629 }
4630# endif
4631# ifdef FEAT_MOUSE_GPM
4632 gpm_process_wanted = 0;
4633 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4634# else
4635 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4636# endif
4637 if (!avail)
4638 {
4639 if (input_available())
4640 return 1;
4641# ifdef FEAT_XCLIPBOARD
4642 if (rest == 0 || !do_xterm_trace())
4643# endif
4644 break;
4645 }
4646 }
4647 while (FALSE
4648# ifdef FEAT_MOUSE_GPM
4649 || (gpm_process_wanted && mch_gpm_process() == 0)
4650# endif
4651# ifdef FEAT_XCLIPBOARD
4652 || (!avail && rest != 0)
4653# endif
4654 );
4655
4656#else
4657 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4658#endif
4659 return avail;
4660}
4661
4662/*
4663 * Wait "msec" msec until a character is available from file descriptor "fd".
4664 * Time == -1 will block forever.
4665 * When a GUI is being used, this will not be used for input -- webb
4666 * Returns also, when a request from Sniff is waiting -- toni.
4667 * Or when a Linux GPM mouse event is waiting.
4668 */
4669/* ARGSUSED */
4670#if defined(__BEOS__)
4671 int
4672#else
4673 static int
4674#endif
4675RealWaitForChar(fd, msec, check_for_gpm)
4676 int fd;
4677 long msec;
4678 int *check_for_gpm;
4679{
4680 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004681#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004682 static int busy = FALSE;
4683
4684 /* May retry getting characters after an event was handled. */
4685# define MAY_LOOP
4686
4687# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4688 /* Remember at what time we started, so that we know how much longer we
4689 * should wait after being interrupted. */
4690# define USE_START_TV
4691 struct timeval start_tv;
4692
4693 if (msec > 0 && (
4694# ifdef FEAT_XCLIPBOARD
4695 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004696# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004697 ||
4698# endif
4699# endif
4700# ifdef USE_XSMP
4701 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004702# ifdef FEAT_MZSCHEME
4703 ||
4704# endif
4705# endif
4706# ifdef FEAT_MZSCHEME
4707 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004708# endif
4709 ))
4710 gettimeofday(&start_tv, NULL);
4711# endif
4712
4713 /* Handle being called recursively. This may happen for the session
4714 * manager stuff, it may save the file, which does a breakcheck. */
4715 if (busy)
4716 return 0;
4717#endif
4718
4719#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00004720 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721#endif
4722 {
4723#ifdef MAY_LOOP
4724 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004725# ifdef FEAT_MZSCHEME
4726 int mzquantum_used = FALSE;
4727# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004728#endif
4729#ifndef HAVE_SELECT
4730 struct pollfd fds[5];
4731 int nfd;
4732# ifdef FEAT_XCLIPBOARD
4733 int xterm_idx = -1;
4734# endif
4735# ifdef FEAT_MOUSE_GPM
4736 int gpm_idx = -1;
4737# endif
4738# ifdef USE_XSMP
4739 int xsmp_idx = -1;
4740# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004741 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004742
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004743# ifdef FEAT_MZSCHEME
4744 mzvim_check_threads();
4745 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4746 {
4747 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4748 mzquantum_used = TRUE;
4749 }
4750# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004751 fds[0].fd = fd;
4752 fds[0].events = POLLIN;
4753 nfd = 1;
4754
4755# ifdef FEAT_SNIFF
4756# define SNIFF_IDX 1
4757 if (want_sniff_request)
4758 {
4759 fds[SNIFF_IDX].fd = fd_from_sniff;
4760 fds[SNIFF_IDX].events = POLLIN;
4761 nfd++;
4762 }
4763# endif
4764# ifdef FEAT_XCLIPBOARD
4765 if (xterm_Shell != (Widget)0)
4766 {
4767 xterm_idx = nfd;
4768 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4769 fds[nfd].events = POLLIN;
4770 nfd++;
4771 }
4772# endif
4773# ifdef FEAT_MOUSE_GPM
4774 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4775 {
4776 gpm_idx = nfd;
4777 fds[nfd].fd = gpm_fd;
4778 fds[nfd].events = POLLIN;
4779 nfd++;
4780 }
4781# endif
4782# ifdef USE_XSMP
4783 if (xsmp_icefd != -1)
4784 {
4785 xsmp_idx = nfd;
4786 fds[nfd].fd = xsmp_icefd;
4787 fds[nfd].events = POLLIN;
4788 nfd++;
4789 }
4790# endif
4791
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004792 ret = poll(fds, nfd, towait);
4793# ifdef FEAT_MZSCHEME
4794 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00004795 /* MzThreads scheduling is required and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004796 finished = FALSE;
4797# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004798
4799# ifdef FEAT_SNIFF
4800 if (ret < 0)
4801 sniff_disconnect(1);
4802 else if (want_sniff_request)
4803 {
4804 if (fds[SNIFF_IDX].revents & POLLHUP)
4805 sniff_disconnect(1);
4806 if (fds[SNIFF_IDX].revents & POLLIN)
4807 sniff_request_waiting = 1;
4808 }
4809# endif
4810# ifdef FEAT_XCLIPBOARD
4811 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4812 {
4813 xterm_update(); /* Maybe we should hand out clipboard */
4814 if (--ret == 0 && !input_available())
4815 /* Try again */
4816 finished = FALSE;
4817 }
4818# endif
4819# ifdef FEAT_MOUSE_GPM
4820 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4821 {
4822 *check_for_gpm = 1;
4823 }
4824# endif
4825# ifdef USE_XSMP
4826 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4827 {
4828 if (fds[xsmp_idx].revents & POLLIN)
4829 {
4830 busy = TRUE;
4831 xsmp_handle_requests();
4832 busy = FALSE;
4833 }
4834 else if (fds[xsmp_idx].revents & POLLHUP)
4835 {
4836 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004837 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004838 xsmp_close();
4839 }
4840 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004841 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004842 }
4843# endif
4844
4845
4846#else /* HAVE_SELECT */
4847
4848 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004849 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004850 fd_set rfds, efds;
4851 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004852 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004853
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004854# ifdef FEAT_MZSCHEME
4855 mzvim_check_threads();
4856 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4857 {
4858 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4859 mzquantum_used = TRUE;
4860 }
4861# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004862# ifdef __EMX__
4863 /* don't check for incoming chars if not in raw mode, because select()
4864 * always returns TRUE then (in some version of emx.dll) */
4865 if (curr_tmode != TMODE_RAW)
4866 return 0;
4867# endif
4868
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004869 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004870 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004871 tv.tv_sec = towait / 1000;
4872 tv.tv_usec = (towait % 1000) * (1000000/1000);
4873 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004874 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004875 else
4876 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004877
4878 /*
4879 * Select on ready for reading and exceptional condition (end of file).
4880 */
4881 FD_ZERO(&rfds); /* calls bzero() on a sun */
4882 FD_ZERO(&efds);
4883 FD_SET(fd, &rfds);
4884# if !defined(__QNX__) && !defined(__CYGWIN32__)
4885 /* For QNX select() always returns 1 if this is set. Why? */
4886 FD_SET(fd, &efds);
4887# endif
4888 maxfd = fd;
4889
4890# ifdef FEAT_SNIFF
4891 if (want_sniff_request)
4892 {
4893 FD_SET(fd_from_sniff, &rfds);
4894 FD_SET(fd_from_sniff, &efds);
4895 if (maxfd < fd_from_sniff)
4896 maxfd = fd_from_sniff;
4897 }
4898# endif
4899# ifdef FEAT_XCLIPBOARD
4900 if (xterm_Shell != (Widget)0)
4901 {
4902 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4903 if (maxfd < ConnectionNumber(xterm_dpy))
4904 maxfd = ConnectionNumber(xterm_dpy);
4905 }
4906# endif
4907# ifdef FEAT_MOUSE_GPM
4908 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4909 {
4910 FD_SET(gpm_fd, &rfds);
4911 FD_SET(gpm_fd, &efds);
4912 if (maxfd < gpm_fd)
4913 maxfd = gpm_fd;
4914 }
4915# endif
4916# ifdef USE_XSMP
4917 if (xsmp_icefd != -1)
4918 {
4919 FD_SET(xsmp_icefd, &rfds);
4920 FD_SET(xsmp_icefd, &efds);
4921 if (maxfd < xsmp_icefd)
4922 maxfd = xsmp_icefd;
4923 }
4924# endif
4925
4926# ifdef OLD_VMS
4927 /* Old VMS as v6.2 and older have broken select(). It waits more than
4928 * required. Should not be used */
4929 ret = 0;
4930# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004931 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4932# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00004933# ifdef __TANDEM
4934 if (ret == -1 && errno == ENOTSUP)
4935 {
4936 FD_ZERO(&rfds);
4937 FD_ZERO(&efds);
4938 ret = 0;
4939 }
4940#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004941# ifdef FEAT_MZSCHEME
4942 if (ret == 0 && mzquantum_used)
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00004943 /* loop if MzThreads must be scheduled and timeout occurred */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004944 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004945# endif
4946
4947# ifdef FEAT_SNIFF
4948 if (ret < 0 )
4949 sniff_disconnect(1);
4950 else if (ret > 0 && want_sniff_request)
4951 {
4952 if (FD_ISSET(fd_from_sniff, &efds))
4953 sniff_disconnect(1);
4954 if (FD_ISSET(fd_from_sniff, &rfds))
4955 sniff_request_waiting = 1;
4956 }
4957# endif
4958# ifdef FEAT_XCLIPBOARD
4959 if (ret > 0 && xterm_Shell != (Widget)0
4960 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4961 {
4962 xterm_update(); /* Maybe we should hand out clipboard */
4963 /* continue looping when we only got the X event and the input
4964 * buffer is empty */
4965 if (--ret == 0 && !input_available())
4966 {
4967 /* Try again */
4968 finished = FALSE;
4969 }
4970 }
4971# endif
4972# ifdef FEAT_MOUSE_GPM
4973 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4974 {
4975 if (FD_ISSET(gpm_fd, &efds))
4976 gpm_close();
4977 else if (FD_ISSET(gpm_fd, &rfds))
4978 *check_for_gpm = 1;
4979 }
4980# endif
4981# ifdef USE_XSMP
4982 if (ret > 0 && xsmp_icefd != -1)
4983 {
4984 if (FD_ISSET(xsmp_icefd, &efds))
4985 {
4986 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004987 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004988 xsmp_close();
4989 if (--ret == 0)
4990 finished = FALSE; /* keep going if event was only one */
4991 }
4992 else if (FD_ISSET(xsmp_icefd, &rfds))
4993 {
4994 busy = TRUE;
4995 xsmp_handle_requests();
4996 busy = FALSE;
4997 if (--ret == 0)
4998 finished = FALSE; /* keep going if event was only one */
4999 }
5000 }
5001# endif
5002
5003#endif /* HAVE_SELECT */
5004
5005#ifdef MAY_LOOP
5006 if (finished || msec == 0)
5007 break;
5008
5009 /* We're going to loop around again, find out for how long */
5010 if (msec > 0)
5011 {
5012# ifdef USE_START_TV
5013 struct timeval mtv;
5014
5015 /* Compute remaining wait time. */
5016 gettimeofday(&mtv, NULL);
5017 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
5018 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
5019# else
5020 /* Guess we got interrupted halfway. */
5021 msec = msec / 2;
5022# endif
5023 if (msec <= 0)
5024 break; /* waited long enough */
5025 }
5026#endif
5027 }
5028
5029 return (ret > 0);
5030}
5031
5032#ifndef VMS
5033
5034#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00005035/*
Bram Moolenaar02743632005-07-25 20:42:36 +00005036 * Expand a path into all matching files and/or directories. Handles "*",
5037 * "?", "[a-z]", "**", etc.
5038 * "path" has backslashes before chars that are not to be expanded.
5039 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005040 */
5041 int
5042mch_expandpath(gap, path, flags)
5043 garray_T *gap;
5044 char_u *path;
5045 int flags; /* EW_* flags */
5046{
Bram Moolenaar02743632005-07-25 20:42:36 +00005047 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005048}
5049#endif
5050
5051/*
5052 * mch_expand_wildcards() - this code does wild-card pattern matching using
5053 * the shell
5054 *
5055 * return OK for success, FAIL for error (you may lose some memory) and put
5056 * an error message in *file.
5057 *
5058 * num_pat is number of input patterns
5059 * pat is array of pointers to input patterns
5060 * num_file is pointer to number of matched file names
5061 * file is pointer to array of pointers to matched file names
5062 */
5063
5064#ifndef SEEK_SET
5065# define SEEK_SET 0
5066#endif
5067#ifndef SEEK_END
5068# define SEEK_END 2
5069#endif
5070
Bram Moolenaar5555acc2006-04-07 21:33:12 +00005071#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00005072
Bram Moolenaar071d4272004-06-13 20:20:40 +00005073/* ARGSUSED */
5074 int
5075mch_expand_wildcards(num_pat, pat, num_file, file, flags)
5076 int num_pat;
5077 char_u **pat;
5078 int *num_file;
5079 char_u ***file;
5080 int flags; /* EW_* flags */
5081{
5082 int i;
5083 size_t len;
5084 char_u *p;
5085 int dir;
5086#ifdef __EMX__
Bram Moolenaarc7247912008-01-13 12:54:11 +00005087 /*
5088 * This is the OS/2 implementation.
5089 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005090# define EXPL_ALLOC_INC 16
5091 char_u **expl_files;
5092 size_t files_alloced, files_free;
5093 char_u *buf;
5094 int has_wildcard;
5095
5096 *num_file = 0; /* default: no files found */
5097 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
5098 files_free = EXPL_ALLOC_INC; /* how much space is not used */
5099 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
5100 if (*file == NULL)
5101 return FAIL;
5102
5103 for (; num_pat > 0; num_pat--, pat++)
5104 {
5105 expl_files = NULL;
5106 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
5107 /* expand environment var or home dir */
5108 buf = expand_env_save(*pat);
5109 else
5110 buf = vim_strsave(*pat);
5111 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005112 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005113 if (has_wildcard) /* yes, so expand them */
5114 expl_files = (char_u **)_fnexplode(buf);
5115
5116 /*
5117 * return value of buf if no wildcards left,
5118 * OR if no match AND EW_NOTFOUND is set.
5119 */
5120 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
5121 || (expl_files == NULL && (flags & EW_NOTFOUND)))
5122 { /* simply save the current contents of *buf */
5123 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
5124 if (expl_files != NULL)
5125 {
5126 expl_files[0] = vim_strsave(buf);
5127 expl_files[1] = NULL;
5128 }
5129 }
5130 vim_free(buf);
5131
5132 /*
5133 * Count number of names resulting from expansion,
5134 * At the same time add a backslash to the end of names that happen to
5135 * be directories, and replace slashes with backslashes.
5136 */
5137 if (expl_files)
5138 {
5139 for (i = 0; (p = expl_files[i]) != NULL; i++)
5140 {
5141 dir = mch_isdir(p);
5142 /* If we don't want dirs and this is one, skip it */
5143 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5144 continue;
5145
Bram Moolenaara2031822006-03-07 22:29:51 +00005146 /* Skip files that are not executable if we check for that. */
5147 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
5148 continue;
5149
Bram Moolenaar071d4272004-06-13 20:20:40 +00005150 if (--files_free == 0)
5151 {
5152 /* need more room in table of pointers */
5153 files_alloced += EXPL_ALLOC_INC;
5154 *file = (char_u **)vim_realloc(*file,
5155 sizeof(char_u **) * files_alloced);
5156 if (*file == NULL)
5157 {
5158 EMSG(_(e_outofmem));
5159 *num_file = 0;
5160 return FAIL;
5161 }
5162 files_free = EXPL_ALLOC_INC;
5163 }
5164 slash_adjust(p);
5165 if (dir)
5166 {
5167 /* For a directory we add a '/', unless it's already
5168 * there. */
5169 len = STRLEN(p);
5170 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5171 {
5172 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005173 if (!after_pathsep((*file)[*num_file],
5174 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005175 {
5176 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005177 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005178 }
5179 }
5180 }
5181 else
5182 {
5183 (*file)[*num_file] = vim_strsave(p);
5184 }
5185
5186 /*
5187 * Error message already given by either alloc or vim_strsave.
5188 * Should return FAIL, but returning OK works also.
5189 */
5190 if ((*file)[*num_file] == NULL)
5191 break;
5192 (*num_file)++;
5193 }
5194 _fnexplodefree((char **)expl_files);
5195 }
5196 }
5197 return OK;
5198
5199#else /* __EMX__ */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005200 /*
5201 * This is the non-OS/2 implementation (really Unix).
5202 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005203 int j;
5204 char_u *tempname;
5205 char_u *command;
5206 FILE *fd;
5207 char_u *buffer;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005208#define STYLE_ECHO 0 /* use "echo", the default */
5209#define STYLE_GLOB 1 /* use "glob", for csh */
5210#define STYLE_VIMGLOB 2 /* use "vimglob", for Posix sh */
5211#define STYLE_PRINT 3 /* use "print -N", for zsh */
5212#define STYLE_BT 4 /* `cmd` expansion, execute the pattern
5213 * directly */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005214 int shell_style = STYLE_ECHO;
5215 int check_spaces;
5216 static int did_find_nul = FALSE;
5217 int ampersent = FALSE;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005218 /* vimglob() function to define for Posix shell */
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005219 static char *sh_vimglob_func = "vimglob() { while [ $# -ge 1 ]; do echo \"$1\"; shift; done }; vimglob >";
Bram Moolenaar071d4272004-06-13 20:20:40 +00005220
5221 *num_file = 0; /* default: no files found */
5222 *file = NULL;
5223
5224 /*
5225 * If there are no wildcards, just copy the names to allocated memory.
5226 * Saves a lot of time, because we don't have to start a new shell.
5227 */
5228 if (!have_wildcard(num_pat, pat))
5229 return save_patterns(num_pat, pat, num_file, file);
5230
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005231# ifdef HAVE_SANDBOX
5232 /* Don't allow any shell command in the sandbox. */
5233 if (sandbox != 0 && check_secure())
5234 return FAIL;
5235# endif
5236
Bram Moolenaar071d4272004-06-13 20:20:40 +00005237 /*
5238 * Don't allow the use of backticks in secure and restricted mode.
5239 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005240 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005241 for (i = 0; i < num_pat; ++i)
5242 if (vim_strchr(pat[i], '`') != NULL
5243 && (check_restricted() || check_secure()))
5244 return FAIL;
5245
5246 /*
5247 * get a name for the temp file
5248 */
5249 if ((tempname = vim_tempname('o')) == NULL)
5250 {
5251 EMSG(_(e_notmp));
5252 return FAIL;
5253 }
5254
5255 /*
5256 * Let the shell expand the patterns and write the result into the temp
Bram Moolenaarc7247912008-01-13 12:54:11 +00005257 * file.
5258 * STYLE_BT: NL separated
5259 * If expanding `cmd` execute it directly.
5260 * STYLE_GLOB: NUL separated
5261 * If we use *csh, "glob" will work better than "echo".
5262 * STYLE_PRINT: NL or NUL separated
5263 * If we use *zsh, "print -N" will work better than "glob".
5264 * STYLE_VIMGLOB: NL separated
5265 * If we use *sh*, we define "vimglob()".
5266 * STYLE_ECHO: space separated.
5267 * A shell we don't know, stay safe and use "echo".
Bram Moolenaar071d4272004-06-13 20:20:40 +00005268 */
5269 if (num_pat == 1 && *pat[0] == '`'
5270 && (len = STRLEN(pat[0])) > 2
5271 && *(pat[0] + len - 1) == '`')
5272 shell_style = STYLE_BT;
5273 else if ((len = STRLEN(p_sh)) >= 3)
5274 {
5275 if (STRCMP(p_sh + len - 3, "csh") == 0)
5276 shell_style = STYLE_GLOB;
5277 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5278 shell_style = STYLE_PRINT;
5279 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005280 if (shell_style == STYLE_ECHO && strstr((char *)gettail(p_sh),
5281 "sh") != NULL)
5282 shell_style = STYLE_VIMGLOB;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005283
Bram Moolenaarc7247912008-01-13 12:54:11 +00005284 /* Compute the length of the command. We need 2 extra bytes: for the
5285 * optional '&' and for the NUL.
5286 * Worst case: "unset nonomatch; print -N >" plus two is 29 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005287 len = STRLEN(tempname) + 29;
Bram Moolenaarc7247912008-01-13 12:54:11 +00005288 if (shell_style == STYLE_VIMGLOB)
5289 len += STRLEN(sh_vimglob_func);
5290
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005291 for (i = 0; i < num_pat; ++i)
5292 {
5293 /* Count the length of the patterns in the same way as they are put in
5294 * "command" below. */
5295#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005296 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005297#else
5298 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005299 for (j = 0; pat[i][j] != NUL; ++j)
5300 {
5301 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5302 ++len; /* may add a backslash */
5303 ++len;
5304 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005305#endif
5306 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005307 command = alloc(len);
5308 if (command == NULL)
5309 {
5310 /* out of memory */
5311 vim_free(tempname);
5312 return FAIL;
5313 }
5314
5315 /*
5316 * Build the shell command:
5317 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5318 * recognizes this).
5319 * - Add the shell command to print the expanded names.
5320 * - Add the temp file name.
5321 * - Add the file name patterns.
5322 */
5323 if (shell_style == STYLE_BT)
5324 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005325 /* change `command; command& ` to (command; command ) */
5326 STRCPY(command, "(");
5327 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005328 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005329 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005330 while (p > command && vim_iswhite(*p))
5331 --p;
5332 if (*p == '&') /* remove trailing '&' */
5333 {
5334 ampersent = TRUE;
5335 *p = ' ';
5336 }
5337 STRCAT(command, ">");
5338 }
5339 else
5340 {
5341 if (flags & EW_NOTFOUND)
5342 STRCPY(command, "set nonomatch; ");
5343 else
5344 STRCPY(command, "unset nonomatch; ");
5345 if (shell_style == STYLE_GLOB)
5346 STRCAT(command, "glob >");
5347 else if (shell_style == STYLE_PRINT)
5348 STRCAT(command, "print -N >");
Bram Moolenaarc7247912008-01-13 12:54:11 +00005349 else if (shell_style == STYLE_VIMGLOB)
5350 STRCAT(command, sh_vimglob_func);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005351 else
5352 STRCAT(command, "echo >");
5353 }
Bram Moolenaarc7247912008-01-13 12:54:11 +00005354
Bram Moolenaar071d4272004-06-13 20:20:40 +00005355 STRCAT(command, tempname);
Bram Moolenaarc7247912008-01-13 12:54:11 +00005356
Bram Moolenaar071d4272004-06-13 20:20:40 +00005357 if (shell_style != STYLE_BT)
5358 for (i = 0; i < num_pat; ++i)
5359 {
5360 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005361 * is started twice. Otherwise put a backslash before special
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005362 * characters, except inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005363#ifdef USE_SYSTEM
5364 STRCAT(command, " \"");
5365 STRCAT(command, pat[i]);
5366 STRCAT(command, "\"");
5367#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005368 int intick = FALSE;
5369
Bram Moolenaar071d4272004-06-13 20:20:40 +00005370 p = command + STRLEN(command);
5371 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005372 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005373 {
5374 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005375 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005376 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5377 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005378 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005379 * backslash inside backticks, before a special character
5380 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005381 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005382 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5383 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005384 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005385 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005386 }
5387 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005388 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005389 /* Put a backslash before a special character, but not
5390 * when inside ``. */
5391 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005392
5393 /* Copy one character. */
5394 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005395 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005396 *p = NUL;
5397#endif
5398 }
5399 if (flags & EW_SILENT)
5400 show_shell_mess = FALSE;
5401 if (ampersent)
Bram Moolenaarc7247912008-01-13 12:54:11 +00005402 STRCAT(command, "&"); /* put the '&' after the redirection */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005403
5404 /*
5405 * Using zsh -G: If a pattern has no matches, it is just deleted from
5406 * the argument list, otherwise zsh gives an error message and doesn't
5407 * expand any other pattern.
5408 */
5409 if (shell_style == STYLE_PRINT)
5410 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5411
5412 /*
5413 * If we use -f then shell variables set in .cshrc won't get expanded.
5414 * vi can do it, so we will too, but it is only necessary if there is a "$"
5415 * in one of the patterns, otherwise we can still use the fast option.
5416 */
5417 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5418 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5419
5420 /*
5421 * execute the shell command
5422 */
5423 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5424
5425 /* When running in the background, give it some time to create the temp
5426 * file, but don't wait for it to finish. */
5427 if (ampersent)
5428 mch_delay(10L, TRUE);
5429
5430 extra_shell_arg = NULL; /* cleanup */
5431 show_shell_mess = TRUE;
5432 vim_free(command);
5433
Bram Moolenaarc7247912008-01-13 12:54:11 +00005434 if (i != 0) /* mch_call_shell() failed */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005435 {
5436 mch_remove(tempname);
5437 vim_free(tempname);
5438 /*
5439 * With interactive completion, the error message is not printed.
5440 * However with USE_SYSTEM, I don't know how to turn off error messages
5441 * from the shell, so screen may still get messed up -- webb.
5442 */
5443#ifndef USE_SYSTEM
5444 if (!(flags & EW_SILENT))
5445#endif
5446 {
5447 redraw_later_clear(); /* probably messed up screen */
5448 msg_putchar('\n'); /* clear bottom line quickly */
5449 cmdline_row = Rows - 1; /* continue on last line */
5450#ifdef USE_SYSTEM
5451 if (!(flags & EW_SILENT))
5452#endif
5453 {
5454 MSG(_(e_wildexpand));
5455 msg_start(); /* don't overwrite this message */
5456 }
5457 }
5458 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5459 * EW_NOTFOUND is given */
5460 if (shell_style == STYLE_BT)
5461 return FAIL;
5462 goto notfound;
5463 }
5464
5465 /*
5466 * read the names from the file into memory
5467 */
5468 fd = fopen((char *)tempname, READBIN);
5469 if (fd == NULL)
5470 {
5471 /* Something went wrong, perhaps a file name with a special char. */
5472 if (!(flags & EW_SILENT))
5473 {
5474 MSG(_(e_wildexpand));
5475 msg_start(); /* don't overwrite this message */
5476 }
5477 vim_free(tempname);
5478 goto notfound;
5479 }
5480 fseek(fd, 0L, SEEK_END);
5481 len = ftell(fd); /* get size of temp file */
5482 fseek(fd, 0L, SEEK_SET);
5483 buffer = alloc(len + 1);
5484 if (buffer == NULL)
5485 {
5486 /* out of memory */
5487 mch_remove(tempname);
5488 vim_free(tempname);
5489 fclose(fd);
5490 return FAIL;
5491 }
5492 i = fread((char *)buffer, 1, len, fd);
5493 fclose(fd);
5494 mch_remove(tempname);
5495 if (i != len)
5496 {
5497 /* unexpected read error */
5498 EMSG2(_(e_notread), tempname);
5499 vim_free(tempname);
5500 vim_free(buffer);
5501 return FAIL;
5502 }
5503 vim_free(tempname);
5504
Bram Moolenaarc7247912008-01-13 12:54:11 +00005505# if defined(__CYGWIN__) || defined(__CYGWIN32__)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005506 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5507 p = buffer;
5508 for (i = 0; i < len; ++i)
5509 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5510 *p++ = buffer[i];
5511 len = p - buffer;
5512# endif
5513
5514
5515 /* file names are separated with Space */
5516 if (shell_style == STYLE_ECHO)
5517 {
5518 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5519 p = buffer;
5520 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5521 {
5522 while (*p != ' ' && *p != '\n')
5523 ++p;
5524 p = skipwhite(p); /* skip to next entry */
5525 }
5526 }
5527 /* file names are separated with NL */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005528 else if (shell_style == STYLE_BT || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005529 {
5530 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5531 p = buffer;
5532 for (i = 0; *p != NUL; ++i) /* count number of entries */
5533 {
5534 while (*p != '\n' && *p != NUL)
5535 ++p;
5536 if (*p != NUL)
5537 ++p;
5538 p = skipwhite(p); /* skip leading white space */
5539 }
5540 }
5541 /* file names are separated with NUL */
5542 else
5543 {
5544 /*
5545 * Some versions of zsh use spaces instead of NULs to separate
5546 * results. Only do this when there is no NUL before the end of the
5547 * buffer, otherwise we would never be able to use file names with
5548 * embedded spaces when zsh does use NULs.
5549 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5550 * don't check for spaces again.
5551 */
5552 check_spaces = FALSE;
5553 if (shell_style == STYLE_PRINT && !did_find_nul)
5554 {
5555 /* If there is a NUL, set did_find_nul, else set check_spaces */
5556 if (len && (int)STRLEN(buffer) < len - 1)
5557 did_find_nul = TRUE;
5558 else
5559 check_spaces = TRUE;
5560 }
5561
5562 /*
5563 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5564 * already is one, for STYLE_GLOB it needs to be added.
5565 */
5566 if (len && buffer[len - 1] == NUL)
5567 --len;
5568 else
5569 buffer[len] = NUL;
5570 i = 0;
5571 for (p = buffer; p < buffer + len; ++p)
5572 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5573 {
5574 ++i;
5575 *p = NUL;
5576 }
5577 if (len)
5578 ++i; /* count last entry */
5579 }
5580 if (i == 0)
5581 {
5582 /*
5583 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5584 * /bin/sh will happily expand it to nothing rather than returning an
5585 * error; and hey, it's good to check anyway -- webb.
5586 */
5587 vim_free(buffer);
5588 goto notfound;
5589 }
5590 *num_file = i;
5591 *file = (char_u **)alloc(sizeof(char_u *) * i);
5592 if (*file == NULL)
5593 {
5594 /* out of memory */
5595 vim_free(buffer);
5596 return FAIL;
5597 }
5598
5599 /*
5600 * Isolate the individual file names.
5601 */
5602 p = buffer;
5603 for (i = 0; i < *num_file; ++i)
5604 {
5605 (*file)[i] = p;
5606 /* Space or NL separates */
Bram Moolenaarc7247912008-01-13 12:54:11 +00005607 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT
5608 || shell_style == STYLE_VIMGLOB)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005609 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00005610 while (!(shell_style == STYLE_ECHO && *p == ' ')
5611 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005612 ++p;
5613 if (p == buffer + len) /* last entry */
5614 *p = NUL;
5615 else
5616 {
5617 *p++ = NUL;
5618 p = skipwhite(p); /* skip to next entry */
5619 }
5620 }
5621 else /* NUL separates */
5622 {
5623 while (*p && p < buffer + len) /* skip entry */
5624 ++p;
5625 ++p; /* skip NUL */
5626 }
5627 }
5628
5629 /*
5630 * Move the file names to allocated memory.
5631 */
5632 for (j = 0, i = 0; i < *num_file; ++i)
5633 {
5634 /* Require the files to exist. Helps when using /bin/sh */
5635 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5636 continue;
5637
5638 /* check if this entry should be included */
5639 dir = (mch_isdir((*file)[i]));
5640 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5641 continue;
5642
Bram Moolenaara2031822006-03-07 22:29:51 +00005643 /* Skip files that are not executable if we check for that. */
5644 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
5645 continue;
5646
Bram Moolenaar071d4272004-06-13 20:20:40 +00005647 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5648 if (p)
5649 {
5650 STRCPY(p, (*file)[i]);
5651 if (dir)
Bram Moolenaarb2389092008-01-03 17:56:04 +00005652 add_pathsep(p); /* add '/' to a directory name */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005653 (*file)[j++] = p;
5654 }
5655 }
5656 vim_free(buffer);
5657 *num_file = j;
5658
5659 if (*num_file == 0) /* rejected all entries */
5660 {
5661 vim_free(*file);
5662 *file = NULL;
5663 goto notfound;
5664 }
5665
5666 return OK;
5667
5668notfound:
5669 if (flags & EW_NOTFOUND)
5670 return save_patterns(num_pat, pat, num_file, file);
5671 return FAIL;
5672
5673#endif /* __EMX__ */
5674}
5675
5676#endif /* VMS */
5677
5678#ifndef __EMX__
5679 static int
5680save_patterns(num_pat, pat, num_file, file)
5681 int num_pat;
5682 char_u **pat;
5683 int *num_file;
5684 char_u ***file;
5685{
5686 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005687 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005688
5689 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5690 if (*file == NULL)
5691 return FAIL;
5692 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005693 {
5694 s = vim_strsave(pat[i]);
5695 if (s != NULL)
5696 /* Be compatible with expand_filename(): halve the number of
5697 * backslashes. */
5698 backslash_halve(s);
5699 (*file)[i] = s;
5700 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005701 *num_file = num_pat;
5702 return OK;
5703}
5704#endif
5705
5706
5707/*
5708 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5709 * expand.
5710 */
5711 int
5712mch_has_exp_wildcard(p)
5713 char_u *p;
5714{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005715 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005716 {
5717#ifndef OS2
5718 if (*p == '\\' && p[1] != NUL)
5719 ++p;
5720 else
5721#endif
5722 if (vim_strchr((char_u *)
5723#ifdef VMS
5724 "*?%"
5725#else
5726# ifdef OS2
5727 "*?"
5728# else
5729 "*?[{'"
5730# endif
5731#endif
5732 , *p) != NULL)
5733 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005734 }
5735 return FALSE;
5736}
5737
5738/*
5739 * Return TRUE if the string "p" contains a wildcard.
5740 * Don't recognize '~' at the end as a wildcard.
5741 */
5742 int
5743mch_has_wildcard(p)
5744 char_u *p;
5745{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005746 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005747 {
5748#ifndef OS2
5749 if (*p == '\\' && p[1] != NUL)
5750 ++p;
5751 else
5752#endif
5753 if (vim_strchr((char_u *)
5754#ifdef VMS
5755 "*?%$"
5756#else
5757# ifdef OS2
5758# ifdef VIM_BACKTICK
5759 "*?$`"
5760# else
5761 "*?$"
5762# endif
5763# else
5764 "*?[{`'$"
5765# endif
5766#endif
5767 , *p) != NULL
5768 || (*p == '~' && p[1] != NUL))
5769 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005770 }
5771 return FALSE;
5772}
5773
5774#ifndef __EMX__
5775 static int
5776have_wildcard(num, file)
5777 int num;
5778 char_u **file;
5779{
5780 int i;
5781
5782 for (i = 0; i < num; i++)
5783 if (mch_has_wildcard(file[i]))
5784 return 1;
5785 return 0;
5786}
5787
5788 static int
5789have_dollars(num, file)
5790 int num;
5791 char_u **file;
5792{
5793 int i;
5794
5795 for (i = 0; i < num; i++)
5796 if (vim_strchr(file[i], '$') != NULL)
5797 return TRUE;
5798 return FALSE;
5799}
5800#endif /* ifndef __EMX__ */
5801
5802#ifndef HAVE_RENAME
5803/*
5804 * Scaled-down version of rename(), which is missing in Xenix.
5805 * This version can only move regular files and will fail if the
5806 * destination exists.
5807 */
5808 int
5809mch_rename(src, dest)
5810 const char *src, *dest;
5811{
5812 struct stat st;
5813
5814 if (stat(dest, &st) >= 0) /* fail if destination exists */
5815 return -1;
5816 if (link(src, dest) != 0) /* link file to new name */
5817 return -1;
5818 if (mch_remove(src) == 0) /* delete link to old name */
5819 return 0;
5820 return -1;
5821}
5822#endif /* !HAVE_RENAME */
5823
5824#ifdef FEAT_MOUSE_GPM
5825/*
5826 * Initializes connection with gpm (if it isn't already opened)
5827 * Return 1 if succeeded (or connection already opened), 0 if failed
5828 */
5829 static int
5830gpm_open()
5831{
5832 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5833
5834 if (!gpm_flag)
5835 {
5836 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5837 gpm_connect.defaultMask = ~GPM_HARD;
5838 /* Default handling for mouse move*/
5839 gpm_connect.minMod = 0; /* Handle any modifier keys */
5840 gpm_connect.maxMod = 0xffff;
5841 if (Gpm_Open(&gpm_connect, 0) > 0)
5842 {
5843 /* gpm library tries to handling TSTP causes
5844 * problems. Anyways, we close connection to Gpm whenever
5845 * we are going to suspend or starting an external process
Bram Moolenaarc2a27c32007-12-01 16:19:33 +00005846 * so we shouldn't have problem with this
Bram Moolenaar071d4272004-06-13 20:20:40 +00005847 */
5848 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5849 return 1; /* succeed */
5850 }
5851 if (gpm_fd == -2)
5852 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5853 return 0;
5854 }
5855 return 1; /* already open */
5856}
5857
5858/*
5859 * Closes connection to gpm
Bram Moolenaar071d4272004-06-13 20:20:40 +00005860 */
5861 static void
5862gpm_close()
5863{
5864 if (gpm_flag && gpm_fd >= 0) /* if Open */
5865 Gpm_Close();
5866}
5867
5868/* Reads gpm event and adds special keys to input buf. Returns length of
5869 * generated key sequence.
5870 * This function is made after gui_send_mouse_event
5871 */
5872 static int
5873mch_gpm_process()
5874{
5875 int button;
5876 static Gpm_Event gpm_event;
5877 char_u string[6];
5878 int_u vim_modifiers;
5879 int row,col;
5880 unsigned char buttons_mask;
5881 unsigned char gpm_modifiers;
5882 static unsigned char old_buttons = 0;
5883
5884 Gpm_GetEvent(&gpm_event);
5885
5886#ifdef FEAT_GUI
5887 /* Don't put events in the input queue now. */
5888 if (hold_gui_events)
5889 return 0;
5890#endif
5891
5892 row = gpm_event.y - 1;
5893 col = gpm_event.x - 1;
5894
5895 string[0] = ESC; /* Our termcode */
5896 string[1] = 'M';
5897 string[2] = 'G';
5898 switch (GPM_BARE_EVENTS(gpm_event.type))
5899 {
5900 case GPM_DRAG:
5901 string[3] = MOUSE_DRAG;
5902 break;
5903 case GPM_DOWN:
5904 buttons_mask = gpm_event.buttons & ~old_buttons;
5905 old_buttons = gpm_event.buttons;
5906 switch (buttons_mask)
5907 {
5908 case GPM_B_LEFT:
5909 button = MOUSE_LEFT;
5910 break;
5911 case GPM_B_MIDDLE:
5912 button = MOUSE_MIDDLE;
5913 break;
5914 case GPM_B_RIGHT:
5915 button = MOUSE_RIGHT;
5916 break;
5917 default:
5918 return 0;
5919 /*Don't know what to do. Can more than one button be
5920 * reported in one event? */
5921 }
5922 string[3] = (char_u)(button | 0x20);
5923 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5924 break;
5925 case GPM_UP:
5926 string[3] = MOUSE_RELEASE;
5927 old_buttons &= ~gpm_event.buttons;
5928 break;
5929 default:
5930 return 0;
5931 }
5932 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5933 gpm_modifiers = gpm_event.modifiers;
5934 vim_modifiers = 0x0;
5935 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5936 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5937 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5938 */
5939 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5940 vim_modifiers |= MOUSE_SHIFT;
5941
5942 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5943 vim_modifiers |= MOUSE_CTRL;
5944 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5945 vim_modifiers |= MOUSE_ALT;
5946 string[3] |= vim_modifiers;
5947 string[4] = (char_u)(col + ' ' + 1);
5948 string[5] = (char_u)(row + ' ' + 1);
5949 add_to_input_buf(string, 6);
5950 return 6;
5951}
5952#endif /* FEAT_MOUSE_GPM */
5953
Bram Moolenaar3577c6f2008-06-24 21:16:56 +00005954#ifdef FEAT_SYSMOUSE
5955/*
5956 * Initialize connection with sysmouse.
5957 * Let virtual console inform us with SIGUSR2 for pending sysmouse
5958 * output, any sysmouse output than will be processed via sig_sysmouse().
5959 * Return OK if succeeded, FAIL if failed.
5960 */
5961 static int
5962sysmouse_open()
5963{
5964 struct mouse_info mouse;
5965
5966 mouse.operation = MOUSE_MODE;
5967 mouse.u.mode.mode = 0;
5968 mouse.u.mode.signal = SIGUSR2;
5969 if (ioctl(1, CONS_MOUSECTL, &mouse) != -1)
5970 {
5971 signal(SIGUSR2, (RETSIGTYPE (*)())sig_sysmouse);
5972 mouse.operation = MOUSE_SHOW;
5973 ioctl(1, CONS_MOUSECTL, &mouse);
5974 return OK;
5975 }
5976 return FAIL;
5977}
5978
5979/*
5980 * Stop processing SIGUSR2 signals, and also make sure that
5981 * virtual console do not send us any sysmouse related signal.
5982 */
5983 static void
5984sysmouse_close()
5985{
5986 struct mouse_info mouse;
5987
5988 signal(SIGUSR2, restricted ? SIG_IGN : SIG_DFL);
5989 mouse.operation = MOUSE_MODE;
5990 mouse.u.mode.mode = 0;
5991 mouse.u.mode.signal = 0;
5992 ioctl(1, CONS_MOUSECTL, &mouse);
5993}
5994
5995/*
5996 * Gets info from sysmouse and adds special keys to input buf.
5997 */
5998/* ARGSUSED */
5999 static RETSIGTYPE
6000sig_sysmouse SIGDEFARG(sigarg)
6001{
6002 struct mouse_info mouse;
6003 struct video_info video;
6004 char_u string[6];
6005 int row, col;
6006 int button;
6007 int buttons;
6008 static int oldbuttons = 0;
6009
6010#ifdef FEAT_GUI
6011 /* Don't put events in the input queue now. */
6012 if (hold_gui_events)
6013 return;
6014#endif
6015
6016 mouse.operation = MOUSE_GETINFO;
6017 if (ioctl(1, FBIO_GETMODE, &video.vi_mode) != -1
6018 && ioctl(1, FBIO_MODEINFO, &video) != -1
6019 && ioctl(1, CONS_MOUSECTL, &mouse) != -1
6020 && video.vi_cheight > 0 && video.vi_cwidth > 0)
6021 {
6022 row = mouse.u.data.y / video.vi_cheight;
6023 col = mouse.u.data.x / video.vi_cwidth;
6024 buttons = mouse.u.data.buttons;
6025 string[0] = ESC; /* Our termcode */
6026 string[1] = 'M';
6027 string[2] = 'S';
6028 if (oldbuttons == buttons && buttons != 0)
6029 {
6030 button = MOUSE_DRAG;
6031 }
6032 else
6033 {
6034 switch (buttons)
6035 {
6036 case 0:
6037 button = MOUSE_RELEASE;
6038 break;
6039 case 1:
6040 button = MOUSE_LEFT;
6041 break;
6042 case 2:
6043 button = MOUSE_MIDDLE;
6044 break;
6045 case 4:
6046 button = MOUSE_RIGHT;
6047 break;
6048 default:
6049 return;
6050 }
6051 oldbuttons = buttons;
6052 }
6053 string[3] = (char_u)(button);
6054 string[4] = (char_u)(col + ' ' + 1);
6055 string[5] = (char_u)(row + ' ' + 1);
6056 add_to_input_buf(string, 6);
6057 }
6058 return;
6059}
6060#endif /* FEAT_SYSMOUSE */
6061
Bram Moolenaar071d4272004-06-13 20:20:40 +00006062#if defined(FEAT_LIBCALL) || defined(PROTO)
6063typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
6064typedef char_u * (*INTPROCSTR)__ARGS((int));
6065typedef int (*STRPROCINT)__ARGS((char_u *));
6066typedef int (*INTPROCINT)__ARGS((int));
6067
6068/*
6069 * Call a DLL routine which takes either a string or int param
6070 * and returns an allocated string.
6071 */
6072 int
6073mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
6074 char_u *libname;
6075 char_u *funcname;
6076 char_u *argstring; /* NULL when using a argint */
6077 int argint;
6078 char_u **string_result;/* NULL when using number_result */
6079 int *number_result;
6080{
6081# if defined(USE_DLOPEN)
6082 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006083 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006084# else
6085 shl_t hinstLib;
6086# endif
6087 STRPROCSTR ProcAdd;
6088 INTPROCSTR ProcAddI;
6089 char_u *retval_str = NULL;
6090 int retval_int = 0;
6091 int success = FALSE;
6092
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006093 /*
6094 * Get a handle to the DLL module.
6095 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006096# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00006097 /* First clear any error, it's not cleared by the dlopen() call. */
6098 (void)dlerror();
6099
Bram Moolenaar071d4272004-06-13 20:20:40 +00006100 hinstLib = dlopen((char *)libname, RTLD_LAZY
6101# ifdef RTLD_LOCAL
6102 | RTLD_LOCAL
6103# endif
6104 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006105 if (hinstLib == NULL)
6106 {
6107 /* "dlerr" must be used before dlclose() */
6108 dlerr = (char *)dlerror();
6109 if (dlerr != NULL)
6110 EMSG2(_("dlerror = \"%s\""), dlerr);
6111 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006112# else
6113 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
6114# endif
6115
6116 /* If the handle is valid, try to get the function address. */
6117 if (hinstLib != NULL)
6118 {
6119# ifdef HAVE_SETJMP_H
6120 /*
6121 * Catch a crash when calling the library function. For example when
6122 * using a number where a string pointer is expected.
6123 */
6124 mch_startjmp();
6125 if (SETJMP(lc_jump_env) != 0)
6126 {
6127 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006128# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006129 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00006130# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006131 mch_didjmp();
6132 }
6133 else
6134# endif
6135 {
6136 retval_str = NULL;
6137 retval_int = 0;
6138
6139 if (argstring != NULL)
6140 {
6141# if defined(USE_DLOPEN)
6142 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006143 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006144# else
6145 if (shl_findsym(&hinstLib, (const char *)funcname,
6146 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
6147 ProcAdd = NULL;
6148# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006149 if ((success = (ProcAdd != NULL
6150# if defined(USE_DLOPEN)
6151 && dlerr == NULL
6152# endif
6153 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006154 {
6155 if (string_result == NULL)
6156 retval_int = ((STRPROCINT)ProcAdd)(argstring);
6157 else
6158 retval_str = (ProcAdd)(argstring);
6159 }
6160 }
6161 else
6162 {
6163# if defined(USE_DLOPEN)
6164 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006165 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006166# else
6167 if (shl_findsym(&hinstLib, (const char *)funcname,
6168 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
6169 ProcAddI = NULL;
6170# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006171 if ((success = (ProcAddI != NULL
6172# if defined(USE_DLOPEN)
6173 && dlerr == NULL
6174# endif
6175 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006176 {
6177 if (string_result == NULL)
6178 retval_int = ((INTPROCINT)ProcAddI)(argint);
6179 else
6180 retval_str = (ProcAddI)(argint);
6181 }
6182 }
6183
6184 /* Save the string before we free the library. */
6185 /* Assume that a "1" or "-1" result is an illegal pointer. */
6186 if (string_result == NULL)
6187 *number_result = retval_int;
6188 else if (retval_str != NULL
6189 && retval_str != (char_u *)1
6190 && retval_str != (char_u *)-1)
6191 *string_result = vim_strsave(retval_str);
6192 }
6193
6194# ifdef HAVE_SETJMP_H
6195 mch_endjmp();
6196# ifdef SIGHASARG
6197 if (lc_signal != 0)
6198 {
6199 int i;
6200
6201 /* try to find the name of this signal */
6202 for (i = 0; signal_info[i].sig != -1; i++)
6203 if (lc_signal == signal_info[i].sig)
6204 break;
6205 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
6206 }
6207# endif
6208# endif
6209
Bram Moolenaar071d4272004-06-13 20:20:40 +00006210# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00006211 /* "dlerr" must be used before dlclose() */
6212 if (dlerr != NULL)
6213 EMSG2(_("dlerror = \"%s\""), dlerr);
6214
6215 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00006216 (void)dlclose(hinstLib);
6217# else
6218 (void)shl_unload(hinstLib);
6219# endif
6220 }
6221
6222 if (!success)
6223 {
6224 EMSG2(_(e_libcall), funcname);
6225 return FAIL;
6226 }
6227
6228 return OK;
6229}
6230#endif
6231
6232#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
6233static int xterm_trace = -1; /* default: disabled */
6234static int xterm_button;
6235
6236/*
6237 * Setup a dummy window for X selections in a terminal.
6238 */
6239 void
6240setup_term_clip()
6241{
6242 int z = 0;
6243 char *strp = "";
6244 Widget AppShell;
6245
6246 if (!x_connect_to_server())
6247 return;
6248
6249 open_app_context();
6250 if (app_context != NULL && xterm_Shell == (Widget)0)
6251 {
6252 int (*oldhandler)();
6253#if defined(HAVE_SETJMP_H)
6254 int (*oldIOhandler)();
6255#endif
6256# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6257 struct timeval start_tv;
6258
6259 if (p_verbose > 0)
6260 gettimeofday(&start_tv, NULL);
6261# endif
6262
6263 /* Ignore X errors while opening the display */
6264 oldhandler = XSetErrorHandler(x_error_check);
6265
6266#if defined(HAVE_SETJMP_H)
6267 /* Ignore X IO errors while opening the display */
6268 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
6269 mch_startjmp();
6270 if (SETJMP(lc_jump_env) != 0)
6271 {
6272 mch_didjmp();
6273 xterm_dpy = NULL;
6274 }
6275 else
6276#endif
6277 {
6278 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6279 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6280#if defined(HAVE_SETJMP_H)
6281 mch_endjmp();
6282#endif
6283 }
6284
6285#if defined(HAVE_SETJMP_H)
6286 /* Now handle X IO errors normally. */
6287 (void)XSetIOErrorHandler(oldIOhandler);
6288#endif
6289 /* Now handle X errors normally. */
6290 (void)XSetErrorHandler(oldhandler);
6291
6292 if (xterm_dpy == NULL)
6293 {
6294 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006295 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006296 return;
6297 }
6298
6299 /* Catch terminating error of the X server connection. */
6300 (void)XSetIOErrorHandler(x_IOerror_handler);
6301
6302# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6303 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006304 {
6305 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006306 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006307 verbose_leave();
6308 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006309# endif
6310
6311 /* Create a Shell to make converters work. */
6312 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6313 applicationShellWidgetClass, xterm_dpy,
6314 NULL);
6315 if (AppShell == (Widget)0)
6316 return;
6317 xterm_Shell = XtVaCreatePopupShell("VIM",
6318 topLevelShellWidgetClass, AppShell,
6319 XtNmappedWhenManaged, 0,
6320 XtNwidth, 1,
6321 XtNheight, 1,
6322 NULL);
6323 if (xterm_Shell == (Widget)0)
6324 return;
6325
6326 x11_setup_atoms(xterm_dpy);
6327 if (x11_display == NULL)
6328 x11_display = xterm_dpy;
6329
6330 XtRealizeWidget(xterm_Shell);
6331 XSync(xterm_dpy, False);
6332 xterm_update();
6333 }
6334 if (xterm_Shell != (Widget)0)
6335 {
6336 clip_init(TRUE);
6337 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6338 x11_window = (Window)atol(strp);
6339 /* Check if $WINDOWID is valid. */
6340 if (test_x11_window(xterm_dpy) == FAIL)
6341 x11_window = 0;
6342 if (x11_window != 0)
6343 xterm_trace = 0;
6344 }
6345}
6346
6347 void
6348start_xterm_trace(button)
6349 int button;
6350{
6351 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6352 return;
6353 xterm_trace = 1;
6354 xterm_button = button;
6355 do_xterm_trace();
6356}
6357
6358
6359 void
6360stop_xterm_trace()
6361{
6362 if (xterm_trace < 0)
6363 return;
6364 xterm_trace = 0;
6365}
6366
6367/*
6368 * Query the xterm pointer and generate mouse termcodes if necessary
6369 * return TRUE if dragging is active, else FALSE
6370 */
6371 static int
6372do_xterm_trace()
6373{
6374 Window root, child;
6375 int root_x, root_y;
6376 int win_x, win_y;
6377 int row, col;
6378 int_u mask_return;
6379 char_u buf[50];
6380 char_u *strp;
6381 long got_hints;
6382 static char_u *mouse_code;
6383 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6384 static int prev_row = 0, prev_col = 0;
6385 static XSizeHints xterm_hints;
6386
6387 if (xterm_trace <= 0)
6388 return FALSE;
6389
6390 if (xterm_trace == 1)
6391 {
6392 /* Get the hints just before tracking starts. The font size might
Bram Moolenaara6c2c912008-01-13 15:31:00 +00006393 * have changed recently. */
6394 if (!XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints)
6395 || !(got_hints & PResizeInc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006396 || xterm_hints.width_inc <= 1
6397 || xterm_hints.height_inc <= 1)
6398 {
6399 xterm_trace = -1; /* Not enough data -- disable tracing */
6400 return FALSE;
6401 }
6402
6403 /* Rely on the same mouse code for the duration of this */
6404 mouse_code = find_termcode(mouse_name);
6405 prev_row = mouse_row;
6406 prev_row = mouse_col;
6407 xterm_trace = 2;
6408
6409 /* Find the offset of the chars, there might be a scrollbar on the
6410 * left of the window and/or a menu on the top (eterm etc.) */
6411 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6412 &win_x, &win_y, &mask_return);
6413 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6414 - (xterm_hints.height_inc / 2);
6415 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6416 xterm_hints.y = 2;
6417 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6418 - (xterm_hints.width_inc / 2);
6419 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6420 xterm_hints.x = 2;
6421 return TRUE;
6422 }
6423 if (mouse_code == NULL)
6424 {
6425 xterm_trace = 0;
6426 return FALSE;
6427 }
6428
6429 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6430 &win_x, &win_y, &mask_return);
6431
6432 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6433 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6434 if (row == prev_row && col == prev_col)
6435 return TRUE;
6436
6437 STRCPY(buf, mouse_code);
6438 strp = buf + STRLEN(buf);
6439 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6440 *strp++ = (char_u)(col + ' ' + 1);
6441 *strp++ = (char_u)(row + ' ' + 1);
6442 *strp = 0;
6443 add_to_input_buf(buf, STRLEN(buf));
6444
6445 prev_row = row;
6446 prev_col = col;
6447 return TRUE;
6448}
6449
6450# if defined(FEAT_GUI) || defined(PROTO)
6451/*
6452 * Destroy the display, window and app_context. Required for GTK.
6453 */
6454 void
6455clear_xterm_clip()
6456{
6457 if (xterm_Shell != (Widget)0)
6458 {
6459 XtDestroyWidget(xterm_Shell);
6460 xterm_Shell = (Widget)0;
6461 }
6462 if (xterm_dpy != NULL)
6463 {
Bram Moolenaare8208012008-06-20 09:59:25 +00006464# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006465 /* Lesstif and Solaris crash here, lose some memory */
6466 XtCloseDisplay(xterm_dpy);
Bram Moolenaare8208012008-06-20 09:59:25 +00006467# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006468 if (x11_display == xterm_dpy)
6469 x11_display = NULL;
6470 xterm_dpy = NULL;
6471 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006472# if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00006473 if (app_context != (XtAppContext)NULL)
6474 {
6475 /* Lesstif and Solaris crash here, lose some memory */
6476 XtDestroyApplicationContext(app_context);
6477 app_context = (XtAppContext)NULL;
6478 }
Bram Moolenaare8208012008-06-20 09:59:25 +00006479# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006480}
6481# endif
6482
6483/*
6484 * Catch up with any queued X events. This may put keyboard input into the
6485 * input buffer, call resize call-backs, trigger timers etc. If there is
6486 * nothing in the X event queue (& no timers pending), then we return
6487 * immediately.
6488 */
6489 static void
6490xterm_update()
6491{
6492 XEvent event;
6493
6494 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6495 {
6496 XtAppNextEvent(app_context, &event);
6497#ifdef FEAT_CLIENTSERVER
6498 {
6499 XPropertyEvent *e = (XPropertyEvent *)&event;
6500
6501 if (e->type == PropertyNotify && e->window == commWindow
6502 && e->atom == commProperty && e->state == PropertyNewValue)
6503 serverEventProc(xterm_dpy, &event);
6504 }
6505#endif
6506 XtDispatchEvent(&event);
6507 }
6508}
6509
6510 int
6511clip_xterm_own_selection(cbd)
6512 VimClipboard *cbd;
6513{
6514 if (xterm_Shell != (Widget)0)
6515 return clip_x11_own_selection(xterm_Shell, cbd);
6516 return FAIL;
6517}
6518
6519 void
6520clip_xterm_lose_selection(cbd)
6521 VimClipboard *cbd;
6522{
6523 if (xterm_Shell != (Widget)0)
6524 clip_x11_lose_selection(xterm_Shell, cbd);
6525}
6526
6527 void
6528clip_xterm_request_selection(cbd)
6529 VimClipboard *cbd;
6530{
6531 if (xterm_Shell != (Widget)0)
6532 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6533}
6534
6535 void
6536clip_xterm_set_selection(cbd)
6537 VimClipboard *cbd;
6538{
6539 clip_x11_set_selection(cbd);
6540}
6541#endif
6542
6543
6544#if defined(USE_XSMP) || defined(PROTO)
6545/*
6546 * Code for X Session Management Protocol.
6547 */
6548static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6549static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6550static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6551static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6552static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6553
6554
6555# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6556static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6557
6558/*
6559 * This is our chance to ask the user if they want to save,
6560 * or abort the logout
6561 */
6562/*ARGSUSED*/
6563 static void
6564xsmp_handle_interaction(smc_conn, client_data)
6565 SmcConn smc_conn;
6566 SmPointer client_data;
6567{
6568 cmdmod_T save_cmdmod;
6569 int cancel_shutdown = False;
6570
6571 save_cmdmod = cmdmod;
6572 cmdmod.confirm = TRUE;
6573 if (check_changed_any(FALSE))
6574 /* Mustn't logout */
6575 cancel_shutdown = True;
6576 cmdmod = save_cmdmod;
6577 setcursor(); /* position cursor */
6578 out_flush();
6579
6580 /* Done interaction */
6581 SmcInteractDone(smc_conn, cancel_shutdown);
6582
6583 /* Finish off
6584 * Only end save-yourself here if we're not cancelling shutdown;
6585 * we'll get a cancelled callback later in which we'll end it.
6586 * Hopefully get around glitchy SMs (like GNOME-1)
6587 */
6588 if (!cancel_shutdown)
6589 {
6590 xsmp.save_yourself = False;
6591 SmcSaveYourselfDone(smc_conn, True);
6592 }
6593}
6594# endif
6595
6596/*
6597 * Callback that starts save-yourself.
6598 */
6599/*ARGSUSED*/
6600 static void
6601xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6602 shutdown, interact_style, fast)
6603 SmcConn smc_conn;
6604 SmPointer client_data;
6605 int save_type;
6606 Bool shutdown;
6607 int interact_style;
6608 Bool fast;
6609{
6610 /* Handle already being in saveyourself */
6611 if (xsmp.save_yourself)
6612 SmcSaveYourselfDone(smc_conn, True);
6613 xsmp.save_yourself = True;
6614 xsmp.shutdown = shutdown;
6615
6616 /* First up, preserve all files */
6617 out_flush();
6618 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6619
6620 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006621 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006622
6623# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6624 /* Now see if we can ask about unsaved files */
6625 if (shutdown && !fast && gui.in_use)
6626 /* Need to interact with user, but need SM's permission */
6627 SmcInteractRequest(smc_conn, SmDialogError,
6628 xsmp_handle_interaction, client_data);
6629 else
6630# endif
6631 {
6632 /* Can stop the cycle here */
6633 SmcSaveYourselfDone(smc_conn, True);
6634 xsmp.save_yourself = False;
6635 }
6636}
6637
6638
6639/*
6640 * Callback to warn us of imminent death.
6641 */
6642/*ARGSUSED*/
6643 static void
6644xsmp_die(smc_conn, client_data)
6645 SmcConn smc_conn;
6646 SmPointer client_data;
6647{
6648 xsmp_close();
6649
6650 /* quit quickly leaving swapfiles for modified buffers behind */
6651 getout_preserve_modified(0);
6652}
6653
6654
6655/*
6656 * Callback to tell us that save-yourself has completed.
6657 */
6658/*ARGSUSED*/
6659 static void
6660xsmp_save_complete(smc_conn, client_data)
6661 SmcConn smc_conn;
6662 SmPointer client_data;
6663{
6664 xsmp.save_yourself = False;
6665}
6666
6667
6668/*
6669 * Callback to tell us that an instigated shutdown was cancelled
6670 * (maybe even by us)
6671 */
6672/*ARGSUSED*/
6673 static void
6674xsmp_shutdown_cancelled(smc_conn, client_data)
6675 SmcConn smc_conn;
6676 SmPointer client_data;
6677{
6678 if (xsmp.save_yourself)
6679 SmcSaveYourselfDone(smc_conn, True);
6680 xsmp.save_yourself = False;
6681 xsmp.shutdown = False;
6682}
6683
6684
6685/*
6686 * Callback to tell us that a new ICE connection has been established.
6687 */
6688/*ARGSUSED*/
6689 static void
6690xsmp_ice_connection(iceConn, clientData, opening, watchData)
6691 IceConn iceConn;
6692 IcePointer clientData;
6693 Bool opening;
6694 IcePointer *watchData;
6695{
6696 /* Intercept creation of ICE connection fd */
6697 if (opening)
6698 {
6699 xsmp_icefd = IceConnectionNumber(iceConn);
6700 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6701 }
6702}
6703
6704
6705/* Handle any ICE processing that's required; return FAIL if SM lost */
6706 int
6707xsmp_handle_requests()
6708{
6709 Bool rep;
6710
6711 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6712 == IceProcessMessagesIOError)
6713 {
6714 /* Lost ICE */
6715 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006716 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006717 xsmp_close();
6718 return FAIL;
6719 }
6720 else
6721 return OK;
6722}
6723
6724static int dummy;
6725
6726/* Set up X Session Management Protocol */
6727 void
6728xsmp_init(void)
6729{
6730 char errorstring[80];
Bram Moolenaar071d4272004-06-13 20:20:40 +00006731 SmcCallbacks smcallbacks;
6732#if 0
6733 SmPropValue smname;
6734 SmProp smnameprop;
6735 SmProp *smprops[1];
6736#endif
6737
6738 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006739 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006740
6741 xsmp.save_yourself = xsmp.shutdown = False;
6742
6743 /* Set up SM callbacks - must have all, even if they're not used */
6744 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6745 smcallbacks.save_yourself.client_data = NULL;
6746 smcallbacks.die.callback = xsmp_die;
6747 smcallbacks.die.client_data = NULL;
6748 smcallbacks.save_complete.callback = xsmp_save_complete;
6749 smcallbacks.save_complete.client_data = NULL;
6750 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6751 smcallbacks.shutdown_cancelled.client_data = NULL;
6752
6753 /* Set up a watch on ICE connection creations. The "dummy" argument is
6754 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6755 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6756 {
6757 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006758 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006759 return;
6760 }
6761
6762 /* Create an SM connection */
6763 xsmp.smcconn = SmcOpenConnection(
6764 NULL,
6765 NULL,
6766 SmProtoMajor,
6767 SmProtoMinor,
6768 SmcSaveYourselfProcMask | SmcDieProcMask
6769 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6770 &smcallbacks,
6771 NULL,
Bram Moolenaare8208012008-06-20 09:59:25 +00006772 &xsmp.clientid,
Bram Moolenaar071d4272004-06-13 20:20:40 +00006773 sizeof(errorstring),
6774 errorstring);
6775 if (xsmp.smcconn == NULL)
6776 {
6777 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00006778
Bram Moolenaar071d4272004-06-13 20:20:40 +00006779 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006780 {
6781 vim_snprintf(errorreport, sizeof(errorreport),
6782 _("XSMP SmcOpenConnection failed: %s"), errorstring);
6783 verb_msg((char_u *)errorreport);
6784 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006785 return;
6786 }
6787 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6788
6789#if 0
6790 /* ID ourselves */
6791 smname.value = "vim";
6792 smname.length = 3;
6793 smnameprop.name = "SmProgram";
6794 smnameprop.type = "SmARRAY8";
6795 smnameprop.num_vals = 1;
6796 smnameprop.vals = &smname;
6797
6798 smprops[0] = &smnameprop;
6799 SmcSetProperties(xsmp.smcconn, 1, smprops);
6800#endif
6801}
6802
6803
6804/* Shut down XSMP comms. */
6805 void
6806xsmp_close()
6807{
6808 if (xsmp_icefd != -1)
6809 {
6810 SmcCloseConnection(xsmp.smcconn, 0, NULL);
Bram Moolenaare8208012008-06-20 09:59:25 +00006811 vim_free(xsmp.clientid);
6812 xsmp.clientid = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006813 xsmp_icefd = -1;
6814 }
6815}
6816#endif /* USE_XSMP */
6817
6818
6819#ifdef EBCDIC
6820/* Translate character to its CTRL- value */
6821char CtrlTable[] =
6822{
6823/* 00 - 5E */
6824 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6825 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6826 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6827 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6828 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6829 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6830/* ^ */ 0x1E,
6831/* - */ 0x1F,
6832/* 61 - 6C */
6833 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6834/* _ */ 0x1F,
6835/* 6E - 80 */
6836 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6837/* a */ 0x01,
6838/* b */ 0x02,
6839/* c */ 0x03,
6840/* d */ 0x37,
6841/* e */ 0x2D,
6842/* f */ 0x2E,
6843/* g */ 0x2F,
6844/* h */ 0x16,
6845/* i */ 0x05,
6846/* 8A - 90 */
6847 0, 0, 0, 0, 0, 0, 0,
6848/* j */ 0x15,
6849/* k */ 0x0B,
6850/* l */ 0x0C,
6851/* m */ 0x0D,
6852/* n */ 0x0E,
6853/* o */ 0x0F,
6854/* p */ 0x10,
6855/* q */ 0x11,
6856/* r */ 0x12,
6857/* 9A - A1 */
6858 0, 0, 0, 0, 0, 0, 0, 0,
6859/* s */ 0x13,
6860/* t */ 0x3C,
6861/* u */ 0x3D,
6862/* v */ 0x32,
6863/* w */ 0x26,
6864/* x */ 0x18,
6865/* y */ 0x19,
6866/* z */ 0x3F,
6867/* AA - AC */
6868 0, 0, 0,
6869/* [ */ 0x27,
6870/* AE - BC */
6871 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6872/* ] */ 0x1D,
6873/* BE - C0 */ 0, 0, 0,
6874/* A */ 0x01,
6875/* B */ 0x02,
6876/* C */ 0x03,
6877/* D */ 0x37,
6878/* E */ 0x2D,
6879/* F */ 0x2E,
6880/* G */ 0x2F,
6881/* H */ 0x16,
6882/* I */ 0x05,
6883/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6884/* J */ 0x15,
6885/* K */ 0x0B,
6886/* L */ 0x0C,
6887/* M */ 0x0D,
6888/* N */ 0x0E,
6889/* O */ 0x0F,
6890/* P */ 0x10,
6891/* Q */ 0x11,
6892/* R */ 0x12,
6893/* DA - DF */ 0, 0, 0, 0, 0, 0,
6894/* \ */ 0x1C,
6895/* E1 */ 0,
6896/* S */ 0x13,
6897/* T */ 0x3C,
6898/* U */ 0x3D,
6899/* V */ 0x32,
6900/* W */ 0x26,
6901/* X */ 0x18,
6902/* Y */ 0x19,
6903/* Z */ 0x3F,
6904/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6905 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6906};
6907
6908char MetaCharTable[]=
6909{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6910 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6911 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6912 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6913 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6914};
6915
6916
6917/* TODO: Use characters NOT numbers!!! */
6918char CtrlCharTable[]=
6919{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6920 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6921 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6922 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6923 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6924};
6925
6926
6927#endif