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