blob: c062ad1bf3337647e039f168b875a770f21ab001 [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
Bram Moolenaar1a3d0862007-08-30 09:47:38 +0000756# if defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_MAX_ALLOWED) \
757 || MAC_OS_X_VERSION_MAX_ALLOWED <= 1040)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
759 * "struct sigaltstack" needs to be declared. */
760 extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
761# endif
762
763# ifdef HAVE_SS_BASE
764 sigstk.ss_base = signal_stack;
765# else
766 sigstk.ss_sp = signal_stack;
767# endif
768 sigstk.ss_size = SIGSTKSZ;
769 sigstk.ss_flags = 0;
770 (void)sigaltstack(&sigstk, NULL);
771# else
772 sigstk.ss_sp = signal_stack;
773 if (stack_grows_downwards)
774 sigstk.ss_sp += SIGSTKSZ - 1;
775 sigstk.ss_onstack = 0;
776 (void)sigstack(&sigstk, NULL);
777# endif
778 }
779}
780#endif
781
782/*
783 * We need correct potatotypes for a signal function, otherwise mean compilers
784 * will barf when the second argument to signal() is ``wrong''.
785 * Let me try it with a few tricky defines from my own osdef.h (jw).
786 */
787#if defined(SIGWINCH)
788/* ARGSUSED */
789 static RETSIGTYPE
790sig_winch SIGDEFARG(sigarg)
791{
792 /* this is not required on all systems, but it doesn't hurt anybody */
793 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
794 do_resize = TRUE;
795 SIGRETURN;
796}
797#endif
798
799#if defined(SIGINT)
800/* ARGSUSED */
801 static RETSIGTYPE
802catch_sigint SIGDEFARG(sigarg)
803{
804 /* this is not required on all systems, but it doesn't hurt anybody */
805 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
806 got_int = TRUE;
807 SIGRETURN;
808}
809#endif
810
811#if defined(SIGPWR)
812/* ARGSUSED */
813 static RETSIGTYPE
814catch_sigpwr SIGDEFARG(sigarg)
815{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000816 /* this is not required on all systems, but it doesn't hurt anybody */
817 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000818 /*
819 * I'm not sure we get the SIGPWR signal when the system is really going
820 * down or when the batteries are almost empty. Just preserve the swap
821 * files and don't exit, that can't do any harm.
822 */
823 ml_sync_all(FALSE, FALSE);
824 SIGRETURN;
825}
826#endif
827
828#ifdef SET_SIG_ALARM
829/*
830 * signal function for alarm().
831 */
832/* ARGSUSED */
833 static RETSIGTYPE
834sig_alarm SIGDEFARG(sigarg)
835{
836 /* doesn't do anything, just to break a system call */
837 sig_alarm_called = TRUE;
838 SIGRETURN;
839}
840#endif
841
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000842#if (defined(HAVE_SETJMP_H) \
843 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
844 || defined(FEAT_LIBCALL))) \
845 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846/*
847 * A simplistic version of setjmp() that only allows one level of using.
848 * Don't call twice before calling mch_endjmp()!.
849 * Usage:
850 * mch_startjmp();
851 * if (SETJMP(lc_jump_env) != 0)
852 * {
853 * mch_didjmp();
854 * EMSG("crash!");
855 * }
856 * else
857 * {
858 * do_the_work;
859 * mch_endjmp();
860 * }
861 * Note: Can't move SETJMP() here, because a function calling setjmp() must
862 * not return before the saved environment is used.
863 * Returns OK for normal return, FAIL when the protected code caused a
864 * problem and LONGJMP() was used.
865 */
866 void
867mch_startjmp()
868{
869#ifdef SIGHASARG
870 lc_signal = 0;
871#endif
872 lc_active = TRUE;
873}
874
875 void
876mch_endjmp()
877{
878 lc_active = FALSE;
879}
880
881 void
882mch_didjmp()
883{
884# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
885 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
886 * otherwise catching the signal only works once. */
887 init_signal_stack();
888# endif
889}
890#endif
891
892/*
893 * This function handles deadly signals.
894 * It tries to preserve any swap file and exit properly.
895 * (partly from Elvis).
896 */
897 static RETSIGTYPE
898deathtrap SIGDEFARG(sigarg)
899{
900 static int entered = 0; /* count the number of times we got here.
901 Note: when memory has been corrupted
902 this may get an arbitrary value! */
903#ifdef SIGHASARG
904 int i;
905#endif
906
907#if defined(HAVE_SETJMP_H)
908 /*
909 * Catch a crash in protected code.
910 * Restores the environment saved in lc_jump_env, which looks like
911 * SETJMP() returns 1.
912 */
913 if (lc_active)
914 {
915# if defined(SIGHASARG)
916 lc_signal = sigarg;
917# endif
918 lc_active = FALSE; /* don't jump again */
919 LONGJMP(lc_jump_env, 1);
920 /* NOTREACHED */
921 }
922#endif
923
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000924#ifdef SIGHASARG
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000925 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
926 * here. This avoids that a non-reentrant function is interrupted, e.g.,
927 * free(). Calling free() again may then cause a crash. */
928 if (entered == 0
929 && (0
930# ifdef SIGHUP
931 || sigarg == SIGHUP
932# endif
933# ifdef SIGQUIT
934 || sigarg == SIGQUIT
935# endif
936# ifdef SIGTERM
937 || sigarg == SIGTERM
938# endif
939# ifdef SIGPWR
940 || sigarg == SIGPWR
941# endif
942# ifdef SIGUSR1
943 || sigarg == SIGUSR1
944# endif
945# ifdef SIGUSR2
946 || sigarg == SIGUSR2
947# endif
948 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +0000949 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000950 SIGRETURN;
951#endif
952
Bram Moolenaar071d4272004-06-13 20:20:40 +0000953 /* Remember how often we have been called. */
954 ++entered;
955
956#ifdef FEAT_EVAL
957 /* Set the v:dying variable. */
958 set_vim_var_nr(VV_DYING, (long)entered);
959#endif
960
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000961#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +0000962 /* Since we are now using the signal stack, need to reset the stack
963 * limit. Otherwise using a regexp will fail. */
964 get_stack_limit();
965#endif
966
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +0000967#if 0
968 /* This is for opening gdb the moment Vim crashes.
969 * You need to manually adjust the file name and Vim executable name.
970 * Suggested by SungHyun Nam. */
971 {
972# define VI_GDB_FILE "/tmp/vimgdb"
973# define VIM_NAME "/usr/bin/vim"
974 FILE *fp = fopen(VI_GDB_FILE, "w");
975 if (fp)
976 {
977 fprintf(fp,
978 "file %s\n"
979 "attach %d\n"
980 "set height 1000\n"
981 "bt full\n"
982 , VIM_NAME, getpid());
983 fclose(fp);
984 system("xterm -e gdb -x "VI_GDB_FILE);
985 unlink(VI_GDB_FILE);
986 }
987 }
988#endif
989
Bram Moolenaar071d4272004-06-13 20:20:40 +0000990#ifdef SIGHASARG
991 /* try to find the name of this signal */
992 for (i = 0; signal_info[i].sig != -1; i++)
993 if (sigarg == signal_info[i].sig)
994 break;
995 deadly_signal = sigarg;
996#endif
997
998 full_screen = FALSE; /* don't write message to the GUI, it might be
999 * part of the problem... */
1000 /*
1001 * If something goes wrong after entering here, we may get here again.
1002 * When this happens, give a message and try to exit nicely (resetting the
1003 * terminal mode, etc.)
1004 * When this happens twice, just exit, don't even try to give a message,
1005 * stack may be corrupt or something weird.
1006 * When this still happens again (or memory was corrupted in such a way
1007 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1008 */
1009 if (entered >= 3)
1010 {
1011 reset_signals(); /* don't catch any signals anymore */
1012 may_core_dump();
1013 if (entered >= 4)
1014 _exit(8);
1015 exit(7);
1016 }
1017 if (entered == 2)
1018 {
1019 OUT_STR(_("Vim: Double signal, exiting\n"));
1020 out_flush();
1021 getout(1);
1022 }
1023
1024#ifdef SIGHASARG
1025 sprintf((char *)IObuff, _("Vim: Caught deadly signal %s\n"),
1026 signal_info[i].name);
1027#else
1028 sprintf((char *)IObuff, _("Vim: Caught deadly signal\n"));
1029#endif
1030 preserve_exit(); /* preserve files and exit */
1031
Bram Moolenaar009b2592004-10-24 19:18:58 +00001032#ifdef NBDEBUG
1033 reset_signals();
1034 may_core_dump();
1035 abort();
1036#endif
1037
Bram Moolenaar071d4272004-06-13 20:20:40 +00001038 SIGRETURN;
1039}
1040
1041#ifdef _REENTRANT
1042/*
1043 * On Solaris with multi-threading, suspending might not work immediately.
1044 * Catch the SIGCONT signal, which will be used as an indication whether the
1045 * suspending has been done or not.
1046 */
1047static int sigcont_received;
1048static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1049
1050/*
1051 * signal handler for SIGCONT
1052 */
1053/* ARGSUSED */
1054 static RETSIGTYPE
1055sigcont_handler SIGDEFARG(sigarg)
1056{
1057 sigcont_received = TRUE;
1058 SIGRETURN;
1059}
1060#endif
1061
1062/*
1063 * If the machine has job control, use it to suspend the program,
1064 * otherwise fake it by starting a new shell.
1065 */
1066 void
1067mch_suspend()
1068{
1069 /* BeOS does have SIGTSTP, but it doesn't work. */
1070#if defined(SIGTSTP) && !defined(__BEOS__)
1071 out_flush(); /* needed to make cursor visible on some systems */
1072 settmode(TMODE_COOK);
1073 out_flush(); /* needed to disable mouse on some systems */
1074
1075# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1076 /* Since we are going to sleep, we can't respond to requests for the X
1077 * selections. Lose them, otherwise other applications will hang. But
1078 * first copy the text to cut buffer 0. */
1079 if (clip_star.owned || clip_plus.owned)
1080 {
1081 x11_export_final_selection();
1082 if (clip_star.owned)
1083 clip_lose_selection(&clip_star);
1084 if (clip_plus.owned)
1085 clip_lose_selection(&clip_plus);
1086 if (x11_display != NULL)
1087 XFlush(x11_display);
1088 }
1089# endif
1090
1091# ifdef _REENTRANT
1092 sigcont_received = FALSE;
1093# endif
1094 kill(0, SIGTSTP); /* send ourselves a STOP signal */
1095# ifdef _REENTRANT
1096 /* When we didn't suspend immediately in the kill(), do it now. Happens
1097 * on multi-threaded Solaris. */
1098 if (!sigcont_received)
1099 pause();
1100# endif
1101
1102# ifdef FEAT_TITLE
1103 /*
1104 * Set oldtitle to NULL, so the current title is obtained again.
1105 */
1106 vim_free(oldtitle);
1107 oldtitle = NULL;
1108# endif
1109 settmode(TMODE_RAW);
1110 need_check_timestamps = TRUE;
1111 did_check_timestamps = FALSE;
1112#else
1113 suspend_shell();
1114#endif
1115}
1116
1117 void
1118mch_init()
1119{
1120 Columns = 80;
1121 Rows = 24;
1122
1123 out_flush();
1124 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001125
Bram Moolenaar56718732006-03-15 22:53:57 +00001126#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001127 mac_conv_init();
1128#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001129}
1130
1131 static void
1132set_signals()
1133{
1134#if defined(SIGWINCH)
1135 /*
1136 * WINDOW CHANGE signal is handled with sig_winch().
1137 */
1138 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1139#endif
1140
1141 /*
1142 * We want the STOP signal to work, to make mch_suspend() work.
1143 * For "rvim" the STOP signal is ignored.
1144 */
1145#ifdef SIGTSTP
1146 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1147#endif
1148#ifdef _REENTRANT
1149 signal(SIGCONT, sigcont_handler);
1150#endif
1151
1152 /*
1153 * We want to ignore breaking of PIPEs.
1154 */
1155#ifdef SIGPIPE
1156 signal(SIGPIPE, SIG_IGN);
1157#endif
1158
Bram Moolenaar071d4272004-06-13 20:20:40 +00001159#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001160 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001161#endif
1162
1163 /*
1164 * Ignore alarm signals (Perl's alarm() generates it).
1165 */
1166#ifdef SIGALRM
1167 signal(SIGALRM, SIG_IGN);
1168#endif
1169
1170 /*
1171 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1172 * work will be lost.
1173 */
1174#ifdef SIGPWR
1175 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1176#endif
1177
1178 /*
1179 * Arrange for other signals to gracefully shutdown Vim.
1180 */
1181 catch_signals(deathtrap, SIG_ERR);
1182
1183#if defined(FEAT_GUI) && defined(SIGHUP)
1184 /*
1185 * When the GUI is running, ignore the hangup signal.
1186 */
1187 if (gui.in_use)
1188 signal(SIGHUP, SIG_IGN);
1189#endif
1190}
1191
Bram Moolenaardf177f62005-02-22 08:39:57 +00001192#if defined(SIGINT) || defined(PROTO)
1193/*
1194 * Catch CTRL-C (only works while in Cooked mode).
1195 */
1196 static void
1197catch_int_signal()
1198{
1199 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1200}
1201#endif
1202
Bram Moolenaar071d4272004-06-13 20:20:40 +00001203 void
1204reset_signals()
1205{
1206 catch_signals(SIG_DFL, SIG_DFL);
1207#ifdef _REENTRANT
1208 /* SIGCONT isn't in the list, because its default action is ignore */
1209 signal(SIGCONT, SIG_DFL);
1210#endif
1211}
1212
1213 static void
1214catch_signals(func_deadly, func_other)
1215 RETSIGTYPE (*func_deadly)();
1216 RETSIGTYPE (*func_other)();
1217{
1218 int i;
1219
1220 for (i = 0; signal_info[i].sig != -1; i++)
1221 if (signal_info[i].deadly)
1222 {
1223#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1224 struct sigaction sa;
1225
1226 /* Setup to use the alternate stack for the signal function. */
1227 sa.sa_handler = func_deadly;
1228 sigemptyset(&sa.sa_mask);
1229# if defined(__linux__) && defined(_REENTRANT)
1230 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1231 * thread handling in combination with using the alternate stack:
1232 * pthread library functions try to use the stack pointer to
1233 * identify the current thread, causing a SEGV signal, which
1234 * recursively calls deathtrap() and hangs. */
1235 sa.sa_flags = 0;
1236# else
1237 sa.sa_flags = SA_ONSTACK;
1238# endif
1239 sigaction(signal_info[i].sig, &sa, NULL);
1240#else
1241# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1242 struct sigvec sv;
1243
1244 /* Setup to use the alternate stack for the signal function. */
1245 sv.sv_handler = func_deadly;
1246 sv.sv_mask = 0;
1247 sv.sv_flags = SV_ONSTACK;
1248 sigvec(signal_info[i].sig, &sv, NULL);
1249# else
1250 signal(signal_info[i].sig, func_deadly);
1251# endif
1252#endif
1253 }
1254 else if (func_other != SIG_ERR)
1255 signal(signal_info[i].sig, func_other);
1256}
1257
1258/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001259 * Handling of SIGHUP, SIGQUIT and SIGTERM:
Bram Moolenaar9e1d2832007-05-06 12:51:41 +00001260 * "when" == a signal: when busy, postpone and return FALSE, otherwise
1261 * return TRUE
1262 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1263 * "when" == SIGNAL_UNBLOCK: Going to wait, unblock signals, use postponed
1264 * signal
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001265 * Returns TRUE when Vim should exit.
1266 */
1267 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001268vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001269 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001270{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001271 static int got_signal = 0;
1272 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001273
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001274 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001275 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001276 case SIGNAL_BLOCK: blocked = TRUE;
1277 break;
1278
1279 case SIGNAL_UNBLOCK: blocked = FALSE;
1280 if (got_signal != 0)
1281 {
1282 kill(getpid(), got_signal);
1283 got_signal = 0;
1284 }
1285 break;
1286
1287 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001288 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001289 got_signal = sig;
1290#ifdef SIGPWR
1291 if (sig != SIGPWR)
1292#endif
1293 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001294 break;
1295 }
1296 return FALSE;
1297}
1298
1299/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001300 * Check_win checks whether we have an interactive stdout.
1301 */
1302/* ARGSUSED */
1303 int
1304mch_check_win(argc, argv)
1305 int argc;
1306 char **argv;
1307{
1308#ifdef OS2
1309 /*
1310 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1311 * name, mostly it's just "vim" and found in the path, which is unusable.
1312 */
1313 if (mch_isFullName(argv[0]))
1314 exe_name = vim_strsave((char_u *)argv[0]);
1315#endif
1316 if (isatty(1))
1317 return OK;
1318 return FAIL;
1319}
1320
1321/*
1322 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1323 */
1324 int
1325mch_input_isatty()
1326{
1327 if (isatty(read_cmd_fd))
1328 return TRUE;
1329 return FALSE;
1330}
1331
1332#ifdef FEAT_X11
1333
1334# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1335 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1336
1337static void xopen_message __ARGS((struct timeval *tvp));
1338
1339/*
1340 * Give a message about the elapsed time for opening the X window.
1341 */
1342 static void
1343xopen_message(tvp)
1344 struct timeval *tvp; /* must contain start time */
1345{
1346 struct timeval end_tv;
1347
1348 /* Compute elapsed time. */
1349 gettimeofday(&end_tv, NULL);
1350 smsg((char_u *)_("Opening the X display took %ld msec"),
1351 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001352 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353}
1354# endif
1355#endif
1356
1357#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1358/*
1359 * A few functions shared by X11 title and clipboard code.
1360 */
1361static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1362static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1363static int x_connect_to_server __ARGS((void));
1364static int test_x11_window __ARGS((Display *dpy));
1365
1366static int got_x_error = FALSE;
1367
1368/*
1369 * X Error handler, otherwise X just exits! (very rude) -- webb
1370 */
1371 static int
1372x_error_handler(dpy, error_event)
1373 Display *dpy;
1374 XErrorEvent *error_event;
1375{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001376 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001377 STRCAT(IObuff, _("\nVim: Got X error\n"));
1378
1379 /* We cannot print a message and continue, because no X calls are allowed
1380 * here (causes my system to hang). Silently continuing might be an
1381 * alternative... */
1382 preserve_exit(); /* preserve files and exit */
1383
1384 return 0; /* NOTREACHED */
1385}
1386
1387/*
1388 * Another X Error handler, just used to check for errors.
1389 */
1390/* ARGSUSED */
1391 static int
1392x_error_check(dpy, error_event)
1393 Display *dpy;
1394 XErrorEvent *error_event;
1395{
1396 got_x_error = TRUE;
1397 return 0;
1398}
1399
1400#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1401# if defined(HAVE_SETJMP_H)
1402/*
1403 * An X IO Error handler, used to catch error while opening the display.
1404 */
1405static int x_IOerror_check __ARGS((Display *dpy));
1406
1407/* ARGSUSED */
1408 static int
1409x_IOerror_check(dpy)
1410 Display *dpy;
1411{
1412 /* This function should not return, it causes exit(). Longjump instead. */
1413 LONGJMP(lc_jump_env, 1);
1414 /*NOTREACHED*/
1415 return 0;
1416}
1417# endif
1418
1419/*
1420 * An X IO Error handler, used to catch terminal errors.
1421 */
1422static int x_IOerror_handler __ARGS((Display *dpy));
1423
1424/* ARGSUSED */
1425 static int
1426x_IOerror_handler(dpy)
1427 Display *dpy;
1428{
1429 xterm_dpy = NULL;
1430 x11_window = 0;
1431 x11_display = NULL;
1432 xterm_Shell = (Widget)0;
1433
1434 /* This function should not return, it causes exit(). Longjump instead. */
1435 LONGJMP(x_jump_env, 1);
1436 /*NOTREACHED*/
1437 return 0;
1438}
1439#endif
1440
1441/*
1442 * Return TRUE when connection to the X server is desired.
1443 */
1444 static int
1445x_connect_to_server()
1446{
1447 regmatch_T regmatch;
1448
1449#if defined(FEAT_CLIENTSERVER)
1450 if (x_force_connect)
1451 return TRUE;
1452#endif
1453 if (x_no_connect)
1454 return FALSE;
1455
1456 /* Check for a match with "exclude:" from 'clipboard'. */
1457 if (clip_exclude_prog != NULL)
1458 {
1459 regmatch.rm_ic = FALSE; /* Don't ignore case */
1460 regmatch.regprog = clip_exclude_prog;
1461 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1462 return FALSE;
1463 }
1464 return TRUE;
1465}
1466
1467/*
1468 * Test if "dpy" and x11_window are valid by getting the window title.
1469 * I don't actually want it yet, so there may be a simpler call to use, but
1470 * this will cause the error handler x_error_check() to be called if anything
1471 * is wrong, such as the window pointer being invalid (as can happen when the
1472 * user changes his DISPLAY, but not his WINDOWID) -- webb
1473 */
1474 static int
1475test_x11_window(dpy)
1476 Display *dpy;
1477{
1478 int (*old_handler)();
1479 XTextProperty text_prop;
1480
1481 old_handler = XSetErrorHandler(x_error_check);
1482 got_x_error = FALSE;
1483 if (XGetWMName(dpy, x11_window, &text_prop))
1484 XFree((void *)text_prop.value);
1485 XSync(dpy, False);
1486 (void)XSetErrorHandler(old_handler);
1487
1488 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001489 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001490
1491 return (got_x_error ? FAIL : OK);
1492}
1493#endif
1494
1495#ifdef FEAT_TITLE
1496
1497#ifdef FEAT_X11
1498
1499static int get_x11_thing __ARGS((int get_title, int test_only));
1500
1501/*
1502 * try to get x11 window and display
1503 *
1504 * return FAIL for failure, OK otherwise
1505 */
1506 static int
1507get_x11_windis()
1508{
1509 char *winid;
1510 static int result = -1;
1511#define XD_NONE 0 /* x11_display not set here */
1512#define XD_HERE 1 /* x11_display opened here */
1513#define XD_GUI 2 /* x11_display used from gui.dpy */
1514#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1515 static int x11_display_from = XD_NONE;
1516 static int did_set_error_handler = FALSE;
1517
1518 if (!did_set_error_handler)
1519 {
1520 /* X just exits if it finds an error otherwise! */
1521 (void)XSetErrorHandler(x_error_handler);
1522 did_set_error_handler = TRUE;
1523 }
1524
Bram Moolenaar9372a112005-12-06 19:59:18 +00001525#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001526 if (gui.in_use)
1527 {
1528 /*
1529 * If the X11 display was opened here before, for the window where Vim
1530 * was started, close that one now to avoid a memory leak.
1531 */
1532 if (x11_display_from == XD_HERE && x11_display != NULL)
1533 {
1534 XCloseDisplay(x11_display);
1535 x11_display_from = XD_NONE;
1536 }
1537 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1538 {
1539 x11_display_from = XD_GUI;
1540 return OK;
1541 }
1542 x11_display = NULL;
1543 return FAIL;
1544 }
1545 else if (x11_display_from == XD_GUI)
1546 {
1547 /* GUI must have stopped somehow, clear x11_display */
1548 x11_window = 0;
1549 x11_display = NULL;
1550 x11_display_from = XD_NONE;
1551 }
1552#endif
1553
1554 /* When started with the "-X" argument, don't try connecting. */
1555 if (!x_connect_to_server())
1556 return FAIL;
1557
1558 /*
1559 * If WINDOWID not set, should try another method to find out
1560 * what the current window number is. The only code I know for
1561 * this is very complicated.
1562 * We assume that zero is invalid for WINDOWID.
1563 */
1564 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1565 x11_window = (Window)atol(winid);
1566
1567#ifdef FEAT_XCLIPBOARD
1568 if (xterm_dpy != NULL && x11_window != 0)
1569 {
1570 /* Checked it already. */
1571 if (x11_display_from == XD_XTERM)
1572 return OK;
1573
1574 /*
1575 * If the X11 display was opened here before, for the window where Vim
1576 * was started, close that one now to avoid a memory leak.
1577 */
1578 if (x11_display_from == XD_HERE && x11_display != NULL)
1579 XCloseDisplay(x11_display);
1580 x11_display = xterm_dpy;
1581 x11_display_from = XD_XTERM;
1582 if (test_x11_window(x11_display) == FAIL)
1583 {
1584 /* probably bad $WINDOWID */
1585 x11_window = 0;
1586 x11_display = NULL;
1587 x11_display_from = XD_NONE;
1588 return FAIL;
1589 }
1590 return OK;
1591 }
1592#endif
1593
1594 if (x11_window == 0 || x11_display == NULL)
1595 result = -1;
1596
1597 if (result != -1) /* Have already been here and set this */
1598 return result; /* Don't do all these X calls again */
1599
1600 if (x11_window != 0 && x11_display == NULL)
1601 {
1602#ifdef SET_SIG_ALARM
1603 RETSIGTYPE (*sig_save)();
1604#endif
1605#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1606 struct timeval start_tv;
1607
1608 if (p_verbose > 0)
1609 gettimeofday(&start_tv, NULL);
1610#endif
1611
1612#ifdef SET_SIG_ALARM
1613 /*
1614 * Opening the Display may hang if the DISPLAY setting is wrong, or
1615 * the network connection is bad. Set an alarm timer to get out.
1616 */
1617 sig_alarm_called = FALSE;
1618 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1619 (RETSIGTYPE (*)())sig_alarm);
1620 alarm(2);
1621#endif
1622 x11_display = XOpenDisplay(NULL);
1623
1624#ifdef SET_SIG_ALARM
1625 alarm(0);
1626 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1627 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001628 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001629#endif
1630 if (x11_display != NULL)
1631 {
1632# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1633 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001634 {
1635 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001637 verbose_leave();
1638 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001639# endif
1640 if (test_x11_window(x11_display) == FAIL)
1641 {
1642 /* Maybe window id is bad */
1643 x11_window = 0;
1644 XCloseDisplay(x11_display);
1645 x11_display = NULL;
1646 }
1647 else
1648 x11_display_from = XD_HERE;
1649 }
1650 }
1651 if (x11_window == 0 || x11_display == NULL)
1652 return (result = FAIL);
1653 return (result = OK);
1654}
1655
1656/*
1657 * Determine original x11 Window Title
1658 */
1659 static int
1660get_x11_title(test_only)
1661 int test_only;
1662{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001663 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001664}
1665
1666/*
1667 * Determine original x11 Window icon
1668 */
1669 static int
1670get_x11_icon(test_only)
1671 int test_only;
1672{
1673 int retval = FALSE;
1674
1675 retval = get_x11_thing(FALSE, test_only);
1676
1677 /* could not get old icon, use terminal name */
1678 if (oldicon == NULL && !test_only)
1679 {
1680 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1681 oldicon = T_NAME + 8;
1682 else
1683 oldicon = T_NAME;
1684 }
1685
1686 return retval;
1687}
1688
1689 static int
1690get_x11_thing(get_title, test_only)
1691 int get_title; /* get title string */
1692 int test_only;
1693{
1694 XTextProperty text_prop;
1695 int retval = FALSE;
1696 Status status;
1697
1698 if (get_x11_windis() == OK)
1699 {
1700 /* Get window/icon name if any */
1701 if (get_title)
1702 status = XGetWMName(x11_display, x11_window, &text_prop);
1703 else
1704 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1705
1706 /*
1707 * If terminal is xterm, then x11_window may be a child window of the
1708 * outer xterm window that actually contains the window/icon name, so
1709 * keep traversing up the tree until a window with a title/icon is
1710 * found.
1711 */
1712 /* Previously this was only done for xterm and alikes. I don't see a
1713 * reason why it would fail for other terminal emulators.
1714 * if (term_is_xterm) */
1715 {
1716 Window root;
1717 Window parent;
1718 Window win = x11_window;
1719 Window *children;
1720 unsigned int num_children;
1721
1722 while (!status || text_prop.value == NULL)
1723 {
1724 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1725 &num_children))
1726 break;
1727 if (children)
1728 XFree((void *)children);
1729 if (parent == root || parent == 0)
1730 break;
1731
1732 win = parent;
1733 if (get_title)
1734 status = XGetWMName(x11_display, win, &text_prop);
1735 else
1736 status = XGetWMIconName(x11_display, win, &text_prop);
1737 }
1738 }
1739 if (status && text_prop.value != NULL)
1740 {
1741 retval = TRUE;
1742 if (!test_only)
1743 {
1744#ifdef FEAT_XFONTSET
1745 if (text_prop.encoding == XA_STRING)
1746 {
1747#endif
1748 if (get_title)
1749 oldtitle = vim_strsave((char_u *)text_prop.value);
1750 else
1751 oldicon = vim_strsave((char_u *)text_prop.value);
1752#ifdef FEAT_XFONTSET
1753 }
1754 else
1755 {
1756 char **cl;
1757 Status transform_status;
1758 int n = 0;
1759
1760 transform_status = XmbTextPropertyToTextList(x11_display,
1761 &text_prop,
1762 &cl, &n);
1763 if (transform_status >= Success && n > 0 && cl[0])
1764 {
1765 if (get_title)
1766 oldtitle = vim_strsave((char_u *) cl[0]);
1767 else
1768 oldicon = vim_strsave((char_u *) cl[0]);
1769 XFreeStringList(cl);
1770 }
1771 else
1772 {
1773 if (get_title)
1774 oldtitle = vim_strsave((char_u *)text_prop.value);
1775 else
1776 oldicon = vim_strsave((char_u *)text_prop.value);
1777 }
1778 }
1779#endif
1780 }
1781 XFree((void *)text_prop.value);
1782 }
1783 }
1784 return retval;
1785}
1786
1787/* Are Xutf8 functions available? Avoid error from old compilers. */
1788#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1789# if X_HAVE_UTF8_STRING
1790# define USE_UTF8_STRING
1791# endif
1792#endif
1793
1794/*
1795 * Set x11 Window Title
1796 *
1797 * get_x11_windis() must be called before this and have returned OK
1798 */
1799 static void
1800set_x11_title(title)
1801 char_u *title;
1802{
1803 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1804 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1805 * supported everywhere and STRING doesn't work for multi-byte titles.
1806 */
1807#ifdef USE_UTF8_STRING
1808 if (enc_utf8)
1809 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1810 NULL, NULL, 0, NULL, NULL, NULL);
1811 else
1812#endif
1813 {
1814#if XtSpecificationRelease >= 4
1815# ifdef FEAT_XFONTSET
1816 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1817 NULL, NULL, 0, NULL, NULL, NULL);
1818# else
1819 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001820 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001821
1822 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001823 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001824 XSetWMProperties(x11_display, x11_window, &text_prop,
1825 NULL, NULL, 0, NULL, NULL, NULL);
1826# endif
1827#else
1828 XStoreName(x11_display, x11_window, (char *)title);
1829#endif
1830 }
1831 XFlush(x11_display);
1832}
1833
1834/*
1835 * Set x11 Window icon
1836 *
1837 * get_x11_windis() must be called before this and have returned OK
1838 */
1839 static void
1840set_x11_icon(icon)
1841 char_u *icon;
1842{
1843 /* See above for comments about using X*SetWMProperties(). */
1844#ifdef USE_UTF8_STRING
1845 if (enc_utf8)
1846 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1847 NULL, 0, NULL, NULL, NULL);
1848 else
1849#endif
1850 {
1851#if XtSpecificationRelease >= 4
1852# ifdef FEAT_XFONTSET
1853 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1854 NULL, 0, NULL, NULL, NULL);
1855# else
1856 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001857 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001858
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001859 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001860 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
1861 NULL, 0, NULL, NULL, NULL);
1862# endif
1863#else
1864 XSetIconName(x11_display, x11_window, (char *)icon);
1865#endif
1866 }
1867 XFlush(x11_display);
1868}
1869
1870#else /* FEAT_X11 */
1871
1872/*ARGSUSED*/
1873 static int
1874get_x11_title(test_only)
1875 int test_only;
1876{
1877 return FALSE;
1878}
1879
1880 static int
1881get_x11_icon(test_only)
1882 int test_only;
1883{
1884 if (!test_only)
1885 {
1886 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1887 oldicon = T_NAME + 8;
1888 else
1889 oldicon = T_NAME;
1890 }
1891 return FALSE;
1892}
1893
1894#endif /* FEAT_X11 */
1895
1896 int
1897mch_can_restore_title()
1898{
1899 return get_x11_title(TRUE);
1900}
1901
1902 int
1903mch_can_restore_icon()
1904{
1905 return get_x11_icon(TRUE);
1906}
1907
1908/*
1909 * Set the window title and icon.
1910 */
1911 void
1912mch_settitle(title, icon)
1913 char_u *title;
1914 char_u *icon;
1915{
1916 int type = 0;
1917 static int recursive = 0;
1918
1919 if (T_NAME == NULL) /* no terminal name (yet) */
1920 return;
1921 if (title == NULL && icon == NULL) /* nothing to do */
1922 return;
1923
1924 /* When one of the X11 functions causes a deadly signal, we get here again
1925 * recursively. Avoid hanging then (something is probably locked). */
1926 if (recursive)
1927 return;
1928 ++recursive;
1929
1930 /*
1931 * if the window ID and the display is known, we may use X11 calls
1932 */
1933#ifdef FEAT_X11
1934 if (get_x11_windis() == OK)
1935 type = 1;
1936#else
1937# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
1938 if (gui.in_use)
1939 type = 1;
1940# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001941#endif
1942
1943 /*
1944 * Note: if "t_TS" is set, title is set with escape sequence rather
1945 * than x11 calls, because the x11 calls don't always work
1946 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001947 if ((type || *T_TS != NUL) && title != NULL)
1948 {
1949 if (oldtitle == NULL
1950#ifdef FEAT_GUI
1951 && !gui.in_use
1952#endif
1953 ) /* first call but not in GUI, save title */
1954 (void)get_x11_title(FALSE);
1955
1956 if (*T_TS != NUL) /* it's OK if t_fs is empty */
1957 term_settitle(title);
1958#ifdef FEAT_X11
1959 else
1960# ifdef FEAT_GUI_GTK
1961 if (!gui.in_use) /* don't do this if GTK+ is running */
1962# endif
1963 set_x11_title(title); /* x11 */
1964#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00001965#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001966 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
1967 else
1968 gui_mch_settitle(title, icon);
1969#endif
1970 did_set_title = TRUE;
1971 }
1972
1973 if ((type || *T_CIS != NUL) && icon != NULL)
1974 {
1975 if (oldicon == NULL
1976#ifdef FEAT_GUI
1977 && !gui.in_use
1978#endif
1979 ) /* first call, save icon */
1980 get_x11_icon(FALSE);
1981
1982 if (*T_CIS != NUL)
1983 {
1984 out_str(T_CIS); /* set icon start */
1985 out_str_nf(icon);
1986 out_str(T_CIE); /* set icon end */
1987 out_flush();
1988 }
1989#ifdef FEAT_X11
1990 else
1991# ifdef FEAT_GUI_GTK
1992 if (!gui.in_use) /* don't do this if GTK+ is running */
1993# endif
1994 set_x11_icon(icon); /* x11 */
1995#endif
1996 did_set_icon = TRUE;
1997 }
1998 --recursive;
1999}
2000
2001/*
2002 * Restore the window/icon title.
2003 * "which" is one of:
2004 * 1 only restore title
2005 * 2 only restore icon
2006 * 3 restore title and icon
2007 */
2008 void
2009mch_restore_title(which)
2010 int which;
2011{
2012 /* only restore the title or icon when it has been set */
2013 mch_settitle(((which & 1) && did_set_title) ?
2014 (oldtitle ? oldtitle : p_titleold) : NULL,
2015 ((which & 2) && did_set_icon) ? oldicon : NULL);
2016}
2017
2018#endif /* FEAT_TITLE */
2019
2020/*
2021 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002022 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023 */
2024 int
2025vim_is_xterm(name)
2026 char_u *name;
2027{
2028 if (name == NULL)
2029 return FALSE;
2030 return (STRNICMP(name, "xterm", 5) == 0
2031 || STRNICMP(name, "nxterm", 6) == 0
2032 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002033 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002034 || STRNICMP(name, "rxvt", 4) == 0
2035 || STRCMP(name, "builtin_xterm") == 0);
2036}
2037
2038#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2039/*
2040 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2041 * Return 1 for "xterm".
2042 * Return 2 for "xterm2".
2043 */
2044 int
2045use_xterm_mouse()
2046{
2047 if (ttym_flags == TTYM_XTERM2)
2048 return 2;
2049 if (ttym_flags == TTYM_XTERM)
2050 return 1;
2051 return 0;
2052}
2053#endif
2054
2055 int
2056vim_is_iris(name)
2057 char_u *name;
2058{
2059 if (name == NULL)
2060 return FALSE;
2061 return (STRNICMP(name, "iris-ansi", 9) == 0
2062 || STRCMP(name, "builtin_iris-ansi") == 0);
2063}
2064
2065 int
2066vim_is_vt300(name)
2067 char_u *name;
2068{
2069 if (name == NULL)
2070 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002071 /* catch VT100 - VT5xx */
2072 return ((STRNICMP(name, "vt", 2) == 0
2073 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002074 || STRCMP(name, "builtin_vt320") == 0);
2075}
2076
2077/*
2078 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2079 * This should include all windowed terminal emulators.
2080 */
2081 int
2082vim_is_fastterm(name)
2083 char_u *name;
2084{
2085 if (name == NULL)
2086 return FALSE;
2087 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2088 return TRUE;
2089 return ( STRNICMP(name, "hpterm", 6) == 0
2090 || STRNICMP(name, "sun-cmd", 7) == 0
2091 || STRNICMP(name, "screen", 6) == 0
2092 || STRNICMP(name, "dtterm", 6) == 0);
2093}
2094
2095/*
2096 * Insert user name in s[len].
2097 * Return OK if a name found.
2098 */
2099 int
2100mch_get_user_name(s, len)
2101 char_u *s;
2102 int len;
2103{
2104#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002105 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002106 return OK;
2107#else
2108 return mch_get_uname(getuid(), s, len);
2109#endif
2110}
2111
2112/*
2113 * Insert user name for "uid" in s[len].
2114 * Return OK if a name found.
2115 */
2116 int
2117mch_get_uname(uid, s, len)
2118 uid_t uid;
2119 char_u *s;
2120 int len;
2121{
2122#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2123 struct passwd *pw;
2124
2125 if ((pw = getpwuid(uid)) != NULL
2126 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2127 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002128 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002129 return OK;
2130 }
2131#endif
2132 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2133 return FAIL; /* a number is not a name */
2134}
2135
2136/*
2137 * Insert host name is s[len].
2138 */
2139
2140#ifdef HAVE_SYS_UTSNAME_H
2141 void
2142mch_get_host_name(s, len)
2143 char_u *s;
2144 int len;
2145{
2146 struct utsname vutsname;
2147
2148 if (uname(&vutsname) < 0)
2149 *s = NUL;
2150 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002151 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002152}
2153#else /* HAVE_SYS_UTSNAME_H */
2154
2155# ifdef HAVE_SYS_SYSTEMINFO_H
2156# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2157# endif
2158
2159 void
2160mch_get_host_name(s, len)
2161 char_u *s;
2162 int len;
2163{
2164# ifdef VAXC
2165 vaxc$gethostname((char *)s, len);
2166# else
2167 gethostname((char *)s, len);
2168# endif
2169 s[len - 1] = NUL; /* make sure it's terminated */
2170}
2171#endif /* HAVE_SYS_UTSNAME_H */
2172
2173/*
2174 * return process ID
2175 */
2176 long
2177mch_get_pid()
2178{
2179 return (long)getpid();
2180}
2181
2182#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2183static char *strerror __ARGS((int));
2184
2185 static char *
2186strerror(err)
2187 int err;
2188{
2189 extern int sys_nerr;
2190 extern char *sys_errlist[];
2191 static char er[20];
2192
2193 if (err > 0 && err < sys_nerr)
2194 return (sys_errlist[err]);
2195 sprintf(er, "Error %d", err);
2196 return er;
2197}
2198#endif
2199
2200/*
2201 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2202 * Return OK for success, FAIL for failure.
2203 */
2204 int
2205mch_dirname(buf, len)
2206 char_u *buf;
2207 int len;
2208{
2209#if defined(USE_GETCWD)
2210 if (getcwd((char *)buf, len) == NULL)
2211 {
2212 STRCPY(buf, strerror(errno));
2213 return FAIL;
2214 }
2215 return OK;
2216#else
2217 return (getwd((char *)buf) != NULL ? OK : FAIL);
2218#endif
2219}
2220
2221#if defined(OS2) || defined(PROTO)
2222/*
2223 * Replace all slashes by backslashes.
2224 * When 'shellslash' set do it the other way around.
2225 */
2226 void
2227slash_adjust(p)
2228 char_u *p;
2229{
2230 while (*p)
2231 {
2232 if (*p == psepcN)
2233 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002234 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002235 }
2236}
2237#endif
2238
2239/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002240 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002241 *
2242 * return FAIL for failure, OK for success
2243 */
2244 int
2245mch_FullName(fname, buf, len, force)
2246 char_u *fname, *buf;
2247 int len;
2248 int force; /* also expand when already absolute path */
2249{
2250 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002251#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002253#endif
2254#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255 int fd = -1;
2256 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002257#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002258 char_u olddir[MAXPATHL];
2259 char_u *p;
2260 int retval = OK;
2261
Bram Moolenaar38323e42007-03-06 19:22:53 +00002262#ifdef VMS
2263 fname = vms_fixfilename(fname);
2264#endif
2265
Bram Moolenaara2442432007-04-26 14:26:37 +00002266#ifdef __CYGWIN__
2267 /*
2268 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2269 */
2270 cygwin_conv_to_posix_path(fname, fname);
2271#endif
2272
Bram Moolenaar071d4272004-06-13 20:20:40 +00002273 /* expand it if forced or not an absolute path */
2274 if (force || !mch_isFullName(fname))
2275 {
2276 /*
2277 * If the file name has a path, change to that directory for a moment,
2278 * and then do the getwd() (and get back to where we were).
2279 * This will get the correct path name with "../" things.
2280 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002281#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002282 only_drive = 0;
2283 if (((p = vim_strrchr(fname, '/')) != NULL)
2284 || ((p = vim_strrchr(fname, '\\')) != NULL)
2285 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002286#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002287 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002288#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002289 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002290#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002291 /*
2292 * Use fchdir() if possible, it's said to be faster and more
2293 * reliable. But on SunOS 4 it might not work. Check this by
2294 * doing a fchdir() right now.
2295 */
2296 if (!dont_fchdir)
2297 {
2298 fd = open(".", O_RDONLY | O_EXTRA, 0);
2299 if (fd >= 0 && fchdir(fd) < 0)
2300 {
2301 close(fd);
2302 fd = -1;
2303 dont_fchdir = TRUE; /* don't try again */
2304 }
2305 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002306#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002307
2308 /* Only change directory when we are sure we can return to where
2309 * we are now. After doing "su" chdir(".") might not work. */
2310 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002311#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002312 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002313#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002314 (mch_dirname(olddir, MAXPATHL) == FAIL
2315 || mch_chdir((char *)olddir) != 0))
2316 {
2317 p = NULL; /* can't get current dir: don't chdir */
2318 retval = FAIL;
2319 }
2320 else
2321 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002322#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002323 /*
2324 * compensate for case where ':' from "D:" was the only
2325 * path separator detected in the file name; the _next_
2326 * character has to be removed, and then restored later.
2327 */
2328 if (only_drive)
2329 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002330#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331 /* The directory is copied into buf[], to be able to remove
2332 * the file name without changing it (could be a string in
2333 * read-only memory) */
2334 if (p - fname >= len)
2335 retval = FAIL;
2336 else
2337 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002338 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339 if (mch_chdir((char *)buf))
2340 retval = FAIL;
2341 else
2342 fname = p + 1;
2343 *buf = NUL;
2344 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002345#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002346 if (only_drive)
2347 {
2348 p--;
2349 if (retval != FAIL)
2350 fname--;
2351 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002352#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002353 }
2354 }
2355 if (mch_dirname(buf, len) == FAIL)
2356 {
2357 retval = FAIL;
2358 *buf = NUL;
2359 }
2360 if (p != NULL)
2361 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002362#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 if (fd >= 0)
2364 {
2365 l = fchdir(fd);
2366 close(fd);
2367 }
2368 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002369#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002370 l = mch_chdir((char *)olddir);
2371 if (l != 0)
2372 EMSG(_(e_prev_dir));
2373 }
2374
2375 l = STRLEN(buf);
2376 if (l >= len)
2377 retval = FAIL;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002378#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379 else
2380 {
2381 if (l > 0 && buf[l - 1] != '/' && *fname != NUL
2382 && STRCMP(fname, ".") != 0)
2383 STRCAT(buf, "/");
2384 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002385#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002386 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002387
Bram Moolenaar071d4272004-06-13 20:20:40 +00002388 /* Catch file names which are too long. */
2389 if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len)
2390 return FAIL;
2391
2392 /* Do not append ".", "/dir/." is equal to "/dir". */
2393 if (STRCMP(fname, ".") != 0)
2394 STRCAT(buf, fname);
2395
2396 return OK;
2397}
2398
2399/*
2400 * Return TRUE if "fname" does not depend on the current directory.
2401 */
2402 int
2403mch_isFullName(fname)
2404 char_u *fname;
2405{
2406#ifdef __EMX__
2407 return _fnisabs(fname);
2408#else
2409# ifdef VMS
2410 return ( fname[0] == '/' || fname[0] == '.' ||
2411 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2412 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2413 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2414# else
2415 return (*fname == '/' || *fname == '~');
2416# endif
2417#endif
2418}
2419
Bram Moolenaar24552be2005-12-10 20:17:30 +00002420#if defined(USE_FNAME_CASE) || defined(PROTO)
2421/*
2422 * Set the case of the file name, if it already exists. This will cause the
2423 * file name to remain exactly the same.
2424 * Only required for file systems where case is ingored and preserved.
2425 */
2426/*ARGSUSED*/
2427 void
2428fname_case(name, len)
2429 char_u *name;
2430 int len; /* buffer size, only used when name gets longer */
2431{
2432 struct stat st;
2433 char_u *slash, *tail;
2434 DIR *dirp;
2435 struct dirent *dp;
2436
2437 if (lstat((char *)name, &st) >= 0)
2438 {
2439 /* Open the directory where the file is located. */
2440 slash = vim_strrchr(name, '/');
2441 if (slash == NULL)
2442 {
2443 dirp = opendir(".");
2444 tail = name;
2445 }
2446 else
2447 {
2448 *slash = NUL;
2449 dirp = opendir((char *)name);
2450 *slash = '/';
2451 tail = slash + 1;
2452 }
2453
2454 if (dirp != NULL)
2455 {
2456 while ((dp = readdir(dirp)) != NULL)
2457 {
2458 /* Only accept names that differ in case and are the same byte
2459 * length. TODO: accept different length name. */
2460 if (STRICMP(tail, dp->d_name) == 0
2461 && STRLEN(tail) == STRLEN(dp->d_name))
2462 {
2463 char_u newname[MAXPATHL + 1];
2464 struct stat st2;
2465
2466 /* Verify the inode is equal. */
2467 vim_strncpy(newname, name, MAXPATHL);
2468 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2469 MAXPATHL - (tail - name));
2470 if (lstat((char *)newname, &st2) >= 0
2471 && st.st_ino == st2.st_ino
2472 && st.st_dev == st2.st_dev)
2473 {
2474 STRCPY(tail, dp->d_name);
2475 break;
2476 }
2477 }
2478 }
2479
2480 closedir(dirp);
2481 }
2482 }
2483}
2484#endif
2485
Bram Moolenaar071d4272004-06-13 20:20:40 +00002486/*
2487 * Get file permissions for 'name'.
2488 * Returns -1 when it doesn't exist.
2489 */
2490 long
2491mch_getperm(name)
2492 char_u *name;
2493{
2494 struct stat statb;
2495
2496 /* Keep the #ifdef outside of stat(), it may be a macro. */
2497#ifdef VMS
2498 if (stat((char *)vms_fixfilename(name), &statb))
2499#else
2500 if (stat((char *)name, &statb))
2501#endif
2502 return -1;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002503#ifdef __INTERIX
2504 /* The top bit makes the value negative, which means the file doesn't
2505 * exist. Remove the bit, we don't use it. */
2506 return statb.st_mode & ~S_ADDACE;
2507#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002508 return statb.st_mode;
Bram Moolenaar708f62c2007-08-11 20:24:10 +00002509#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002510}
2511
2512/*
2513 * set file permission for 'name' to 'perm'
2514 *
2515 * return FAIL for failure, OK otherwise
2516 */
2517 int
2518mch_setperm(name, perm)
2519 char_u *name;
2520 long perm;
2521{
2522 return (chmod((char *)
2523#ifdef VMS
2524 vms_fixfilename(name),
2525#else
2526 name,
2527#endif
2528 (mode_t)perm) == 0 ? OK : FAIL);
2529}
2530
2531#if defined(HAVE_ACL) || defined(PROTO)
2532# ifdef HAVE_SYS_ACL_H
2533# include <sys/acl.h>
2534# endif
2535# ifdef HAVE_SYS_ACCESS_H
2536# include <sys/access.h>
2537# endif
2538
2539# ifdef HAVE_SOLARIS_ACL
2540typedef struct vim_acl_solaris_T {
2541 int acl_cnt;
2542 aclent_t *acl_entry;
2543} vim_acl_solaris_T;
2544# endif
2545
2546/*
2547 * Return a pointer to the ACL of file "fname" in allocated memory.
2548 * Return NULL if the ACL is not available for whatever reason.
2549 */
2550 vim_acl_T
2551mch_get_acl(fname)
2552 char_u *fname;
2553{
2554 vim_acl_T ret = NULL;
2555#ifdef HAVE_POSIX_ACL
2556 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2557#else
2558#ifdef HAVE_SOLARIS_ACL
2559 vim_acl_solaris_T *aclent;
2560
2561 aclent = malloc(sizeof(vim_acl_solaris_T));
2562 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2563 {
2564 free(aclent);
2565 return NULL;
2566 }
2567 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2568 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2569 {
2570 free(aclent->acl_entry);
2571 free(aclent);
2572 return NULL;
2573 }
2574 ret = (vim_acl_T)aclent;
2575#else
2576#if defined(HAVE_AIX_ACL)
2577 int aclsize;
2578 struct acl *aclent;
2579
2580 aclsize = sizeof(struct acl);
2581 aclent = malloc(aclsize);
2582 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2583 {
2584 if (errno == ENOSPC)
2585 {
2586 aclsize = aclent->acl_len;
2587 aclent = realloc(aclent, aclsize);
2588 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2589 {
2590 free(aclent);
2591 return NULL;
2592 }
2593 }
2594 else
2595 {
2596 free(aclent);
2597 return NULL;
2598 }
2599 }
2600 ret = (vim_acl_T)aclent;
2601#endif /* HAVE_AIX_ACL */
2602#endif /* HAVE_SOLARIS_ACL */
2603#endif /* HAVE_POSIX_ACL */
2604 return ret;
2605}
2606
2607/*
2608 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2609 */
2610 void
2611mch_set_acl(fname, aclent)
2612 char_u *fname;
2613 vim_acl_T aclent;
2614{
2615 if (aclent == NULL)
2616 return;
2617#ifdef HAVE_POSIX_ACL
2618 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2619#else
2620#ifdef HAVE_SOLARIS_ACL
2621 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2622 ((vim_acl_solaris_T *)aclent)->acl_entry);
2623#else
2624#ifdef HAVE_AIX_ACL
2625 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2626#endif /* HAVE_AIX_ACL */
2627#endif /* HAVE_SOLARIS_ACL */
2628#endif /* HAVE_POSIX_ACL */
2629}
2630
2631 void
2632mch_free_acl(aclent)
2633 vim_acl_T aclent;
2634{
2635 if (aclent == NULL)
2636 return;
2637#ifdef HAVE_POSIX_ACL
2638 acl_free((acl_t)aclent);
2639#else
2640#ifdef HAVE_SOLARIS_ACL
2641 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2642 free(aclent);
2643#else
2644#ifdef HAVE_AIX_ACL
2645 free(aclent);
2646#endif /* HAVE_AIX_ACL */
2647#endif /* HAVE_SOLARIS_ACL */
2648#endif /* HAVE_POSIX_ACL */
2649}
2650#endif
2651
2652/*
2653 * Set hidden flag for "name".
2654 */
2655/* ARGSUSED */
2656 void
2657mch_hide(name)
2658 char_u *name;
2659{
2660 /* can't hide a file */
2661}
2662
2663/*
2664 * return TRUE if "name" is a directory
2665 * return FALSE if "name" is not a directory
2666 * return FALSE for error
2667 */
2668 int
2669mch_isdir(name)
2670 char_u *name;
2671{
2672 struct stat statb;
2673
2674 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2675 return FALSE;
2676 if (stat((char *)name, &statb))
2677 return FALSE;
2678#ifdef _POSIX_SOURCE
2679 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2680#else
2681 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2682#endif
2683}
2684
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685static int executable_file __ARGS((char_u *name));
2686
2687/*
2688 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2689 */
2690 static int
2691executable_file(name)
2692 char_u *name;
2693{
2694 struct stat st;
2695
2696 if (stat((char *)name, &st))
2697 return 0;
2698 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2699}
2700
2701/*
2702 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2703 * Return -1 if unknown.
2704 */
2705 int
2706mch_can_exe(name)
2707 char_u *name;
2708{
2709 char_u *buf;
2710 char_u *p, *e;
2711 int retval;
2712
2713 /* If it's an absolute or relative path don't need to use $PATH. */
2714 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2715 || (name[1] == '.' && name[2] == '/'))))
2716 return executable_file(name);
2717
2718 p = (char_u *)getenv("PATH");
2719 if (p == NULL || *p == NUL)
2720 return -1;
2721 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2722 if (buf == NULL)
2723 return -1;
2724
2725 /*
2726 * Walk through all entries in $PATH to check if "name" exists there and
2727 * is an executable file.
2728 */
2729 for (;;)
2730 {
2731 e = (char_u *)strchr((char *)p, ':');
2732 if (e == NULL)
2733 e = p + STRLEN(p);
2734 if (e - p <= 1) /* empty entry means current dir */
2735 STRCPY(buf, "./");
2736 else
2737 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002738 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002739 add_pathsep(buf);
2740 }
2741 STRCAT(buf, name);
2742 retval = executable_file(buf);
2743 if (retval == 1)
2744 break;
2745
2746 if (*e != ':')
2747 break;
2748 p = e + 1;
2749 }
2750
2751 vim_free(buf);
2752 return retval;
2753}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002754
2755/*
2756 * Check what "name" is:
2757 * NODE_NORMAL: file or directory (or doesn't exist)
2758 * NODE_WRITABLE: writable device, socket, fifo, etc.
2759 * NODE_OTHER: non-writable things
2760 */
2761 int
2762mch_nodetype(name)
2763 char_u *name;
2764{
2765 struct stat st;
2766
2767 if (stat((char *)name, &st))
2768 return NODE_NORMAL;
2769 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2770 return NODE_NORMAL;
2771#ifndef OS2
2772 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2773 return NODE_OTHER;
2774#endif
2775 /* Everything else is writable? */
2776 return NODE_WRITABLE;
2777}
2778
2779 void
2780mch_early_init()
2781{
2782#ifdef HAVE_CHECK_STACK_GROWTH
2783 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002784
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785 check_stack_growth((char *)&i);
2786
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002787# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002788 get_stack_limit();
2789# endif
2790
2791#endif
2792
2793 /*
2794 * Setup an alternative stack for signals. Helps to catch signals when
2795 * running out of stack space.
2796 * Use of sigaltstack() is preferred, it's more portable.
2797 * Ignore any errors.
2798 */
2799#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2800 signal_stack = malloc(SIGSTKSZ);
2801 init_signal_stack();
2802#endif
2803}
2804
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002805#if defined(EXITFREE) || defined(PROTO)
2806 void
2807mch_free_mem()
2808{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002809# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2810 if (clip_star.owned)
2811 clip_lose_selection(&clip_star);
2812 if (clip_plus.owned)
2813 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002814# endif
2815# if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
2816 if (xterm_Shell != (Widget)0)
2817 XtDestroyWidget(xterm_Shell);
2818 if (xterm_dpy != NULL)
2819 XtCloseDisplay(xterm_dpy);
2820 if (app_context != (XtAppContext)NULL)
2821 XtDestroyApplicationContext(app_context);
2822# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002823# ifdef FEAT_X11
2824 if (x11_display != NULL && x11_display != xterm_dpy)
2825 XCloseDisplay(x11_display);
2826# endif
2827# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2828 vim_free(signal_stack);
2829 signal_stack = NULL;
2830# endif
2831# ifdef FEAT_TITLE
2832 vim_free(oldtitle);
2833 vim_free(oldicon);
2834# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002835}
2836#endif
2837
Bram Moolenaar071d4272004-06-13 20:20:40 +00002838static void exit_scroll __ARGS((void));
2839
2840/*
2841 * Output a newline when exiting.
2842 * Make sure the newline goes to the same stream as the text.
2843 */
2844 static void
2845exit_scroll()
2846{
Bram Moolenaardf177f62005-02-22 08:39:57 +00002847 if (silent_mode)
2848 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002849 if (newline_on_exit || msg_didout)
2850 {
2851 if (msg_use_printf())
2852 {
2853 if (info_message)
2854 mch_msg("\n");
2855 else
2856 mch_errmsg("\r\n");
2857 }
2858 else
2859 out_char('\n');
2860 }
2861 else
2862 {
2863 restore_cterm_colors(); /* get original colors back */
2864 msg_clr_eos_force(); /* clear the rest of the display */
2865 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
2866 }
2867}
2868
2869 void
2870mch_exit(r)
2871 int r;
2872{
2873 exiting = TRUE;
2874
2875#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
2876 x11_export_final_selection();
2877#endif
2878
2879#ifdef FEAT_GUI
2880 if (!gui.in_use)
2881#endif
2882 {
2883 settmode(TMODE_COOK);
2884#ifdef FEAT_TITLE
2885 mch_restore_title(3); /* restore xterm title and icon name */
2886#endif
2887 /*
2888 * When t_ti is not empty but it doesn't cause swapping terminal
2889 * pages, need to output a newline when msg_didout is set. But when
2890 * t_ti does swap pages it should not go to the shell page. Do this
2891 * before stoptermcap().
2892 */
2893 if (swapping_screen() && !newline_on_exit)
2894 exit_scroll();
2895
2896 /* Stop termcap: May need to check for T_CRV response, which
2897 * requires RAW mode. */
2898 stoptermcap();
2899
2900 /*
2901 * A newline is only required after a message in the alternate screen.
2902 * This is set to TRUE by wait_return().
2903 */
2904 if (!swapping_screen() || newline_on_exit)
2905 exit_scroll();
2906
2907 /* Cursor may have been switched off without calling starttermcap()
2908 * when doing "vim -u vimrc" and vimrc contains ":q". */
2909 if (full_screen)
2910 cursor_on();
2911 }
2912 out_flush();
2913 ml_close_all(TRUE); /* remove all memfiles */
2914 may_core_dump();
2915#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002916 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002917 gui_exit(r);
2918#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00002919
Bram Moolenaar56718732006-03-15 22:53:57 +00002920#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00002921 mac_conv_cleanup();
2922#endif
2923
Bram Moolenaar071d4272004-06-13 20:20:40 +00002924#ifdef __QNX__
2925 /* A core dump won't be created if the signal handler
2926 * doesn't return, so we can't call exit() */
2927 if (deadly_signal != 0)
2928 return;
2929#endif
2930
Bram Moolenaar009b2592004-10-24 19:18:58 +00002931#ifdef FEAT_NETBEANS_INTG
2932 if (usingNetbeans)
2933 netbeans_send_disconnect();
2934#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002935
2936#ifdef EXITFREE
2937 free_all_mem();
2938#endif
2939
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940 exit(r);
2941}
2942
2943 static void
2944may_core_dump()
2945{
2946 if (deadly_signal != 0)
2947 {
2948 signal(deadly_signal, SIG_DFL);
2949 kill(getpid(), deadly_signal); /* Die using the signal we caught */
2950 }
2951}
2952
2953#ifndef VMS
2954
2955 void
2956mch_settmode(tmode)
2957 int tmode;
2958{
2959 static int first = TRUE;
2960
2961 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2962#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2963 /*
2964 * for "new" tty systems
2965 */
2966# ifdef HAVE_TERMIOS_H
2967 static struct termios told;
2968 struct termios tnew;
2969# else
2970 static struct termio told;
2971 struct termio tnew;
2972# endif
2973
2974 if (first)
2975 {
2976 first = FALSE;
2977# if defined(HAVE_TERMIOS_H)
2978 tcgetattr(read_cmd_fd, &told);
2979# else
2980 ioctl(read_cmd_fd, TCGETA, &told);
2981# endif
2982 }
2983
2984 tnew = told;
2985 if (tmode == TMODE_RAW)
2986 {
2987 /*
2988 * ~ICRNL enables typing ^V^M
2989 */
2990 tnew.c_iflag &= ~ICRNL;
2991 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
2992# if defined(IEXTEN) && !defined(__MINT__)
2993 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
2994 /* but it breaks function keys on MINT */
2995# endif
2996 );
2997# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
2998 tnew.c_oflag &= ~ONLCR;
2999# endif
3000 tnew.c_cc[VMIN] = 1; /* return after 1 char */
3001 tnew.c_cc[VTIME] = 0; /* don't wait */
3002 }
3003 else if (tmode == TMODE_SLEEP)
3004 tnew.c_lflag &= ~(ECHO);
3005
3006# if defined(HAVE_TERMIOS_H)
3007 {
3008 int n = 10;
3009
3010 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3011 * few times. */
3012 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3013 && errno == EINTR && n > 0)
3014 --n;
3015 }
3016# else
3017 ioctl(read_cmd_fd, TCSETA, &tnew);
3018# endif
3019
3020#else
3021
3022 /*
3023 * for "old" tty systems
3024 */
3025# ifndef TIOCSETN
3026# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3027# endif
3028 static struct sgttyb ttybold;
3029 struct sgttyb ttybnew;
3030
3031 if (first)
3032 {
3033 first = FALSE;
3034 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3035 }
3036
3037 ttybnew = ttybold;
3038 if (tmode == TMODE_RAW)
3039 {
3040 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3041 ttybnew.sg_flags |= RAW;
3042 }
3043 else if (tmode == TMODE_SLEEP)
3044 ttybnew.sg_flags &= ~(ECHO);
3045 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3046#endif
3047 curr_tmode = tmode;
3048}
3049
3050/*
3051 * Try to get the code for "t_kb" from the stty setting
3052 *
3053 * Even if termcap claims a backspace key, the user's setting *should*
3054 * prevail. stty knows more about reality than termcap does, and if
3055 * somebody's usual erase key is DEL (which, for most BSD users, it will
3056 * be), they're going to get really annoyed if their erase key starts
3057 * doing forward deletes for no reason. (Eric Fischer)
3058 */
3059 void
3060get_stty()
3061{
3062 char_u buf[2];
3063 char_u *p;
3064
3065 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3066#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3067 /* for "new" tty systems */
3068# ifdef HAVE_TERMIOS_H
3069 struct termios keys;
3070# else
3071 struct termio keys;
3072# endif
3073
3074# if defined(HAVE_TERMIOS_H)
3075 if (tcgetattr(read_cmd_fd, &keys) != -1)
3076# else
3077 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3078# endif
3079 {
3080 buf[0] = keys.c_cc[VERASE];
3081 intr_char = keys.c_cc[VINTR];
3082#else
3083 /* for "old" tty systems */
3084 struct sgttyb keys;
3085
3086 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3087 {
3088 buf[0] = keys.sg_erase;
3089 intr_char = keys.sg_kill;
3090#endif
3091 buf[1] = NUL;
3092 add_termcode((char_u *)"kb", buf, FALSE);
3093
3094 /*
3095 * If <BS> and <DEL> are now the same, redefine <DEL>.
3096 */
3097 p = find_termcode((char_u *)"kD");
3098 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3099 do_fixdel(NULL);
3100 }
3101#if 0
3102 } /* to keep cindent happy */
3103#endif
3104}
3105
3106#endif /* VMS */
3107
3108#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3109/*
3110 * Set mouse clicks on or off.
3111 */
3112 void
3113mch_setmouse(on)
3114 int on;
3115{
3116 static int ison = FALSE;
3117 int xterm_mouse_vers;
3118
3119 if (on == ison) /* return quickly if nothing to do */
3120 return;
3121
3122 xterm_mouse_vers = use_xterm_mouse();
3123 if (xterm_mouse_vers > 0)
3124 {
3125 if (on) /* enable mouse events, use mouse tracking if available */
3126 out_str_nf((char_u *)
3127 (xterm_mouse_vers > 1
3128 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3129 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3130 else /* disable mouse events, could probably always send the same */
3131 out_str_nf((char_u *)
3132 (xterm_mouse_vers > 1
3133 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3134 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3135 ison = on;
3136 }
3137
3138# ifdef FEAT_MOUSE_DEC
3139 else if (ttym_flags == TTYM_DEC)
3140 {
3141 if (on) /* enable mouse events */
3142 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3143 else /* disable mouse events */
3144 out_str_nf((char_u *)"\033['z");
3145 ison = on;
3146 }
3147# endif
3148
3149# ifdef FEAT_MOUSE_GPM
3150 else
3151 {
3152 if (on)
3153 {
3154 if (gpm_open())
3155 ison = TRUE;
3156 }
3157 else
3158 {
3159 gpm_close();
3160 ison = FALSE;
3161 }
3162 }
3163# endif
3164
3165# ifdef FEAT_MOUSE_JSB
3166 else
3167 {
3168 if (on)
3169 {
3170 /* D - Enable Mouse up/down messages
3171 * L - Enable Left Button Reporting
3172 * M - Enable Middle Button Reporting
3173 * R - Enable Right Button Reporting
3174 * K - Enable SHIFT and CTRL key Reporting
3175 * + - Enable Advanced messaging of mouse moves and up/down messages
3176 * Q - Quiet No Ack
3177 * # - Numeric value of mouse pointer required
3178 * 0 = Multiview 2000 cursor, used as standard
3179 * 1 = Windows Arrow
3180 * 2 = Windows I Beam
3181 * 3 = Windows Hour Glass
3182 * 4 = Windows Cross Hair
3183 * 5 = Windows UP Arrow
3184 */
3185#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3186 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3187 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3188#else
3189 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3190 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3191#endif
3192 ison = TRUE;
3193 }
3194 else
3195 {
3196 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3197 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3198 ison = FALSE;
3199 }
3200 }
3201# endif
3202# ifdef FEAT_MOUSE_PTERM
3203 else
3204 {
3205 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3206 if (on)
3207 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3208 else
3209 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3210 ison = on;
3211 }
3212# endif
3213}
3214
3215/*
3216 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3217 */
3218 void
3219check_mouse_termcode()
3220{
3221# ifdef FEAT_MOUSE_XTERM
3222 if (use_xterm_mouse()
3223# ifdef FEAT_GUI
3224 && !gui.in_use
3225# endif
3226 )
3227 {
3228 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003229 ? IF_EB("\233M", CSI_STR "M")
3230 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231 if (*p_mouse != NUL)
3232 {
3233 /* force mouse off and maybe on to send possibly new mouse
3234 * activation sequence to the xterm, with(out) drag tracing. */
3235 mch_setmouse(FALSE);
3236 setmouse();
3237 }
3238 }
3239 else
3240 del_mouse_termcode(KS_MOUSE);
3241# endif
3242
3243# ifdef FEAT_MOUSE_GPM
3244 if (!use_xterm_mouse()
3245# ifdef FEAT_GUI
3246 && !gui.in_use
3247# endif
3248 )
3249 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3250# endif
3251
3252# ifdef FEAT_MOUSE_JSB
3253 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3254 if (!use_xterm_mouse()
3255# ifdef FEAT_GUI
3256 && !gui.in_use
3257# endif
3258 )
3259 set_mouse_termcode(KS_JSBTERM_MOUSE,
3260 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3261 else
3262 del_mouse_termcode(KS_JSBTERM_MOUSE);
3263# endif
3264
3265# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003266 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003267 * define it in the GUI or when using an xterm. */
3268 if (!use_xterm_mouse()
3269# ifdef FEAT_GUI
3270 && !gui.in_use
3271# endif
3272 )
3273 set_mouse_termcode(KS_NETTERM_MOUSE,
3274 (char_u *)IF_EB("\033}", ESC_STR "}"));
3275 else
3276 del_mouse_termcode(KS_NETTERM_MOUSE);
3277# endif
3278
3279# ifdef FEAT_MOUSE_DEC
3280 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3281 if (!use_xterm_mouse()
3282# ifdef FEAT_GUI
3283 && !gui.in_use
3284# endif
3285 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003286 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3287 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003288 else
3289 del_mouse_termcode(KS_DEC_MOUSE);
3290# endif
3291# ifdef FEAT_MOUSE_PTERM
3292 /* same as the dec mouse */
3293 if (!use_xterm_mouse()
3294# ifdef FEAT_GUI
3295 && !gui.in_use
3296# endif
3297 )
3298 set_mouse_termcode(KS_PTERM_MOUSE,
3299 (char_u *) IF_EB("\033[", ESC_STR "["));
3300 else
3301 del_mouse_termcode(KS_PTERM_MOUSE);
3302# endif
3303}
3304#endif
3305
3306/*
3307 * set screen mode, always fails.
3308 */
3309/* ARGSUSED */
3310 int
3311mch_screenmode(arg)
3312 char_u *arg;
3313{
3314 EMSG(_(e_screenmode));
3315 return FAIL;
3316}
3317
3318#ifndef VMS
3319
3320/*
3321 * Try to get the current window size:
3322 * 1. with an ioctl(), most accurate method
3323 * 2. from the environment variables LINES and COLUMNS
3324 * 3. from the termcap
3325 * 4. keep using the old values
3326 * Return OK when size could be determined, FAIL otherwise.
3327 */
3328 int
3329mch_get_shellsize()
3330{
3331 long rows = 0;
3332 long columns = 0;
3333 char_u *p;
3334
3335 /*
3336 * For OS/2 use _scrsize().
3337 */
3338# ifdef __EMX__
3339 {
3340 int s[2];
3341
3342 _scrsize(s);
3343 columns = s[0];
3344 rows = s[1];
3345 }
3346# endif
3347
3348 /*
3349 * 1. try using an ioctl. It is the most accurate method.
3350 *
3351 * Try using TIOCGWINSZ first, some systems that have it also define
3352 * TIOCGSIZE but don't have a struct ttysize.
3353 */
3354# ifdef TIOCGWINSZ
3355 {
3356 struct winsize ws;
3357 int fd = 1;
3358
3359 /* When stdout is not a tty, use stdin for the ioctl(). */
3360 if (!isatty(fd) && isatty(read_cmd_fd))
3361 fd = read_cmd_fd;
3362 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3363 {
3364 columns = ws.ws_col;
3365 rows = ws.ws_row;
3366 }
3367 }
3368# else /* TIOCGWINSZ */
3369# ifdef TIOCGSIZE
3370 {
3371 struct ttysize ts;
3372 int fd = 1;
3373
3374 /* When stdout is not a tty, use stdin for the ioctl(). */
3375 if (!isatty(fd) && isatty(read_cmd_fd))
3376 fd = read_cmd_fd;
3377 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3378 {
3379 columns = ts.ts_cols;
3380 rows = ts.ts_lines;
3381 }
3382 }
3383# endif /* TIOCGSIZE */
3384# endif /* TIOCGWINSZ */
3385
3386 /*
3387 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003388 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3389 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003390 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003391 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003392 {
3393 if ((p = (char_u *)getenv("LINES")))
3394 rows = atoi((char *)p);
3395 if ((p = (char_u *)getenv("COLUMNS")))
3396 columns = atoi((char *)p);
3397 }
3398
3399#ifdef HAVE_TGETENT
3400 /*
3401 * 3. try reading "co" and "li" entries from termcap
3402 */
3403 if (columns == 0 || rows == 0)
3404 getlinecol(&columns, &rows);
3405#endif
3406
3407 /*
3408 * 4. If everything fails, use the old values
3409 */
3410 if (columns <= 0 || rows <= 0)
3411 return FAIL;
3412
3413 Rows = rows;
3414 Columns = columns;
3415 return OK;
3416}
3417
3418/*
3419 * Try to set the window size to Rows and Columns.
3420 */
3421 void
3422mch_set_shellsize()
3423{
3424 if (*T_CWS)
3425 {
3426 /*
3427 * NOTE: if you get an error here that term_set_winsize() is
3428 * undefined, check the output of configure. It could probably not
3429 * find a ncurses, termcap or termlib library.
3430 */
3431 term_set_winsize((int)Rows, (int)Columns);
3432 out_flush();
3433 screen_start(); /* don't know where cursor is now */
3434 }
3435}
3436
3437#endif /* VMS */
3438
3439/*
3440 * Rows and/or Columns has changed.
3441 */
3442 void
3443mch_new_shellsize()
3444{
3445 /* Nothing to do. */
3446}
3447
Bram Moolenaardf177f62005-02-22 08:39:57 +00003448#ifndef USE_SYSTEM
3449static void append_ga_line __ARGS((garray_T *gap));
3450
3451/*
3452 * Append the text in "gap" below the cursor line and clear "gap".
3453 */
3454 static void
3455append_ga_line(gap)
3456 garray_T *gap;
3457{
3458 /* Remove trailing CR. */
3459 if (gap->ga_len > 0
3460 && !curbuf->b_p_bin
3461 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3462 --gap->ga_len;
3463 ga_append(gap, NUL);
3464 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3465 gap->ga_len = 0;
3466}
3467#endif
3468
Bram Moolenaar071d4272004-06-13 20:20:40 +00003469 int
3470mch_call_shell(cmd, options)
3471 char_u *cmd;
3472 int options; /* SHELL_*, see vim.h */
3473{
3474#ifdef VMS
3475 char *ifn = NULL;
3476 char *ofn = NULL;
3477#endif
3478 int tmode = cur_tmode;
3479#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3480 int x;
3481# ifndef __EMX__
3482 char_u *newcmd; /* only needed for unix */
3483# else
3484 /*
3485 * Set the preferred shell in the EMXSHELL environment variable (but
3486 * only if it is different from what is already in the environment).
3487 * Emx then takes care of whether to use "/c" or "-c" in an
3488 * intelligent way. Simply pass the whole thing to emx's system() call.
3489 * Emx also starts an interactive shell if system() is passed an empty
3490 * string.
3491 */
3492 char_u *p, *old;
3493
3494 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3495 {
3496 /* should check HAVE_SETENV, but I know we don't have it. */
3497 p = alloc(10 + strlen(p_sh));
3498 if (p)
3499 {
3500 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3501 putenv((char *)p); /* don't free the pointer! */
3502 }
3503 }
3504# endif
3505
3506 out_flush();
3507
3508 if (options & SHELL_COOKED)
3509 settmode(TMODE_COOK); /* set to normal mode */
3510
3511# ifdef __EMX__
3512 if (cmd == NULL)
3513 x = system(""); /* this starts an interactive shell in emx */
3514 else
3515 x = system((char *)cmd);
3516 /* system() returns -1 when error occurs in starting shell */
3517 if (x == -1 && !emsg_silent)
3518 {
3519 MSG_PUTS(_("\nCannot execute shell "));
3520 msg_outtrans(p_sh);
3521 msg_putchar('\n');
3522 }
3523# else /* not __EMX__ */
3524 if (cmd == NULL)
3525 x = system((char *)p_sh);
3526 else
3527 {
3528# ifdef VMS
3529 if (ofn = strchr((char *)cmd, '>'))
3530 *ofn++ = '\0';
3531 if (ifn = strchr((char *)cmd, '<'))
3532 {
3533 char *p;
3534
3535 *ifn++ = '\0';
3536 p = strchr(ifn,' '); /* chop off any trailing spaces */
3537 if (p)
3538 *p = '\0';
3539 }
3540 if (ofn)
3541 x = vms_sys((char *)cmd, ofn, ifn);
3542 else
3543 x = system((char *)cmd);
3544# else
3545 newcmd = lalloc(STRLEN(p_sh)
3546 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3547 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3548 if (newcmd == NULL)
3549 x = 0;
3550 else
3551 {
3552 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3553 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3554 (char *)p_shcf,
3555 (char *)cmd);
3556 x = system((char *)newcmd);
3557 vim_free(newcmd);
3558 }
3559# endif
3560 }
3561# ifdef VMS
3562 x = vms_sys_status(x);
3563# endif
3564 if (emsg_silent)
3565 ;
3566 else if (x == 127)
3567 MSG_PUTS(_("\nCannot execute shell sh\n"));
3568# endif /* __EMX__ */
3569 else if (x && !(options & SHELL_SILENT))
3570 {
3571 MSG_PUTS(_("\nshell returned "));
3572 msg_outnum((long)x);
3573 msg_putchar('\n');
3574 }
3575
3576 if (tmode == TMODE_RAW)
3577 settmode(TMODE_RAW); /* set to raw mode */
3578# ifdef FEAT_TITLE
3579 resettitle();
3580# endif
3581 return x;
3582
3583#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3584
Bram Moolenaardf177f62005-02-22 08:39:57 +00003585# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3586 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003587
3588 char_u *newcmd = NULL;
3589 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003590 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003591 pid_t wait_pid = 0;
3592# ifdef HAVE_UNION_WAIT
3593 union wait status;
3594# else
3595 int status = -1;
3596# endif
3597 int retval = -1;
3598 char **argv = NULL;
3599 int argc;
3600 int i;
3601 char_u *p;
3602 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003603 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003604# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003605 int pty_slave_fd = -1;
3606 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003607# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003608 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003609 int fd_fromshell[2];
3610 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003611# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003612 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003613# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003614 static char envbuf_Rows[20];
3615 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003616# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003617 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003618
3619 out_flush();
3620 if (options & SHELL_COOKED)
3621 settmode(TMODE_COOK); /* set to normal mode */
3622
Bram Moolenaar071d4272004-06-13 20:20:40 +00003623 newcmd = vim_strsave(p_sh);
3624 if (newcmd == NULL) /* out of memory */
3625 goto error;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003626
3627 /*
3628 * Do this loop twice:
3629 * 1: find number of arguments
3630 * 2: separate them and build argv[]
3631 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003632 for (i = 0; i < 2; ++i)
3633 {
3634 p = newcmd;
3635 inquote = FALSE;
3636 argc = 0;
3637 for (;;)
3638 {
3639 if (i == 1)
3640 argv[argc] = (char *)p;
3641 ++argc;
3642 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3643 {
3644 if (*p == '"')
3645 inquote = !inquote;
3646 ++p;
3647 }
3648 if (*p == NUL)
3649 break;
3650 if (i == 1)
3651 *p++ = NUL;
3652 p = skipwhite(p);
3653 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003654 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655 {
3656 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3657 if (argv == NULL) /* out of memory */
3658 goto error;
3659 }
3660 }
3661 if (cmd != NULL)
3662 {
3663 if (extra_shell_arg != NULL)
3664 argv[argc++] = (char *)extra_shell_arg;
3665 argv[argc++] = (char *)p_shcf;
3666 argv[argc++] = (char *)cmd;
3667 }
3668 argv[argc] = NULL;
3669
Bram Moolenaar071d4272004-06-13 20:20:40 +00003670 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003671 * For the GUI, when writing the output into the buffer and when reading
3672 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3673 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003674 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003675 if ((options & (SHELL_READ|SHELL_WRITE))
3676# ifdef FEAT_GUI
3677 || (gui.in_use && show_shell_mess)
3678# endif
3679 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003680 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003681# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003682 /*
3683 * Try to open a master pty.
3684 * If this works, open the slave pty.
3685 * If the slave can't be opened, close the master pty.
3686 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003687 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003688 {
3689 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3690 if (pty_master_fd >= 0 && ((pty_slave_fd =
3691 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3692 {
3693 close(pty_master_fd);
3694 pty_master_fd = -1;
3695 }
3696 }
3697 /*
3698 * If not opening a pty or it didn't work, try using pipes.
3699 */
3700 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003701# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003702 {
3703 pipe_error = (pipe(fd_toshell) < 0);
3704 if (!pipe_error) /* pipe create OK */
3705 {
3706 pipe_error = (pipe(fd_fromshell) < 0);
3707 if (pipe_error) /* pipe create failed */
3708 {
3709 close(fd_toshell[0]);
3710 close(fd_toshell[1]);
3711 }
3712 }
3713 if (pipe_error)
3714 {
3715 MSG_PUTS(_("\nCannot create pipes\n"));
3716 out_flush();
3717 }
3718 }
3719 }
3720
3721 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003722 {
3723# ifdef __BEOS__
3724 beos_cleanup_read_thread();
3725# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003726
Bram Moolenaar071d4272004-06-13 20:20:40 +00003727 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3728 {
3729 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003730 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003731# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003732 || (gui.in_use && show_shell_mess)
3733# endif
3734 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003735 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003736# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737 if (pty_master_fd >= 0) /* close the pseudo tty */
3738 {
3739 close(pty_master_fd);
3740 close(pty_slave_fd);
3741 }
3742 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003743# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003744 {
3745 close(fd_toshell[0]);
3746 close(fd_toshell[1]);
3747 close(fd_fromshell[0]);
3748 close(fd_fromshell[1]);
3749 }
3750 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751 }
3752 else if (pid == 0) /* child */
3753 {
3754 reset_signals(); /* handle signals normally */
3755
3756 if (!show_shell_mess || (options & SHELL_EXPAND))
3757 {
3758 int fd;
3759
3760 /*
3761 * Don't want to show any message from the shell. Can't just
3762 * close stdout and stderr though, because some systems will
3763 * break if you try to write to them after that, so we must
3764 * use dup() to replace them with something else -- webb
3765 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3766 * waiting for input.
3767 */
3768 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3769 fclose(stdin);
3770 fclose(stdout);
3771 fclose(stderr);
3772
3773 /*
3774 * If any of these open()'s and dup()'s fail, we just continue
3775 * anyway. It's not fatal, and on most systems it will make
3776 * no difference at all. On a few it will cause the execvp()
3777 * to exit with a non-zero status even when the completion
3778 * could be done, which is nothing too serious. If the open()
3779 * or dup() failed we'd just do the same thing ourselves
3780 * anyway -- webb
3781 */
3782 if (fd >= 0)
3783 {
3784 dup(fd); /* To replace stdin (file descriptor 0) */
3785 dup(fd); /* To replace stdout (file descriptor 1) */
3786 dup(fd); /* To replace stderr (file descriptor 2) */
3787
3788 /* Don't need this now that we've duplicated it */
3789 close(fd);
3790 }
3791 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003792 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003793# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003794 || gui.in_use
3795# endif
3796 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003797 {
3798
Bram Moolenaardf177f62005-02-22 08:39:57 +00003799# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003800 /* Create our own process group, so that the child and all its
3801 * children can be kill()ed. Don't do this when using pipes,
3802 * because stdin is not a tty, we would loose /dev/tty. */
3803 if (p_stmp)
3804 (void)setsid();
Bram Moolenaardf177f62005-02-22 08:39:57 +00003805# endif
3806# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003807 if (pty_slave_fd >= 0)
3808 {
3809 /* push stream discipline modules */
3810 if (options & SHELL_COOKED)
3811 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003813 /* Try to become controlling tty (probably doesn't work,
3814 * unless run by root) */
3815 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003816# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003817 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003818# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003820# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003821 setenv("TERM", "dumb", 1);
3822 sprintf((char *)envbuf, "%ld", Rows);
3823 setenv("ROWS", (char *)envbuf, 1);
3824 sprintf((char *)envbuf, "%ld", Rows);
3825 setenv("LINES", (char *)envbuf, 1);
3826 sprintf((char *)envbuf, "%ld", Columns);
3827 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003828# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003829 /*
3830 * Putenv does not copy the string, it has to remain valid.
3831 * Use a static array to avoid loosing allocated memory.
3832 */
3833 putenv("TERM=dumb");
3834 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
3835 putenv(envbuf_Rows);
3836 sprintf(envbuf_Rows, "LINES=%ld", Rows);
3837 putenv(envbuf_Rows);
3838 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
3839 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003840# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003841
Bram Moolenaara5792f52005-11-23 21:25:05 +00003842 /*
3843 * stderr is only redirected when using the GUI, so that a
3844 * program like gpg can still access the terminal to get a
3845 * passphrase using stderr.
3846 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003847# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003848 if (pty_master_fd >= 0)
3849 {
3850 close(pty_master_fd); /* close master side of pty */
3851
3852 /* set up stdin/stdout/stderr for the child */
3853 close(0);
3854 dup(pty_slave_fd);
3855 close(1);
3856 dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003857 if (gui.in_use)
3858 {
3859 close(2);
3860 dup(pty_slave_fd);
3861 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003862
3863 close(pty_slave_fd); /* has been dupped, close it now */
3864 }
3865 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003866# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003867 {
3868 /* set up stdin for the child */
3869 close(fd_toshell[1]);
3870 close(0);
3871 dup(fd_toshell[0]);
3872 close(fd_toshell[0]);
3873
3874 /* set up stdout for the child */
3875 close(fd_fromshell[0]);
3876 close(1);
3877 dup(fd_fromshell[1]);
3878 close(fd_fromshell[1]);
3879
Bram Moolenaara5792f52005-11-23 21:25:05 +00003880# ifdef FEAT_GUI
3881 if (gui.in_use)
3882 {
3883 /* set up stderr for the child */
3884 close(2);
3885 dup(1);
3886 }
3887# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888 }
3889 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003890
Bram Moolenaar071d4272004-06-13 20:20:40 +00003891 /*
3892 * There is no type cast for the argv, because the type may be
3893 * different on different machines. This may cause a warning
3894 * message with strict compilers, don't worry about it.
3895 * Call _exit() instead of exit() to avoid closing the connection
3896 * to the X server (esp. with GTK, which uses atexit()).
3897 */
3898 execvp(argv[0], argv);
3899 _exit(EXEC_FAILED); /* exec failed, return failure code */
3900 }
3901 else /* parent */
3902 {
3903 /*
3904 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003905 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003906 */
3907 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003908 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003909
3910 /*
3911 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003912 * This is also used to pipe stdin/stdout to/from the external
3913 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003914 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003915 if ((options & (SHELL_READ|SHELL_WRITE))
3916# ifdef FEAT_GUI
3917 || (gui.in_use && show_shell_mess)
3918# endif
3919 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003920 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003921# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003922 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003923# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003924 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003925# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003926 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
3927 int ta_len = 0; /* valid bytes in ta_buf[] */
3928 int len;
3929 int p_more_save;
3930 int old_State;
3931 int c;
3932 int toshell_fd;
3933 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003934 garray_T ga;
3935 int noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003936
Bram Moolenaardf177f62005-02-22 08:39:57 +00003937# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003938 if (pty_master_fd >= 0)
3939 {
3940 close(pty_slave_fd); /* close slave side of pty */
3941 fromshell_fd = pty_master_fd;
3942 toshell_fd = dup(pty_master_fd);
3943 }
3944 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003945# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003946 {
3947 close(fd_toshell[0]);
3948 close(fd_fromshell[1]);
3949 toshell_fd = fd_toshell[1];
3950 fromshell_fd = fd_fromshell[0];
3951 }
3952
3953 /*
3954 * Write to the child if there are typed characters.
3955 * Read from the child if there are characters available.
3956 * Repeat the reading a few times if more characters are
3957 * available. Need to check for typed keys now and then, but
3958 * not too often (delays when no chars are available).
3959 * This loop is quit if no characters can be read from the pty
3960 * (WaitForChar detected special condition), or there are no
3961 * characters available and the child has exited.
3962 * Only check if the child has exited when there is no more
3963 * output. The child may exit before all the output has
3964 * been printed.
3965 *
3966 * Currently this busy loops!
3967 * This can probably dead-lock when the write blocks!
3968 */
3969 p_more_save = p_more;
3970 p_more = FALSE;
3971 old_State = State;
3972 State = EXTERNCMD; /* don't redraw at window resize */
3973
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003974 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003975 {
3976 /* Fork a process that will write the lines to the
3977 * external program. */
3978 if ((wpid = fork()) == -1)
3979 {
3980 MSG_PUTS(_("\nCannot fork\n"));
3981 }
3982 else if (wpid == 0)
3983 {
3984 linenr_T lnum = curbuf->b_op_start.lnum;
3985 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00003986 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003987 char_u *s;
3988 size_t l;
3989
3990 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00003991 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003992 for (;;)
3993 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00003994 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003995 if (l == 0)
3996 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00003997 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003998 /* NL -> NUL translation */
3999 len = write(toshell_fd, "", (size_t)1);
4000 else
4001 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00004002 s = vim_strchr(lp + written, NL);
4003 len = write(toshell_fd, (char *)lp + written,
4004 s == NULL ? l : s - (lp + written));
Bram Moolenaardf177f62005-02-22 08:39:57 +00004005 }
4006 if (len == l)
4007 {
4008 /* Finished a line, add a NL, unless this line
4009 * should not have one. */
4010 if (lnum != curbuf->b_op_end.lnum
4011 || !curbuf->b_p_bin
4012 || (lnum != write_no_eol_lnum
4013 && (lnum !=
4014 curbuf->b_ml.ml_line_count
4015 || curbuf->b_p_eol)))
4016 write(toshell_fd, "\n", (size_t)1);
4017 ++lnum;
4018 if (lnum > curbuf->b_op_end.lnum)
4019 {
4020 /* finished all the lines, close pipe */
4021 close(toshell_fd);
4022 toshell_fd = -1;
4023 break;
4024 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004025 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004026 written = 0;
4027 }
4028 else if (len > 0)
4029 written += len;
4030 }
4031 _exit(0);
4032 }
4033 else
4034 {
4035 close(toshell_fd);
4036 toshell_fd = -1;
4037 }
4038 }
4039
4040 if (options & SHELL_READ)
4041 ga_init2(&ga, 1, BUFLEN);
4042
4043 noread_cnt = 0;
4044
Bram Moolenaar071d4272004-06-13 20:20:40 +00004045 for (;;)
4046 {
4047 /*
4048 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004049 * if there are any.
4050 * Don't do this if we are expanding wild cards (would eat
4051 * typeahead).
4052 * Don't do this when filtering and terminal is in cooked
4053 * mode, the shell command will handle the I/O. Avoids
4054 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004055 * Don't get characters when the child has already
4056 * finished (wait_pid == 0).
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004057 * Don't get extra characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004058 * Don't read characters unless we didn't get output for a
4059 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004060 */
4061 len = 0;
4062 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004063 && ((options &
4064 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4065 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
4066#ifdef FEAT_GUI
4067 || gui.in_use
4068#endif
4069 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004070 && wait_pid == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004071 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00004072 || (noread_cnt > 4
4073 && (len = ui_inchar(ta_buf,
4074 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004075 {
4076 /*
4077 * For pipes:
4078 * Check for CTRL-C: send interrupt signal to child.
4079 * Check for CTRL-D: EOF, close pipe to child.
4080 */
4081 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4082 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004083# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004084 /*
4085 * Send SIGINT to the child's group or all
4086 * processes in our group.
4087 */
4088 if (ta_buf[ta_len] == Ctrl_C
4089 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004090 {
4091# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004092 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004093# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004094 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004095# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004096 if (wpid > 0)
4097 kill(wpid, SIGINT);
4098 }
4099# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004100 if (pty_master_fd < 0 && toshell_fd >= 0
4101 && ta_buf[ta_len] == Ctrl_D)
4102 {
4103 close(toshell_fd);
4104 toshell_fd = -1;
4105 }
4106 }
4107
4108 /* replace K_BS by <BS> and K_DEL by <DEL> */
4109 for (i = ta_len; i < ta_len + len; ++i)
4110 {
4111 if (ta_buf[i] == CSI && len - i > 2)
4112 {
4113 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4114 if (c == K_DEL || c == K_KDEL || c == K_BS)
4115 {
4116 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4117 (size_t)(len - i - 2));
4118 if (c == K_DEL || c == K_KDEL)
4119 ta_buf[i] = DEL;
4120 else
4121 ta_buf[i] = Ctrl_H;
4122 len -= 2;
4123 }
4124 }
4125 else if (ta_buf[i] == '\r')
4126 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004127# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004128 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004129 i += (*mb_ptr2len)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004130# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004131 }
4132
4133 /*
4134 * For pipes: echo the typed characters.
4135 * For a pty this does not seem to work.
4136 */
4137 if (pty_master_fd < 0)
4138 {
4139 for (i = ta_len; i < ta_len + len; ++i)
4140 {
4141 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4142 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004143# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004144 else if (has_mbyte)
4145 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004146 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004147
4148 msg_outtrans_len(ta_buf + i, l);
4149 i += l - 1;
4150 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004151# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004152 else
4153 msg_outtrans_len(ta_buf + i, 1);
4154 }
4155 windgoto(msg_row, msg_col);
4156 out_flush();
4157 }
4158
4159 ta_len += len;
4160
4161 /*
4162 * Write the characters to the child, unless EOF has
4163 * been typed for pipes. Write one character at a
4164 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004165 * When writing buffer lines, drop the typed
4166 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004168 if (options & SHELL_WRITE)
4169 ta_len = 0;
4170 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004171 {
4172 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4173 if (len > 0)
4174 {
4175 ta_len -= len;
4176 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004177 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178 }
4179 }
4180 }
4181
Bram Moolenaardf177f62005-02-22 08:39:57 +00004182 if (got_int)
4183 {
4184 /* CTRL-C sends a signal to the child, we ignore it
4185 * ourselves */
4186# ifdef HAVE_SETSID
4187 kill(-pid, SIGINT);
4188# else
4189 kill(0, SIGINT);
4190# endif
4191 if (wpid > 0)
4192 kill(wpid, SIGINT);
4193 got_int = FALSE;
4194 }
4195
Bram Moolenaar071d4272004-06-13 20:20:40 +00004196 /*
4197 * Check if the child has any characters to be printed.
4198 * Read them and write them to our window. Repeat this as
4199 * long as there is something to do, avoid the 10ms wait
4200 * for mch_inchar(), or sending typeahead characters to
4201 * the external process.
4202 * TODO: This should handle escape sequences, compatible
4203 * to some terminal (vt52?).
4204 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004205 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004206 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4207 {
4208 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004209# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004210 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004211# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004212 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004213# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004214 );
4215 if (len <= 0) /* end of file or error */
4216 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004217
4218 noread_cnt = 0;
4219 if (options & SHELL_READ)
4220 {
4221 /* Do NUL -> NL translation, append NL separated
4222 * lines to the current buffer. */
4223 for (i = 0; i < len; ++i)
4224 {
4225 if (buffer[i] == NL)
4226 append_ga_line(&ga);
4227 else if (buffer[i] == NUL)
4228 ga_append(&ga, NL);
4229 else
4230 ga_append(&ga, buffer[i]);
4231 }
4232 }
4233# ifdef FEAT_MBYTE
4234 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235 {
4236 int l;
4237
Bram Moolenaardf177f62005-02-22 08:39:57 +00004238 len += buffer_off;
4239 buffer[len] = NUL;
4240
Bram Moolenaar071d4272004-06-13 20:20:40 +00004241 /* Check if the last character in buffer[] is
4242 * incomplete, keep these bytes for the next
4243 * round. */
4244 for (p = buffer; p < buffer + len; p += l)
4245 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004246 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004247 if (l == 0)
4248 l = 1; /* NUL byte? */
4249 else if (MB_BYTE2LEN(*p) != l)
4250 break;
4251 }
4252 if (p == buffer) /* no complete character */
4253 {
4254 /* avoid getting stuck at an illegal byte */
4255 if (len >= 12)
4256 ++p;
4257 else
4258 {
4259 buffer_off = len;
4260 continue;
4261 }
4262 }
4263 c = *p;
4264 *p = NUL;
4265 msg_puts(buffer);
4266 if (p < buffer + len)
4267 {
4268 *p = c;
4269 buffer_off = (buffer + len) - p;
4270 mch_memmove(buffer, p, buffer_off);
4271 continue;
4272 }
4273 buffer_off = 0;
4274 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004275# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004276 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004277 {
4278 buffer[len] = NUL;
4279 msg_puts(buffer);
4280 }
4281
4282 windgoto(msg_row, msg_col);
4283 cursor_on();
4284 out_flush();
4285 if (got_int)
4286 break;
4287 }
4288
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004289 /* If we already detected the child has finished break the
4290 * loop now. */
4291 if (wait_pid == pid)
4292 break;
4293
Bram Moolenaar071d4272004-06-13 20:20:40 +00004294 /*
4295 * Check if the child still exists, before checking for
4296 * typed characters (otherwise we would loose typeahead).
4297 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004298# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004299 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004300# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004302# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4304 || (wait_pid == pid && WIFEXITED(status)))
4305 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004306 /* Don't break the loop yet, try reading more
4307 * characters from "fromshell_fd" first. When using
4308 * pipes there might still be something to read and
4309 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004310 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004311 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004312 else
4313 wait_pid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314 }
4315finished:
4316 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004317 if (options & SHELL_READ)
4318 {
4319 if (ga.ga_len > 0)
4320 {
4321 append_ga_line(&ga);
4322 /* remember that the NL was missing */
4323 write_no_eol_lnum = curwin->w_cursor.lnum;
4324 }
4325 else
4326 write_no_eol_lnum = 0;
4327 ga_clear(&ga);
4328 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004329
Bram Moolenaar071d4272004-06-13 20:20:40 +00004330 /*
4331 * Give all typeahead that wasn't used back to ui_inchar().
4332 */
4333 if (ta_len)
4334 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004335 State = old_State;
4336 if (toshell_fd >= 0)
4337 close(toshell_fd);
4338 close(fromshell_fd);
4339 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004340
4341 /*
4342 * Wait until our child has exited.
4343 * Ignore wait() returning pids of other children and returning
4344 * because of some signal like SIGWINCH.
4345 * Don't wait if wait_pid was already set above, indicating the
4346 * child already exited.
4347 */
4348 while (wait_pid != pid)
4349 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004350# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004351 /* Ugly hack: when compiled with Python threads are probably
4352 * used, in which case wait() sometimes hangs for no obvious
4353 * reason. Use waitpid() instead and loop (like the GUI). */
4354# ifdef __NeXT__
4355 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4356# else
4357 wait_pid = waitpid(pid, &status, WNOHANG);
4358# endif
4359 if (wait_pid == 0)
4360 {
4361 /* Wait for 1/100 sec before trying again. */
4362 mch_delay(10L, TRUE);
4363 continue;
4364 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004365# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004366 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004367# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004368 if (wait_pid <= 0
4369# ifdef ECHILD
4370 && errno == ECHILD
4371# endif
4372 )
4373 break;
4374 }
4375
Bram Moolenaardf177f62005-02-22 08:39:57 +00004376 /* Make sure the child that writes to the external program is
4377 * dead. */
4378 if (wpid > 0)
4379 kill(wpid, SIGKILL);
4380
Bram Moolenaar071d4272004-06-13 20:20:40 +00004381 /*
4382 * Set to raw mode right now, otherwise a CTRL-C after
4383 * catch_signals() will kill Vim.
4384 */
4385 if (tmode == TMODE_RAW)
4386 settmode(TMODE_RAW);
4387 did_settmode = TRUE;
4388 set_signals();
4389
4390 if (WIFEXITED(status))
4391 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004392 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004393 retval = WEXITSTATUS(status);
4394 if (retval && !emsg_silent)
4395 {
4396 if (retval == EXEC_FAILED)
4397 {
4398 MSG_PUTS(_("\nCannot execute shell "));
4399 msg_outtrans(p_sh);
4400 msg_putchar('\n');
4401 }
4402 else if (!(options & SHELL_SILENT))
4403 {
4404 MSG_PUTS(_("\nshell returned "));
4405 msg_outnum((long)retval);
4406 msg_putchar('\n');
4407 }
4408 }
4409 }
4410 else
4411 MSG_PUTS(_("\nCommand terminated\n"));
4412 }
4413 }
4414 vim_free(argv);
4415
4416error:
4417 if (!did_settmode)
4418 if (tmode == TMODE_RAW)
4419 settmode(TMODE_RAW); /* set to raw mode */
4420# ifdef FEAT_TITLE
4421 resettitle();
4422# endif
4423 vim_free(newcmd);
4424
4425 return retval;
4426
4427#endif /* USE_SYSTEM */
4428}
4429
4430/*
4431 * Check for CTRL-C typed by reading all available characters.
4432 * In cooked mode we should get SIGINT, no need to check.
4433 */
4434 void
4435mch_breakcheck()
4436{
4437 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4438 fill_input_buf(FALSE);
4439}
4440
4441/*
4442 * Wait "msec" msec until a character is available from the keyboard or from
4443 * inbuf[]. msec == -1 will block forever.
4444 * When a GUI is being used, this will never get called -- webb
4445 */
4446 static int
4447WaitForChar(msec)
4448 long msec;
4449{
4450#ifdef FEAT_MOUSE_GPM
4451 int gpm_process_wanted;
4452#endif
4453#ifdef FEAT_XCLIPBOARD
4454 int rest;
4455#endif
4456 int avail;
4457
4458 if (input_available()) /* something in inbuf[] */
4459 return 1;
4460
4461#if defined(FEAT_MOUSE_DEC)
4462 /* May need to query the mouse position. */
4463 if (WantQueryMouse)
4464 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004465 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004466 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4467 }
4468#endif
4469
4470 /*
4471 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4472 * events. This is a bit complicated, because they might both be defined.
4473 */
4474#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4475# ifdef FEAT_XCLIPBOARD
4476 rest = 0;
4477 if (do_xterm_trace())
4478 rest = msec;
4479# endif
4480 do
4481 {
4482# ifdef FEAT_XCLIPBOARD
4483 if (rest != 0)
4484 {
4485 msec = XT_TRACE_DELAY;
4486 if (rest >= 0 && rest < XT_TRACE_DELAY)
4487 msec = rest;
4488 if (rest >= 0)
4489 rest -= msec;
4490 }
4491# endif
4492# ifdef FEAT_MOUSE_GPM
4493 gpm_process_wanted = 0;
4494 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4495# else
4496 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4497# endif
4498 if (!avail)
4499 {
4500 if (input_available())
4501 return 1;
4502# ifdef FEAT_XCLIPBOARD
4503 if (rest == 0 || !do_xterm_trace())
4504# endif
4505 break;
4506 }
4507 }
4508 while (FALSE
4509# ifdef FEAT_MOUSE_GPM
4510 || (gpm_process_wanted && mch_gpm_process() == 0)
4511# endif
4512# ifdef FEAT_XCLIPBOARD
4513 || (!avail && rest != 0)
4514# endif
4515 );
4516
4517#else
4518 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4519#endif
4520 return avail;
4521}
4522
4523/*
4524 * Wait "msec" msec until a character is available from file descriptor "fd".
4525 * Time == -1 will block forever.
4526 * When a GUI is being used, this will not be used for input -- webb
4527 * Returns also, when a request from Sniff is waiting -- toni.
4528 * Or when a Linux GPM mouse event is waiting.
4529 */
4530/* ARGSUSED */
4531#if defined(__BEOS__)
4532 int
4533#else
4534 static int
4535#endif
4536RealWaitForChar(fd, msec, check_for_gpm)
4537 int fd;
4538 long msec;
4539 int *check_for_gpm;
4540{
4541 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004542#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543 static int busy = FALSE;
4544
4545 /* May retry getting characters after an event was handled. */
4546# define MAY_LOOP
4547
4548# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4549 /* Remember at what time we started, so that we know how much longer we
4550 * should wait after being interrupted. */
4551# define USE_START_TV
4552 struct timeval start_tv;
4553
4554 if (msec > 0 && (
4555# ifdef FEAT_XCLIPBOARD
4556 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004557# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558 ||
4559# endif
4560# endif
4561# ifdef USE_XSMP
4562 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004563# ifdef FEAT_MZSCHEME
4564 ||
4565# endif
4566# endif
4567# ifdef FEAT_MZSCHEME
4568 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004569# endif
4570 ))
4571 gettimeofday(&start_tv, NULL);
4572# endif
4573
4574 /* Handle being called recursively. This may happen for the session
4575 * manager stuff, it may save the file, which does a breakcheck. */
4576 if (busy)
4577 return 0;
4578#endif
4579
4580#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00004581 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004582#endif
4583 {
4584#ifdef MAY_LOOP
4585 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004586# ifdef FEAT_MZSCHEME
4587 int mzquantum_used = FALSE;
4588# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004589#endif
4590#ifndef HAVE_SELECT
4591 struct pollfd fds[5];
4592 int nfd;
4593# ifdef FEAT_XCLIPBOARD
4594 int xterm_idx = -1;
4595# endif
4596# ifdef FEAT_MOUSE_GPM
4597 int gpm_idx = -1;
4598# endif
4599# ifdef USE_XSMP
4600 int xsmp_idx = -1;
4601# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004602 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004603
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004604# ifdef FEAT_MZSCHEME
4605 mzvim_check_threads();
4606 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4607 {
4608 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4609 mzquantum_used = TRUE;
4610 }
4611# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612 fds[0].fd = fd;
4613 fds[0].events = POLLIN;
4614 nfd = 1;
4615
4616# ifdef FEAT_SNIFF
4617# define SNIFF_IDX 1
4618 if (want_sniff_request)
4619 {
4620 fds[SNIFF_IDX].fd = fd_from_sniff;
4621 fds[SNIFF_IDX].events = POLLIN;
4622 nfd++;
4623 }
4624# endif
4625# ifdef FEAT_XCLIPBOARD
4626 if (xterm_Shell != (Widget)0)
4627 {
4628 xterm_idx = nfd;
4629 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4630 fds[nfd].events = POLLIN;
4631 nfd++;
4632 }
4633# endif
4634# ifdef FEAT_MOUSE_GPM
4635 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4636 {
4637 gpm_idx = nfd;
4638 fds[nfd].fd = gpm_fd;
4639 fds[nfd].events = POLLIN;
4640 nfd++;
4641 }
4642# endif
4643# ifdef USE_XSMP
4644 if (xsmp_icefd != -1)
4645 {
4646 xsmp_idx = nfd;
4647 fds[nfd].fd = xsmp_icefd;
4648 fds[nfd].events = POLLIN;
4649 nfd++;
4650 }
4651# endif
4652
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004653 ret = poll(fds, nfd, towait);
4654# ifdef FEAT_MZSCHEME
4655 if (ret == 0 && mzquantum_used)
4656 /* MzThreads scheduling is required and timeout occured */
4657 finished = FALSE;
4658# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004659
4660# ifdef FEAT_SNIFF
4661 if (ret < 0)
4662 sniff_disconnect(1);
4663 else if (want_sniff_request)
4664 {
4665 if (fds[SNIFF_IDX].revents & POLLHUP)
4666 sniff_disconnect(1);
4667 if (fds[SNIFF_IDX].revents & POLLIN)
4668 sniff_request_waiting = 1;
4669 }
4670# endif
4671# ifdef FEAT_XCLIPBOARD
4672 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4673 {
4674 xterm_update(); /* Maybe we should hand out clipboard */
4675 if (--ret == 0 && !input_available())
4676 /* Try again */
4677 finished = FALSE;
4678 }
4679# endif
4680# ifdef FEAT_MOUSE_GPM
4681 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4682 {
4683 *check_for_gpm = 1;
4684 }
4685# endif
4686# ifdef USE_XSMP
4687 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4688 {
4689 if (fds[xsmp_idx].revents & POLLIN)
4690 {
4691 busy = TRUE;
4692 xsmp_handle_requests();
4693 busy = FALSE;
4694 }
4695 else if (fds[xsmp_idx].revents & POLLHUP)
4696 {
4697 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004698 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004699 xsmp_close();
4700 }
4701 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004702 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004703 }
4704# endif
4705
4706
4707#else /* HAVE_SELECT */
4708
4709 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004710 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004711 fd_set rfds, efds;
4712 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004713 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004715# ifdef FEAT_MZSCHEME
4716 mzvim_check_threads();
4717 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4718 {
4719 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4720 mzquantum_used = TRUE;
4721 }
4722# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004723# ifdef __EMX__
4724 /* don't check for incoming chars if not in raw mode, because select()
4725 * always returns TRUE then (in some version of emx.dll) */
4726 if (curr_tmode != TMODE_RAW)
4727 return 0;
4728# endif
4729
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004730 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004731 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004732 tv.tv_sec = towait / 1000;
4733 tv.tv_usec = (towait % 1000) * (1000000/1000);
4734 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004735 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004736 else
4737 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004738
4739 /*
4740 * Select on ready for reading and exceptional condition (end of file).
4741 */
4742 FD_ZERO(&rfds); /* calls bzero() on a sun */
4743 FD_ZERO(&efds);
4744 FD_SET(fd, &rfds);
4745# if !defined(__QNX__) && !defined(__CYGWIN32__)
4746 /* For QNX select() always returns 1 if this is set. Why? */
4747 FD_SET(fd, &efds);
4748# endif
4749 maxfd = fd;
4750
4751# ifdef FEAT_SNIFF
4752 if (want_sniff_request)
4753 {
4754 FD_SET(fd_from_sniff, &rfds);
4755 FD_SET(fd_from_sniff, &efds);
4756 if (maxfd < fd_from_sniff)
4757 maxfd = fd_from_sniff;
4758 }
4759# endif
4760# ifdef FEAT_XCLIPBOARD
4761 if (xterm_Shell != (Widget)0)
4762 {
4763 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4764 if (maxfd < ConnectionNumber(xterm_dpy))
4765 maxfd = ConnectionNumber(xterm_dpy);
4766 }
4767# endif
4768# ifdef FEAT_MOUSE_GPM
4769 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4770 {
4771 FD_SET(gpm_fd, &rfds);
4772 FD_SET(gpm_fd, &efds);
4773 if (maxfd < gpm_fd)
4774 maxfd = gpm_fd;
4775 }
4776# endif
4777# ifdef USE_XSMP
4778 if (xsmp_icefd != -1)
4779 {
4780 FD_SET(xsmp_icefd, &rfds);
4781 FD_SET(xsmp_icefd, &efds);
4782 if (maxfd < xsmp_icefd)
4783 maxfd = xsmp_icefd;
4784 }
4785# endif
4786
4787# ifdef OLD_VMS
4788 /* Old VMS as v6.2 and older have broken select(). It waits more than
4789 * required. Should not be used */
4790 ret = 0;
4791# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004792 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4793# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00004794# ifdef __TANDEM
4795 if (ret == -1 && errno == ENOTSUP)
4796 {
4797 FD_ZERO(&rfds);
4798 FD_ZERO(&efds);
4799 ret = 0;
4800 }
4801#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004802# ifdef FEAT_MZSCHEME
4803 if (ret == 0 && mzquantum_used)
4804 /* loop if MzThreads must be scheduled and timeout occured */
4805 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004806# endif
4807
4808# ifdef FEAT_SNIFF
4809 if (ret < 0 )
4810 sniff_disconnect(1);
4811 else if (ret > 0 && want_sniff_request)
4812 {
4813 if (FD_ISSET(fd_from_sniff, &efds))
4814 sniff_disconnect(1);
4815 if (FD_ISSET(fd_from_sniff, &rfds))
4816 sniff_request_waiting = 1;
4817 }
4818# endif
4819# ifdef FEAT_XCLIPBOARD
4820 if (ret > 0 && xterm_Shell != (Widget)0
4821 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4822 {
4823 xterm_update(); /* Maybe we should hand out clipboard */
4824 /* continue looping when we only got the X event and the input
4825 * buffer is empty */
4826 if (--ret == 0 && !input_available())
4827 {
4828 /* Try again */
4829 finished = FALSE;
4830 }
4831 }
4832# endif
4833# ifdef FEAT_MOUSE_GPM
4834 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4835 {
4836 if (FD_ISSET(gpm_fd, &efds))
4837 gpm_close();
4838 else if (FD_ISSET(gpm_fd, &rfds))
4839 *check_for_gpm = 1;
4840 }
4841# endif
4842# ifdef USE_XSMP
4843 if (ret > 0 && xsmp_icefd != -1)
4844 {
4845 if (FD_ISSET(xsmp_icefd, &efds))
4846 {
4847 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004848 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004849 xsmp_close();
4850 if (--ret == 0)
4851 finished = FALSE; /* keep going if event was only one */
4852 }
4853 else if (FD_ISSET(xsmp_icefd, &rfds))
4854 {
4855 busy = TRUE;
4856 xsmp_handle_requests();
4857 busy = FALSE;
4858 if (--ret == 0)
4859 finished = FALSE; /* keep going if event was only one */
4860 }
4861 }
4862# endif
4863
4864#endif /* HAVE_SELECT */
4865
4866#ifdef MAY_LOOP
4867 if (finished || msec == 0)
4868 break;
4869
4870 /* We're going to loop around again, find out for how long */
4871 if (msec > 0)
4872 {
4873# ifdef USE_START_TV
4874 struct timeval mtv;
4875
4876 /* Compute remaining wait time. */
4877 gettimeofday(&mtv, NULL);
4878 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
4879 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
4880# else
4881 /* Guess we got interrupted halfway. */
4882 msec = msec / 2;
4883# endif
4884 if (msec <= 0)
4885 break; /* waited long enough */
4886 }
4887#endif
4888 }
4889
4890 return (ret > 0);
4891}
4892
4893#ifndef VMS
4894
4895#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004896/*
Bram Moolenaar02743632005-07-25 20:42:36 +00004897 * Expand a path into all matching files and/or directories. Handles "*",
4898 * "?", "[a-z]", "**", etc.
4899 * "path" has backslashes before chars that are not to be expanded.
4900 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004901 */
4902 int
4903mch_expandpath(gap, path, flags)
4904 garray_T *gap;
4905 char_u *path;
4906 int flags; /* EW_* flags */
4907{
Bram Moolenaar02743632005-07-25 20:42:36 +00004908 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004909}
4910#endif
4911
4912/*
4913 * mch_expand_wildcards() - this code does wild-card pattern matching using
4914 * the shell
4915 *
4916 * return OK for success, FAIL for error (you may lose some memory) and put
4917 * an error message in *file.
4918 *
4919 * num_pat is number of input patterns
4920 * pat is array of pointers to input patterns
4921 * num_file is pointer to number of matched file names
4922 * file is pointer to array of pointers to matched file names
4923 */
4924
4925#ifndef SEEK_SET
4926# define SEEK_SET 0
4927#endif
4928#ifndef SEEK_END
4929# define SEEK_END 2
4930#endif
4931
Bram Moolenaar5555acc2006-04-07 21:33:12 +00004932#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00004933
Bram Moolenaar071d4272004-06-13 20:20:40 +00004934/* ARGSUSED */
4935 int
4936mch_expand_wildcards(num_pat, pat, num_file, file, flags)
4937 int num_pat;
4938 char_u **pat;
4939 int *num_file;
4940 char_u ***file;
4941 int flags; /* EW_* flags */
4942{
4943 int i;
4944 size_t len;
4945 char_u *p;
4946 int dir;
4947#ifdef __EMX__
4948# define EXPL_ALLOC_INC 16
4949 char_u **expl_files;
4950 size_t files_alloced, files_free;
4951 char_u *buf;
4952 int has_wildcard;
4953
4954 *num_file = 0; /* default: no files found */
4955 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
4956 files_free = EXPL_ALLOC_INC; /* how much space is not used */
4957 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
4958 if (*file == NULL)
4959 return FAIL;
4960
4961 for (; num_pat > 0; num_pat--, pat++)
4962 {
4963 expl_files = NULL;
4964 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
4965 /* expand environment var or home dir */
4966 buf = expand_env_save(*pat);
4967 else
4968 buf = vim_strsave(*pat);
4969 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00004970 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004971 if (has_wildcard) /* yes, so expand them */
4972 expl_files = (char_u **)_fnexplode(buf);
4973
4974 /*
4975 * return value of buf if no wildcards left,
4976 * OR if no match AND EW_NOTFOUND is set.
4977 */
4978 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
4979 || (expl_files == NULL && (flags & EW_NOTFOUND)))
4980 { /* simply save the current contents of *buf */
4981 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
4982 if (expl_files != NULL)
4983 {
4984 expl_files[0] = vim_strsave(buf);
4985 expl_files[1] = NULL;
4986 }
4987 }
4988 vim_free(buf);
4989
4990 /*
4991 * Count number of names resulting from expansion,
4992 * At the same time add a backslash to the end of names that happen to
4993 * be directories, and replace slashes with backslashes.
4994 */
4995 if (expl_files)
4996 {
4997 for (i = 0; (p = expl_files[i]) != NULL; i++)
4998 {
4999 dir = mch_isdir(p);
5000 /* If we don't want dirs and this is one, skip it */
5001 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5002 continue;
5003
Bram Moolenaara2031822006-03-07 22:29:51 +00005004 /* Skip files that are not executable if we check for that. */
5005 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
5006 continue;
5007
Bram Moolenaar071d4272004-06-13 20:20:40 +00005008 if (--files_free == 0)
5009 {
5010 /* need more room in table of pointers */
5011 files_alloced += EXPL_ALLOC_INC;
5012 *file = (char_u **)vim_realloc(*file,
5013 sizeof(char_u **) * files_alloced);
5014 if (*file == NULL)
5015 {
5016 EMSG(_(e_outofmem));
5017 *num_file = 0;
5018 return FAIL;
5019 }
5020 files_free = EXPL_ALLOC_INC;
5021 }
5022 slash_adjust(p);
5023 if (dir)
5024 {
5025 /* For a directory we add a '/', unless it's already
5026 * there. */
5027 len = STRLEN(p);
5028 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5029 {
5030 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005031 if (!after_pathsep((*file)[*num_file],
5032 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005033 {
5034 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005035 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005036 }
5037 }
5038 }
5039 else
5040 {
5041 (*file)[*num_file] = vim_strsave(p);
5042 }
5043
5044 /*
5045 * Error message already given by either alloc or vim_strsave.
5046 * Should return FAIL, but returning OK works also.
5047 */
5048 if ((*file)[*num_file] == NULL)
5049 break;
5050 (*num_file)++;
5051 }
5052 _fnexplodefree((char **)expl_files);
5053 }
5054 }
5055 return OK;
5056
5057#else /* __EMX__ */
5058
5059 int j;
5060 char_u *tempname;
5061 char_u *command;
5062 FILE *fd;
5063 char_u *buffer;
5064#define STYLE_ECHO 0 /* use "echo" to expand */
5065#define STYLE_GLOB 1 /* use "glob" to expand, for csh */
5066#define STYLE_PRINT 2 /* use "print -N" to expand, for zsh */
5067#define STYLE_BT 3 /* `cmd` expansion, execute the pattern directly */
5068 int shell_style = STYLE_ECHO;
5069 int check_spaces;
5070 static int did_find_nul = FALSE;
5071 int ampersent = FALSE;
5072
5073 *num_file = 0; /* default: no files found */
5074 *file = NULL;
5075
5076 /*
5077 * If there are no wildcards, just copy the names to allocated memory.
5078 * Saves a lot of time, because we don't have to start a new shell.
5079 */
5080 if (!have_wildcard(num_pat, pat))
5081 return save_patterns(num_pat, pat, num_file, file);
5082
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005083# ifdef HAVE_SANDBOX
5084 /* Don't allow any shell command in the sandbox. */
5085 if (sandbox != 0 && check_secure())
5086 return FAIL;
5087# endif
5088
Bram Moolenaar071d4272004-06-13 20:20:40 +00005089 /*
5090 * Don't allow the use of backticks in secure and restricted mode.
5091 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005092 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005093 for (i = 0; i < num_pat; ++i)
5094 if (vim_strchr(pat[i], '`') != NULL
5095 && (check_restricted() || check_secure()))
5096 return FAIL;
5097
5098 /*
5099 * get a name for the temp file
5100 */
5101 if ((tempname = vim_tempname('o')) == NULL)
5102 {
5103 EMSG(_(e_notmp));
5104 return FAIL;
5105 }
5106
5107 /*
5108 * Let the shell expand the patterns and write the result into the temp
5109 * file. if expanding `cmd` execute it directly.
5110 * If we use csh, glob will work better than echo.
5111 * If we use zsh, print -N will work better than glob.
5112 */
5113 if (num_pat == 1 && *pat[0] == '`'
5114 && (len = STRLEN(pat[0])) > 2
5115 && *(pat[0] + len - 1) == '`')
5116 shell_style = STYLE_BT;
5117 else if ((len = STRLEN(p_sh)) >= 3)
5118 {
5119 if (STRCMP(p_sh + len - 3, "csh") == 0)
5120 shell_style = STYLE_GLOB;
5121 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5122 shell_style = STYLE_PRINT;
5123 }
5124
5125 /* "unset nonomatch; print -N >" plus two is 29 */
5126 len = STRLEN(tempname) + 29;
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005127 for (i = 0; i < num_pat; ++i)
5128 {
5129 /* Count the length of the patterns in the same way as they are put in
5130 * "command" below. */
5131#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005132 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005133#else
5134 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005135 for (j = 0; pat[i][j] != NUL; ++j)
5136 {
5137 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5138 ++len; /* may add a backslash */
5139 ++len;
5140 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005141#endif
5142 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005143 command = alloc(len);
5144 if (command == NULL)
5145 {
5146 /* out of memory */
5147 vim_free(tempname);
5148 return FAIL;
5149 }
5150
5151 /*
5152 * Build the shell command:
5153 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5154 * recognizes this).
5155 * - Add the shell command to print the expanded names.
5156 * - Add the temp file name.
5157 * - Add the file name patterns.
5158 */
5159 if (shell_style == STYLE_BT)
5160 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005161 /* change `command; command& ` to (command; command ) */
5162 STRCPY(command, "(");
5163 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005164 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005165 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005166 while (p > command && vim_iswhite(*p))
5167 --p;
5168 if (*p == '&') /* remove trailing '&' */
5169 {
5170 ampersent = TRUE;
5171 *p = ' ';
5172 }
5173 STRCAT(command, ">");
5174 }
5175 else
5176 {
5177 if (flags & EW_NOTFOUND)
5178 STRCPY(command, "set nonomatch; ");
5179 else
5180 STRCPY(command, "unset nonomatch; ");
5181 if (shell_style == STYLE_GLOB)
5182 STRCAT(command, "glob >");
5183 else if (shell_style == STYLE_PRINT)
5184 STRCAT(command, "print -N >");
5185 else
5186 STRCAT(command, "echo >");
5187 }
5188 STRCAT(command, tempname);
5189 if (shell_style != STYLE_BT)
5190 for (i = 0; i < num_pat; ++i)
5191 {
5192 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005193 * is started twice. Otherwise put a backslash before special
5194 * characters, except insice ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005195#ifdef USE_SYSTEM
5196 STRCAT(command, " \"");
5197 STRCAT(command, pat[i]);
5198 STRCAT(command, "\"");
5199#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005200 int intick = FALSE;
5201
Bram Moolenaar071d4272004-06-13 20:20:40 +00005202 p = command + STRLEN(command);
5203 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005204 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005205 {
5206 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005207 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005208 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5209 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005210 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005211 * backslash inside backticks, before a special character
5212 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005213 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005214 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5215 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005216 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005217 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005218 }
5219 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005220 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005221 /* Put a backslash before a special character, but not
5222 * when inside ``. */
5223 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005224
5225 /* Copy one character. */
5226 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005227 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005228 *p = NUL;
5229#endif
5230 }
5231 if (flags & EW_SILENT)
5232 show_shell_mess = FALSE;
5233 if (ampersent)
5234 STRCAT(command, "&"); /* put the '&' back after the
5235 redirection */
5236
5237 /*
5238 * Using zsh -G: If a pattern has no matches, it is just deleted from
5239 * the argument list, otherwise zsh gives an error message and doesn't
5240 * expand any other pattern.
5241 */
5242 if (shell_style == STYLE_PRINT)
5243 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5244
5245 /*
5246 * If we use -f then shell variables set in .cshrc won't get expanded.
5247 * vi can do it, so we will too, but it is only necessary if there is a "$"
5248 * in one of the patterns, otherwise we can still use the fast option.
5249 */
5250 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5251 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5252
5253 /*
5254 * execute the shell command
5255 */
5256 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5257
5258 /* When running in the background, give it some time to create the temp
5259 * file, but don't wait for it to finish. */
5260 if (ampersent)
5261 mch_delay(10L, TRUE);
5262
5263 extra_shell_arg = NULL; /* cleanup */
5264 show_shell_mess = TRUE;
5265 vim_free(command);
5266
5267 if (i) /* mch_call_shell() failed */
5268 {
5269 mch_remove(tempname);
5270 vim_free(tempname);
5271 /*
5272 * With interactive completion, the error message is not printed.
5273 * However with USE_SYSTEM, I don't know how to turn off error messages
5274 * from the shell, so screen may still get messed up -- webb.
5275 */
5276#ifndef USE_SYSTEM
5277 if (!(flags & EW_SILENT))
5278#endif
5279 {
5280 redraw_later_clear(); /* probably messed up screen */
5281 msg_putchar('\n'); /* clear bottom line quickly */
5282 cmdline_row = Rows - 1; /* continue on last line */
5283#ifdef USE_SYSTEM
5284 if (!(flags & EW_SILENT))
5285#endif
5286 {
5287 MSG(_(e_wildexpand));
5288 msg_start(); /* don't overwrite this message */
5289 }
5290 }
5291 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5292 * EW_NOTFOUND is given */
5293 if (shell_style == STYLE_BT)
5294 return FAIL;
5295 goto notfound;
5296 }
5297
5298 /*
5299 * read the names from the file into memory
5300 */
5301 fd = fopen((char *)tempname, READBIN);
5302 if (fd == NULL)
5303 {
5304 /* Something went wrong, perhaps a file name with a special char. */
5305 if (!(flags & EW_SILENT))
5306 {
5307 MSG(_(e_wildexpand));
5308 msg_start(); /* don't overwrite this message */
5309 }
5310 vim_free(tempname);
5311 goto notfound;
5312 }
5313 fseek(fd, 0L, SEEK_END);
5314 len = ftell(fd); /* get size of temp file */
5315 fseek(fd, 0L, SEEK_SET);
5316 buffer = alloc(len + 1);
5317 if (buffer == NULL)
5318 {
5319 /* out of memory */
5320 mch_remove(tempname);
5321 vim_free(tempname);
5322 fclose(fd);
5323 return FAIL;
5324 }
5325 i = fread((char *)buffer, 1, len, fd);
5326 fclose(fd);
5327 mch_remove(tempname);
5328 if (i != len)
5329 {
5330 /* unexpected read error */
5331 EMSG2(_(e_notread), tempname);
5332 vim_free(tempname);
5333 vim_free(buffer);
5334 return FAIL;
5335 }
5336 vim_free(tempname);
5337
5338#if defined(__CYGWIN__) || defined(__CYGWIN32__)
5339 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5340 p = buffer;
5341 for (i = 0; i < len; ++i)
5342 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5343 *p++ = buffer[i];
5344 len = p - buffer;
5345# endif
5346
5347
5348 /* file names are separated with Space */
5349 if (shell_style == STYLE_ECHO)
5350 {
5351 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5352 p = buffer;
5353 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5354 {
5355 while (*p != ' ' && *p != '\n')
5356 ++p;
5357 p = skipwhite(p); /* skip to next entry */
5358 }
5359 }
5360 /* file names are separated with NL */
5361 else if (shell_style == STYLE_BT)
5362 {
5363 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5364 p = buffer;
5365 for (i = 0; *p != NUL; ++i) /* count number of entries */
5366 {
5367 while (*p != '\n' && *p != NUL)
5368 ++p;
5369 if (*p != NUL)
5370 ++p;
5371 p = skipwhite(p); /* skip leading white space */
5372 }
5373 }
5374 /* file names are separated with NUL */
5375 else
5376 {
5377 /*
5378 * Some versions of zsh use spaces instead of NULs to separate
5379 * results. Only do this when there is no NUL before the end of the
5380 * buffer, otherwise we would never be able to use file names with
5381 * embedded spaces when zsh does use NULs.
5382 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5383 * don't check for spaces again.
5384 */
5385 check_spaces = FALSE;
5386 if (shell_style == STYLE_PRINT && !did_find_nul)
5387 {
5388 /* If there is a NUL, set did_find_nul, else set check_spaces */
5389 if (len && (int)STRLEN(buffer) < len - 1)
5390 did_find_nul = TRUE;
5391 else
5392 check_spaces = TRUE;
5393 }
5394
5395 /*
5396 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5397 * already is one, for STYLE_GLOB it needs to be added.
5398 */
5399 if (len && buffer[len - 1] == NUL)
5400 --len;
5401 else
5402 buffer[len] = NUL;
5403 i = 0;
5404 for (p = buffer; p < buffer + len; ++p)
5405 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5406 {
5407 ++i;
5408 *p = NUL;
5409 }
5410 if (len)
5411 ++i; /* count last entry */
5412 }
5413 if (i == 0)
5414 {
5415 /*
5416 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5417 * /bin/sh will happily expand it to nothing rather than returning an
5418 * error; and hey, it's good to check anyway -- webb.
5419 */
5420 vim_free(buffer);
5421 goto notfound;
5422 }
5423 *num_file = i;
5424 *file = (char_u **)alloc(sizeof(char_u *) * i);
5425 if (*file == NULL)
5426 {
5427 /* out of memory */
5428 vim_free(buffer);
5429 return FAIL;
5430 }
5431
5432 /*
5433 * Isolate the individual file names.
5434 */
5435 p = buffer;
5436 for (i = 0; i < *num_file; ++i)
5437 {
5438 (*file)[i] = p;
5439 /* Space or NL separates */
5440 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT)
5441 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00005442 while (!(shell_style == STYLE_ECHO && *p == ' ')
5443 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005444 ++p;
5445 if (p == buffer + len) /* last entry */
5446 *p = NUL;
5447 else
5448 {
5449 *p++ = NUL;
5450 p = skipwhite(p); /* skip to next entry */
5451 }
5452 }
5453 else /* NUL separates */
5454 {
5455 while (*p && p < buffer + len) /* skip entry */
5456 ++p;
5457 ++p; /* skip NUL */
5458 }
5459 }
5460
5461 /*
5462 * Move the file names to allocated memory.
5463 */
5464 for (j = 0, i = 0; i < *num_file; ++i)
5465 {
5466 /* Require the files to exist. Helps when using /bin/sh */
5467 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5468 continue;
5469
5470 /* check if this entry should be included */
5471 dir = (mch_isdir((*file)[i]));
5472 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5473 continue;
5474
Bram Moolenaara2031822006-03-07 22:29:51 +00005475 /* Skip files that are not executable if we check for that. */
5476 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
5477 continue;
5478
Bram Moolenaar071d4272004-06-13 20:20:40 +00005479 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5480 if (p)
5481 {
5482 STRCPY(p, (*file)[i]);
5483 if (dir)
5484 STRCAT(p, "/"); /* add '/' to a directory name */
5485 (*file)[j++] = p;
5486 }
5487 }
5488 vim_free(buffer);
5489 *num_file = j;
5490
5491 if (*num_file == 0) /* rejected all entries */
5492 {
5493 vim_free(*file);
5494 *file = NULL;
5495 goto notfound;
5496 }
5497
5498 return OK;
5499
5500notfound:
5501 if (flags & EW_NOTFOUND)
5502 return save_patterns(num_pat, pat, num_file, file);
5503 return FAIL;
5504
5505#endif /* __EMX__ */
5506}
5507
5508#endif /* VMS */
5509
5510#ifndef __EMX__
5511 static int
5512save_patterns(num_pat, pat, num_file, file)
5513 int num_pat;
5514 char_u **pat;
5515 int *num_file;
5516 char_u ***file;
5517{
5518 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005519 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005520
5521 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5522 if (*file == NULL)
5523 return FAIL;
5524 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005525 {
5526 s = vim_strsave(pat[i]);
5527 if (s != NULL)
5528 /* Be compatible with expand_filename(): halve the number of
5529 * backslashes. */
5530 backslash_halve(s);
5531 (*file)[i] = s;
5532 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005533 *num_file = num_pat;
5534 return OK;
5535}
5536#endif
5537
5538
5539/*
5540 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5541 * expand.
5542 */
5543 int
5544mch_has_exp_wildcard(p)
5545 char_u *p;
5546{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005547 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005548 {
5549#ifndef OS2
5550 if (*p == '\\' && p[1] != NUL)
5551 ++p;
5552 else
5553#endif
5554 if (vim_strchr((char_u *)
5555#ifdef VMS
5556 "*?%"
5557#else
5558# ifdef OS2
5559 "*?"
5560# else
5561 "*?[{'"
5562# endif
5563#endif
5564 , *p) != NULL)
5565 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005566 }
5567 return FALSE;
5568}
5569
5570/*
5571 * Return TRUE if the string "p" contains a wildcard.
5572 * Don't recognize '~' at the end as a wildcard.
5573 */
5574 int
5575mch_has_wildcard(p)
5576 char_u *p;
5577{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005578 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005579 {
5580#ifndef OS2
5581 if (*p == '\\' && p[1] != NUL)
5582 ++p;
5583 else
5584#endif
5585 if (vim_strchr((char_u *)
5586#ifdef VMS
5587 "*?%$"
5588#else
5589# ifdef OS2
5590# ifdef VIM_BACKTICK
5591 "*?$`"
5592# else
5593 "*?$"
5594# endif
5595# else
5596 "*?[{`'$"
5597# endif
5598#endif
5599 , *p) != NULL
5600 || (*p == '~' && p[1] != NUL))
5601 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005602 }
5603 return FALSE;
5604}
5605
5606#ifndef __EMX__
5607 static int
5608have_wildcard(num, file)
5609 int num;
5610 char_u **file;
5611{
5612 int i;
5613
5614 for (i = 0; i < num; i++)
5615 if (mch_has_wildcard(file[i]))
5616 return 1;
5617 return 0;
5618}
5619
5620 static int
5621have_dollars(num, file)
5622 int num;
5623 char_u **file;
5624{
5625 int i;
5626
5627 for (i = 0; i < num; i++)
5628 if (vim_strchr(file[i], '$') != NULL)
5629 return TRUE;
5630 return FALSE;
5631}
5632#endif /* ifndef __EMX__ */
5633
5634#ifndef HAVE_RENAME
5635/*
5636 * Scaled-down version of rename(), which is missing in Xenix.
5637 * This version can only move regular files and will fail if the
5638 * destination exists.
5639 */
5640 int
5641mch_rename(src, dest)
5642 const char *src, *dest;
5643{
5644 struct stat st;
5645
5646 if (stat(dest, &st) >= 0) /* fail if destination exists */
5647 return -1;
5648 if (link(src, dest) != 0) /* link file to new name */
5649 return -1;
5650 if (mch_remove(src) == 0) /* delete link to old name */
5651 return 0;
5652 return -1;
5653}
5654#endif /* !HAVE_RENAME */
5655
5656#ifdef FEAT_MOUSE_GPM
5657/*
5658 * Initializes connection with gpm (if it isn't already opened)
5659 * Return 1 if succeeded (or connection already opened), 0 if failed
5660 */
5661 static int
5662gpm_open()
5663{
5664 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5665
5666 if (!gpm_flag)
5667 {
5668 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5669 gpm_connect.defaultMask = ~GPM_HARD;
5670 /* Default handling for mouse move*/
5671 gpm_connect.minMod = 0; /* Handle any modifier keys */
5672 gpm_connect.maxMod = 0xffff;
5673 if (Gpm_Open(&gpm_connect, 0) > 0)
5674 {
5675 /* gpm library tries to handling TSTP causes
5676 * problems. Anyways, we close connection to Gpm whenever
5677 * we are going to suspend or starting an external process
5678 * so we should'nt have problem with this
5679 */
5680 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5681 return 1; /* succeed */
5682 }
5683 if (gpm_fd == -2)
5684 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5685 return 0;
5686 }
5687 return 1; /* already open */
5688}
5689
5690/*
5691 * Closes connection to gpm
Bram Moolenaar1a3d0862007-08-30 09:47:38 +00005692 * returns non-zero if connection successfully closed
Bram Moolenaar071d4272004-06-13 20:20:40 +00005693 */
5694 static void
5695gpm_close()
5696{
5697 if (gpm_flag && gpm_fd >= 0) /* if Open */
5698 Gpm_Close();
5699}
5700
5701/* Reads gpm event and adds special keys to input buf. Returns length of
5702 * generated key sequence.
5703 * This function is made after gui_send_mouse_event
5704 */
5705 static int
5706mch_gpm_process()
5707{
5708 int button;
5709 static Gpm_Event gpm_event;
5710 char_u string[6];
5711 int_u vim_modifiers;
5712 int row,col;
5713 unsigned char buttons_mask;
5714 unsigned char gpm_modifiers;
5715 static unsigned char old_buttons = 0;
5716
5717 Gpm_GetEvent(&gpm_event);
5718
5719#ifdef FEAT_GUI
5720 /* Don't put events in the input queue now. */
5721 if (hold_gui_events)
5722 return 0;
5723#endif
5724
5725 row = gpm_event.y - 1;
5726 col = gpm_event.x - 1;
5727
5728 string[0] = ESC; /* Our termcode */
5729 string[1] = 'M';
5730 string[2] = 'G';
5731 switch (GPM_BARE_EVENTS(gpm_event.type))
5732 {
5733 case GPM_DRAG:
5734 string[3] = MOUSE_DRAG;
5735 break;
5736 case GPM_DOWN:
5737 buttons_mask = gpm_event.buttons & ~old_buttons;
5738 old_buttons = gpm_event.buttons;
5739 switch (buttons_mask)
5740 {
5741 case GPM_B_LEFT:
5742 button = MOUSE_LEFT;
5743 break;
5744 case GPM_B_MIDDLE:
5745 button = MOUSE_MIDDLE;
5746 break;
5747 case GPM_B_RIGHT:
5748 button = MOUSE_RIGHT;
5749 break;
5750 default:
5751 return 0;
5752 /*Don't know what to do. Can more than one button be
5753 * reported in one event? */
5754 }
5755 string[3] = (char_u)(button | 0x20);
5756 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5757 break;
5758 case GPM_UP:
5759 string[3] = MOUSE_RELEASE;
5760 old_buttons &= ~gpm_event.buttons;
5761 break;
5762 default:
5763 return 0;
5764 }
5765 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5766 gpm_modifiers = gpm_event.modifiers;
5767 vim_modifiers = 0x0;
5768 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5769 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5770 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5771 */
5772 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5773 vim_modifiers |= MOUSE_SHIFT;
5774
5775 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5776 vim_modifiers |= MOUSE_CTRL;
5777 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5778 vim_modifiers |= MOUSE_ALT;
5779 string[3] |= vim_modifiers;
5780 string[4] = (char_u)(col + ' ' + 1);
5781 string[5] = (char_u)(row + ' ' + 1);
5782 add_to_input_buf(string, 6);
5783 return 6;
5784}
5785#endif /* FEAT_MOUSE_GPM */
5786
5787#if defined(FEAT_LIBCALL) || defined(PROTO)
5788typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
5789typedef char_u * (*INTPROCSTR)__ARGS((int));
5790typedef int (*STRPROCINT)__ARGS((char_u *));
5791typedef int (*INTPROCINT)__ARGS((int));
5792
5793/*
5794 * Call a DLL routine which takes either a string or int param
5795 * and returns an allocated string.
5796 */
5797 int
5798mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
5799 char_u *libname;
5800 char_u *funcname;
5801 char_u *argstring; /* NULL when using a argint */
5802 int argint;
5803 char_u **string_result;/* NULL when using number_result */
5804 int *number_result;
5805{
5806# if defined(USE_DLOPEN)
5807 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005808 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005809# else
5810 shl_t hinstLib;
5811# endif
5812 STRPROCSTR ProcAdd;
5813 INTPROCSTR ProcAddI;
5814 char_u *retval_str = NULL;
5815 int retval_int = 0;
5816 int success = FALSE;
5817
Bram Moolenaarb39ef122006-06-22 16:19:31 +00005818 /*
5819 * Get a handle to the DLL module.
5820 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005821# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00005822 /* First clear any error, it's not cleared by the dlopen() call. */
5823 (void)dlerror();
5824
Bram Moolenaar071d4272004-06-13 20:20:40 +00005825 hinstLib = dlopen((char *)libname, RTLD_LAZY
5826# ifdef RTLD_LOCAL
5827 | RTLD_LOCAL
5828# endif
5829 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005830 if (hinstLib == NULL)
5831 {
5832 /* "dlerr" must be used before dlclose() */
5833 dlerr = (char *)dlerror();
5834 if (dlerr != NULL)
5835 EMSG2(_("dlerror = \"%s\""), dlerr);
5836 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005837# else
5838 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
5839# endif
5840
5841 /* If the handle is valid, try to get the function address. */
5842 if (hinstLib != NULL)
5843 {
5844# ifdef HAVE_SETJMP_H
5845 /*
5846 * Catch a crash when calling the library function. For example when
5847 * using a number where a string pointer is expected.
5848 */
5849 mch_startjmp();
5850 if (SETJMP(lc_jump_env) != 0)
5851 {
5852 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00005853# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005854 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00005855# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005856 mch_didjmp();
5857 }
5858 else
5859# endif
5860 {
5861 retval_str = NULL;
5862 retval_int = 0;
5863
5864 if (argstring != NULL)
5865 {
5866# if defined(USE_DLOPEN)
5867 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005868 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005869# else
5870 if (shl_findsym(&hinstLib, (const char *)funcname,
5871 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
5872 ProcAdd = NULL;
5873# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005874 if ((success = (ProcAdd != NULL
5875# if defined(USE_DLOPEN)
5876 && dlerr == NULL
5877# endif
5878 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005879 {
5880 if (string_result == NULL)
5881 retval_int = ((STRPROCINT)ProcAdd)(argstring);
5882 else
5883 retval_str = (ProcAdd)(argstring);
5884 }
5885 }
5886 else
5887 {
5888# if defined(USE_DLOPEN)
5889 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005890 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005891# else
5892 if (shl_findsym(&hinstLib, (const char *)funcname,
5893 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
5894 ProcAddI = NULL;
5895# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005896 if ((success = (ProcAddI != NULL
5897# if defined(USE_DLOPEN)
5898 && dlerr == NULL
5899# endif
5900 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005901 {
5902 if (string_result == NULL)
5903 retval_int = ((INTPROCINT)ProcAddI)(argint);
5904 else
5905 retval_str = (ProcAddI)(argint);
5906 }
5907 }
5908
5909 /* Save the string before we free the library. */
5910 /* Assume that a "1" or "-1" result is an illegal pointer. */
5911 if (string_result == NULL)
5912 *number_result = retval_int;
5913 else if (retval_str != NULL
5914 && retval_str != (char_u *)1
5915 && retval_str != (char_u *)-1)
5916 *string_result = vim_strsave(retval_str);
5917 }
5918
5919# ifdef HAVE_SETJMP_H
5920 mch_endjmp();
5921# ifdef SIGHASARG
5922 if (lc_signal != 0)
5923 {
5924 int i;
5925
5926 /* try to find the name of this signal */
5927 for (i = 0; signal_info[i].sig != -1; i++)
5928 if (lc_signal == signal_info[i].sig)
5929 break;
5930 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
5931 }
5932# endif
5933# endif
5934
Bram Moolenaar071d4272004-06-13 20:20:40 +00005935# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005936 /* "dlerr" must be used before dlclose() */
5937 if (dlerr != NULL)
5938 EMSG2(_("dlerror = \"%s\""), dlerr);
5939
5940 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005941 (void)dlclose(hinstLib);
5942# else
5943 (void)shl_unload(hinstLib);
5944# endif
5945 }
5946
5947 if (!success)
5948 {
5949 EMSG2(_(e_libcall), funcname);
5950 return FAIL;
5951 }
5952
5953 return OK;
5954}
5955#endif
5956
5957#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
5958static int xterm_trace = -1; /* default: disabled */
5959static int xterm_button;
5960
5961/*
5962 * Setup a dummy window for X selections in a terminal.
5963 */
5964 void
5965setup_term_clip()
5966{
5967 int z = 0;
5968 char *strp = "";
5969 Widget AppShell;
5970
5971 if (!x_connect_to_server())
5972 return;
5973
5974 open_app_context();
5975 if (app_context != NULL && xterm_Shell == (Widget)0)
5976 {
5977 int (*oldhandler)();
5978#if defined(HAVE_SETJMP_H)
5979 int (*oldIOhandler)();
5980#endif
5981# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5982 struct timeval start_tv;
5983
5984 if (p_verbose > 0)
5985 gettimeofday(&start_tv, NULL);
5986# endif
5987
5988 /* Ignore X errors while opening the display */
5989 oldhandler = XSetErrorHandler(x_error_check);
5990
5991#if defined(HAVE_SETJMP_H)
5992 /* Ignore X IO errors while opening the display */
5993 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
5994 mch_startjmp();
5995 if (SETJMP(lc_jump_env) != 0)
5996 {
5997 mch_didjmp();
5998 xterm_dpy = NULL;
5999 }
6000 else
6001#endif
6002 {
6003 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6004 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6005#if defined(HAVE_SETJMP_H)
6006 mch_endjmp();
6007#endif
6008 }
6009
6010#if defined(HAVE_SETJMP_H)
6011 /* Now handle X IO errors normally. */
6012 (void)XSetIOErrorHandler(oldIOhandler);
6013#endif
6014 /* Now handle X errors normally. */
6015 (void)XSetErrorHandler(oldhandler);
6016
6017 if (xterm_dpy == NULL)
6018 {
6019 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006020 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006021 return;
6022 }
6023
6024 /* Catch terminating error of the X server connection. */
6025 (void)XSetIOErrorHandler(x_IOerror_handler);
6026
6027# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6028 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006029 {
6030 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006031 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006032 verbose_leave();
6033 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006034# endif
6035
6036 /* Create a Shell to make converters work. */
6037 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6038 applicationShellWidgetClass, xterm_dpy,
6039 NULL);
6040 if (AppShell == (Widget)0)
6041 return;
6042 xterm_Shell = XtVaCreatePopupShell("VIM",
6043 topLevelShellWidgetClass, AppShell,
6044 XtNmappedWhenManaged, 0,
6045 XtNwidth, 1,
6046 XtNheight, 1,
6047 NULL);
6048 if (xterm_Shell == (Widget)0)
6049 return;
6050
6051 x11_setup_atoms(xterm_dpy);
6052 if (x11_display == NULL)
6053 x11_display = xterm_dpy;
6054
6055 XtRealizeWidget(xterm_Shell);
6056 XSync(xterm_dpy, False);
6057 xterm_update();
6058 }
6059 if (xterm_Shell != (Widget)0)
6060 {
6061 clip_init(TRUE);
6062 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6063 x11_window = (Window)atol(strp);
6064 /* Check if $WINDOWID is valid. */
6065 if (test_x11_window(xterm_dpy) == FAIL)
6066 x11_window = 0;
6067 if (x11_window != 0)
6068 xterm_trace = 0;
6069 }
6070}
6071
6072 void
6073start_xterm_trace(button)
6074 int button;
6075{
6076 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6077 return;
6078 xterm_trace = 1;
6079 xterm_button = button;
6080 do_xterm_trace();
6081}
6082
6083
6084 void
6085stop_xterm_trace()
6086{
6087 if (xterm_trace < 0)
6088 return;
6089 xterm_trace = 0;
6090}
6091
6092/*
6093 * Query the xterm pointer and generate mouse termcodes if necessary
6094 * return TRUE if dragging is active, else FALSE
6095 */
6096 static int
6097do_xterm_trace()
6098{
6099 Window root, child;
6100 int root_x, root_y;
6101 int win_x, win_y;
6102 int row, col;
6103 int_u mask_return;
6104 char_u buf[50];
6105 char_u *strp;
6106 long got_hints;
6107 static char_u *mouse_code;
6108 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6109 static int prev_row = 0, prev_col = 0;
6110 static XSizeHints xterm_hints;
6111
6112 if (xterm_trace <= 0)
6113 return FALSE;
6114
6115 if (xterm_trace == 1)
6116 {
6117 /* Get the hints just before tracking starts. The font size might
6118 * have changed recently */
6119 XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints);
6120 if (!(got_hints & PResizeInc)
6121 || xterm_hints.width_inc <= 1
6122 || xterm_hints.height_inc <= 1)
6123 {
6124 xterm_trace = -1; /* Not enough data -- disable tracing */
6125 return FALSE;
6126 }
6127
6128 /* Rely on the same mouse code for the duration of this */
6129 mouse_code = find_termcode(mouse_name);
6130 prev_row = mouse_row;
6131 prev_row = mouse_col;
6132 xterm_trace = 2;
6133
6134 /* Find the offset of the chars, there might be a scrollbar on the
6135 * left of the window and/or a menu on the top (eterm etc.) */
6136 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6137 &win_x, &win_y, &mask_return);
6138 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6139 - (xterm_hints.height_inc / 2);
6140 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6141 xterm_hints.y = 2;
6142 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6143 - (xterm_hints.width_inc / 2);
6144 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6145 xterm_hints.x = 2;
6146 return TRUE;
6147 }
6148 if (mouse_code == NULL)
6149 {
6150 xterm_trace = 0;
6151 return FALSE;
6152 }
6153
6154 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6155 &win_x, &win_y, &mask_return);
6156
6157 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6158 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6159 if (row == prev_row && col == prev_col)
6160 return TRUE;
6161
6162 STRCPY(buf, mouse_code);
6163 strp = buf + STRLEN(buf);
6164 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6165 *strp++ = (char_u)(col + ' ' + 1);
6166 *strp++ = (char_u)(row + ' ' + 1);
6167 *strp = 0;
6168 add_to_input_buf(buf, STRLEN(buf));
6169
6170 prev_row = row;
6171 prev_col = col;
6172 return TRUE;
6173}
6174
6175# if defined(FEAT_GUI) || defined(PROTO)
6176/*
6177 * Destroy the display, window and app_context. Required for GTK.
6178 */
6179 void
6180clear_xterm_clip()
6181{
6182 if (xterm_Shell != (Widget)0)
6183 {
6184 XtDestroyWidget(xterm_Shell);
6185 xterm_Shell = (Widget)0;
6186 }
6187 if (xterm_dpy != NULL)
6188 {
6189#if 0
6190 /* Lesstif and Solaris crash here, lose some memory */
6191 XtCloseDisplay(xterm_dpy);
6192#endif
6193 if (x11_display == xterm_dpy)
6194 x11_display = NULL;
6195 xterm_dpy = NULL;
6196 }
6197#if 0
6198 if (app_context != (XtAppContext)NULL)
6199 {
6200 /* Lesstif and Solaris crash here, lose some memory */
6201 XtDestroyApplicationContext(app_context);
6202 app_context = (XtAppContext)NULL;
6203 }
6204#endif
6205}
6206# endif
6207
6208/*
6209 * Catch up with any queued X events. This may put keyboard input into the
6210 * input buffer, call resize call-backs, trigger timers etc. If there is
6211 * nothing in the X event queue (& no timers pending), then we return
6212 * immediately.
6213 */
6214 static void
6215xterm_update()
6216{
6217 XEvent event;
6218
6219 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6220 {
6221 XtAppNextEvent(app_context, &event);
6222#ifdef FEAT_CLIENTSERVER
6223 {
6224 XPropertyEvent *e = (XPropertyEvent *)&event;
6225
6226 if (e->type == PropertyNotify && e->window == commWindow
6227 && e->atom == commProperty && e->state == PropertyNewValue)
6228 serverEventProc(xterm_dpy, &event);
6229 }
6230#endif
6231 XtDispatchEvent(&event);
6232 }
6233}
6234
6235 int
6236clip_xterm_own_selection(cbd)
6237 VimClipboard *cbd;
6238{
6239 if (xterm_Shell != (Widget)0)
6240 return clip_x11_own_selection(xterm_Shell, cbd);
6241 return FAIL;
6242}
6243
6244 void
6245clip_xterm_lose_selection(cbd)
6246 VimClipboard *cbd;
6247{
6248 if (xterm_Shell != (Widget)0)
6249 clip_x11_lose_selection(xterm_Shell, cbd);
6250}
6251
6252 void
6253clip_xterm_request_selection(cbd)
6254 VimClipboard *cbd;
6255{
6256 if (xterm_Shell != (Widget)0)
6257 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6258}
6259
6260 void
6261clip_xterm_set_selection(cbd)
6262 VimClipboard *cbd;
6263{
6264 clip_x11_set_selection(cbd);
6265}
6266#endif
6267
6268
6269#if defined(USE_XSMP) || defined(PROTO)
6270/*
6271 * Code for X Session Management Protocol.
6272 */
6273static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6274static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6275static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6276static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6277static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6278
6279
6280# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6281static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6282
6283/*
6284 * This is our chance to ask the user if they want to save,
6285 * or abort the logout
6286 */
6287/*ARGSUSED*/
6288 static void
6289xsmp_handle_interaction(smc_conn, client_data)
6290 SmcConn smc_conn;
6291 SmPointer client_data;
6292{
6293 cmdmod_T save_cmdmod;
6294 int cancel_shutdown = False;
6295
6296 save_cmdmod = cmdmod;
6297 cmdmod.confirm = TRUE;
6298 if (check_changed_any(FALSE))
6299 /* Mustn't logout */
6300 cancel_shutdown = True;
6301 cmdmod = save_cmdmod;
6302 setcursor(); /* position cursor */
6303 out_flush();
6304
6305 /* Done interaction */
6306 SmcInteractDone(smc_conn, cancel_shutdown);
6307
6308 /* Finish off
6309 * Only end save-yourself here if we're not cancelling shutdown;
6310 * we'll get a cancelled callback later in which we'll end it.
6311 * Hopefully get around glitchy SMs (like GNOME-1)
6312 */
6313 if (!cancel_shutdown)
6314 {
6315 xsmp.save_yourself = False;
6316 SmcSaveYourselfDone(smc_conn, True);
6317 }
6318}
6319# endif
6320
6321/*
6322 * Callback that starts save-yourself.
6323 */
6324/*ARGSUSED*/
6325 static void
6326xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6327 shutdown, interact_style, fast)
6328 SmcConn smc_conn;
6329 SmPointer client_data;
6330 int save_type;
6331 Bool shutdown;
6332 int interact_style;
6333 Bool fast;
6334{
6335 /* Handle already being in saveyourself */
6336 if (xsmp.save_yourself)
6337 SmcSaveYourselfDone(smc_conn, True);
6338 xsmp.save_yourself = True;
6339 xsmp.shutdown = shutdown;
6340
6341 /* First up, preserve all files */
6342 out_flush();
6343 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6344
6345 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006346 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006347
6348# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6349 /* Now see if we can ask about unsaved files */
6350 if (shutdown && !fast && gui.in_use)
6351 /* Need to interact with user, but need SM's permission */
6352 SmcInteractRequest(smc_conn, SmDialogError,
6353 xsmp_handle_interaction, client_data);
6354 else
6355# endif
6356 {
6357 /* Can stop the cycle here */
6358 SmcSaveYourselfDone(smc_conn, True);
6359 xsmp.save_yourself = False;
6360 }
6361}
6362
6363
6364/*
6365 * Callback to warn us of imminent death.
6366 */
6367/*ARGSUSED*/
6368 static void
6369xsmp_die(smc_conn, client_data)
6370 SmcConn smc_conn;
6371 SmPointer client_data;
6372{
6373 xsmp_close();
6374
6375 /* quit quickly leaving swapfiles for modified buffers behind */
6376 getout_preserve_modified(0);
6377}
6378
6379
6380/*
6381 * Callback to tell us that save-yourself has completed.
6382 */
6383/*ARGSUSED*/
6384 static void
6385xsmp_save_complete(smc_conn, client_data)
6386 SmcConn smc_conn;
6387 SmPointer client_data;
6388{
6389 xsmp.save_yourself = False;
6390}
6391
6392
6393/*
6394 * Callback to tell us that an instigated shutdown was cancelled
6395 * (maybe even by us)
6396 */
6397/*ARGSUSED*/
6398 static void
6399xsmp_shutdown_cancelled(smc_conn, client_data)
6400 SmcConn smc_conn;
6401 SmPointer client_data;
6402{
6403 if (xsmp.save_yourself)
6404 SmcSaveYourselfDone(smc_conn, True);
6405 xsmp.save_yourself = False;
6406 xsmp.shutdown = False;
6407}
6408
6409
6410/*
6411 * Callback to tell us that a new ICE connection has been established.
6412 */
6413/*ARGSUSED*/
6414 static void
6415xsmp_ice_connection(iceConn, clientData, opening, watchData)
6416 IceConn iceConn;
6417 IcePointer clientData;
6418 Bool opening;
6419 IcePointer *watchData;
6420{
6421 /* Intercept creation of ICE connection fd */
6422 if (opening)
6423 {
6424 xsmp_icefd = IceConnectionNumber(iceConn);
6425 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6426 }
6427}
6428
6429
6430/* Handle any ICE processing that's required; return FAIL if SM lost */
6431 int
6432xsmp_handle_requests()
6433{
6434 Bool rep;
6435
6436 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6437 == IceProcessMessagesIOError)
6438 {
6439 /* Lost ICE */
6440 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006441 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006442 xsmp_close();
6443 return FAIL;
6444 }
6445 else
6446 return OK;
6447}
6448
6449static int dummy;
6450
6451/* Set up X Session Management Protocol */
6452 void
6453xsmp_init(void)
6454{
6455 char errorstring[80];
6456 char *clientid;
6457 SmcCallbacks smcallbacks;
6458#if 0
6459 SmPropValue smname;
6460 SmProp smnameprop;
6461 SmProp *smprops[1];
6462#endif
6463
6464 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006465 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006466
6467 xsmp.save_yourself = xsmp.shutdown = False;
6468
6469 /* Set up SM callbacks - must have all, even if they're not used */
6470 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6471 smcallbacks.save_yourself.client_data = NULL;
6472 smcallbacks.die.callback = xsmp_die;
6473 smcallbacks.die.client_data = NULL;
6474 smcallbacks.save_complete.callback = xsmp_save_complete;
6475 smcallbacks.save_complete.client_data = NULL;
6476 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6477 smcallbacks.shutdown_cancelled.client_data = NULL;
6478
6479 /* Set up a watch on ICE connection creations. The "dummy" argument is
6480 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6481 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6482 {
6483 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006484 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006485 return;
6486 }
6487
6488 /* Create an SM connection */
6489 xsmp.smcconn = SmcOpenConnection(
6490 NULL,
6491 NULL,
6492 SmProtoMajor,
6493 SmProtoMinor,
6494 SmcSaveYourselfProcMask | SmcDieProcMask
6495 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6496 &smcallbacks,
6497 NULL,
6498 &clientid,
6499 sizeof(errorstring),
6500 errorstring);
6501 if (xsmp.smcconn == NULL)
6502 {
6503 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00006504
Bram Moolenaar071d4272004-06-13 20:20:40 +00006505 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006506 {
6507 vim_snprintf(errorreport, sizeof(errorreport),
6508 _("XSMP SmcOpenConnection failed: %s"), errorstring);
6509 verb_msg((char_u *)errorreport);
6510 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006511 return;
6512 }
6513 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6514
6515#if 0
6516 /* ID ourselves */
6517 smname.value = "vim";
6518 smname.length = 3;
6519 smnameprop.name = "SmProgram";
6520 smnameprop.type = "SmARRAY8";
6521 smnameprop.num_vals = 1;
6522 smnameprop.vals = &smname;
6523
6524 smprops[0] = &smnameprop;
6525 SmcSetProperties(xsmp.smcconn, 1, smprops);
6526#endif
6527}
6528
6529
6530/* Shut down XSMP comms. */
6531 void
6532xsmp_close()
6533{
6534 if (xsmp_icefd != -1)
6535 {
6536 SmcCloseConnection(xsmp.smcconn, 0, NULL);
6537 xsmp_icefd = -1;
6538 }
6539}
6540#endif /* USE_XSMP */
6541
6542
6543#ifdef EBCDIC
6544/* Translate character to its CTRL- value */
6545char CtrlTable[] =
6546{
6547/* 00 - 5E */
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, 0,
6553 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6554/* ^ */ 0x1E,
6555/* - */ 0x1F,
6556/* 61 - 6C */
6557 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6558/* _ */ 0x1F,
6559/* 6E - 80 */
6560 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6561/* a */ 0x01,
6562/* b */ 0x02,
6563/* c */ 0x03,
6564/* d */ 0x37,
6565/* e */ 0x2D,
6566/* f */ 0x2E,
6567/* g */ 0x2F,
6568/* h */ 0x16,
6569/* i */ 0x05,
6570/* 8A - 90 */
6571 0, 0, 0, 0, 0, 0, 0,
6572/* j */ 0x15,
6573/* k */ 0x0B,
6574/* l */ 0x0C,
6575/* m */ 0x0D,
6576/* n */ 0x0E,
6577/* o */ 0x0F,
6578/* p */ 0x10,
6579/* q */ 0x11,
6580/* r */ 0x12,
6581/* 9A - A1 */
6582 0, 0, 0, 0, 0, 0, 0, 0,
6583/* s */ 0x13,
6584/* t */ 0x3C,
6585/* u */ 0x3D,
6586/* v */ 0x32,
6587/* w */ 0x26,
6588/* x */ 0x18,
6589/* y */ 0x19,
6590/* z */ 0x3F,
6591/* AA - AC */
6592 0, 0, 0,
6593/* [ */ 0x27,
6594/* AE - BC */
6595 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6596/* ] */ 0x1D,
6597/* BE - C0 */ 0, 0, 0,
6598/* A */ 0x01,
6599/* B */ 0x02,
6600/* C */ 0x03,
6601/* D */ 0x37,
6602/* E */ 0x2D,
6603/* F */ 0x2E,
6604/* G */ 0x2F,
6605/* H */ 0x16,
6606/* I */ 0x05,
6607/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6608/* J */ 0x15,
6609/* K */ 0x0B,
6610/* L */ 0x0C,
6611/* M */ 0x0D,
6612/* N */ 0x0E,
6613/* O */ 0x0F,
6614/* P */ 0x10,
6615/* Q */ 0x11,
6616/* R */ 0x12,
6617/* DA - DF */ 0, 0, 0, 0, 0, 0,
6618/* \ */ 0x1C,
6619/* E1 */ 0,
6620/* S */ 0x13,
6621/* T */ 0x3C,
6622/* U */ 0x3D,
6623/* V */ 0x32,
6624/* W */ 0x26,
6625/* X */ 0x18,
6626/* Y */ 0x19,
6627/* Z */ 0x3F,
6628/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6629 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6630};
6631
6632char MetaCharTable[]=
6633{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6634 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6635 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6636 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6637 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6638};
6639
6640
6641/* TODO: Use characters NOT numbers!!! */
6642char CtrlCharTable[]=
6643{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6644 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6645 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6646 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6647 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6648};
6649
6650
6651#endif