blob: a188452917487e07d71ed70140c88137f37877db [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 {
493 pagesize = pagesize >> 1;
494 --shiftright;
495 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496 mem = (long_u)pagesize * pagecount;
Bram Moolenaar914572a2007-05-01 11:37:47 +0000497 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 }
499# endif
500
501 /* Return the minimum of the physical memory and the user limit, because
502 * using more than the user limit may cause Vim to be terminated. */
503# if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT)
504 {
505 struct rlimit rlp;
506
507 if (getrlimit(RLIMIT_DATA, &rlp) == 0
508 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
509# ifdef RLIM_INFINITY
510 && rlp.rlim_cur != RLIM_INFINITY
511# endif
Bram Moolenaar914572a2007-05-01 11:37:47 +0000512 && ((long_u)rlp.rlim_cur >> 10) < (mem >> shiftright)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513 )
Bram Moolenaar914572a2007-05-01 11:37:47 +0000514 {
515 mem = (long_u)rlp.rlim_cur;
516 shiftright = 10;
517 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000518 }
519# endif
520
521 if (mem > 0)
Bram Moolenaar914572a2007-05-01 11:37:47 +0000522 return mem >> shiftright;
523 return (long_u)0x1fffff;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000524# endif
525}
526#endif
527
528 void
529mch_delay(msec, ignoreinput)
530 long msec;
531 int ignoreinput;
532{
533 int old_tmode;
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000534#ifdef FEAT_MZSCHEME
535 long total = msec; /* remember original value */
536#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000537
538 if (ignoreinput)
539 {
540 /* Go to cooked mode without echo, to allow SIGINT interrupting us
541 * here */
542 old_tmode = curr_tmode;
543 if (curr_tmode == TMODE_RAW)
544 settmode(TMODE_SLEEP);
545
546 /*
547 * Everybody sleeps in a different way...
548 * Prefer nanosleep(), some versions of usleep() can only sleep up to
549 * one second.
550 */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000551#ifdef FEAT_MZSCHEME
552 do
553 {
554 /* if total is large enough, wait by portions in p_mzq */
555 if (total > p_mzq)
556 msec = p_mzq;
557 else
558 msec = total;
559 total -= msec;
560#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000561#ifdef HAVE_NANOSLEEP
562 {
563 struct timespec ts;
564
565 ts.tv_sec = msec / 1000;
566 ts.tv_nsec = (msec % 1000) * 1000000;
567 (void)nanosleep(&ts, NULL);
568 }
569#else
570# ifdef HAVE_USLEEP
571 while (msec >= 1000)
572 {
573 usleep((unsigned int)(999 * 1000));
574 msec -= 999;
575 }
576 usleep((unsigned int)(msec * 1000));
577# else
578# ifndef HAVE_SELECT
579 poll(NULL, 0, (int)msec);
580# else
581# ifdef __EMX__
582 _sleep2(msec);
583# else
584 {
585 struct timeval tv;
586
587 tv.tv_sec = msec / 1000;
588 tv.tv_usec = (msec % 1000) * 1000;
589 /*
590 * NOTE: Solaris 2.6 has a bug that makes select() hang here. Get
591 * a patch from Sun to fix this. Reported by Gunnar Pedersen.
592 */
593 select(0, NULL, NULL, NULL, &tv);
594 }
595# endif /* __EMX__ */
596# endif /* HAVE_SELECT */
597# endif /* HAVE_NANOSLEEP */
598#endif /* HAVE_USLEEP */
Bram Moolenaar325b7a22004-07-05 15:58:32 +0000599#ifdef FEAT_MZSCHEME
600 }
601 while (total > 0);
602#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603
604 settmode(old_tmode);
605 }
606 else
607 WaitForChar(msec);
608}
609
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000610#if 0 /* disabled, no longer needed now that regmatch() is not recursive */
611# if defined(HAVE_GETRLIMIT)
612# define HAVE_STACK_LIMIT
613# endif
614#endif
615
616#if defined(HAVE_STACK_LIMIT) \
Bram Moolenaar071d4272004-06-13 20:20:40 +0000617 || (!defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGSTACK))
618# define HAVE_CHECK_STACK_GROWTH
619/*
620 * Support for checking for an almost-out-of-stack-space situation.
621 */
622
623/*
624 * Return a pointer to an item on the stack. Used to find out if the stack
625 * grows up or down.
626 */
627static void check_stack_growth __ARGS((char *p));
628static int stack_grows_downwards;
629
630/*
631 * Find out if the stack grows upwards or downwards.
632 * "p" points to a variable on the stack of the caller.
633 */
634 static void
635check_stack_growth(p)
636 char *p;
637{
638 int i;
639
640 stack_grows_downwards = (p > (char *)&i);
641}
642#endif
643
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000644#if defined(HAVE_STACK_LIMIT) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645static char *stack_limit = NULL;
646
647#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
648# include <pthread.h>
649# include <pthread_np.h>
650#endif
651
652/*
653 * Find out until how var the stack can grow without getting into trouble.
654 * Called when starting up and when switching to the signal stack in
655 * deathtrap().
656 */
657 static void
658get_stack_limit()
659{
660 struct rlimit rlp;
661 int i;
662 long lim;
663
664 /* Set the stack limit to 15/16 of the allowable size. Skip this when the
665 * limit doesn't fit in a long (rlim_cur might be "long long"). */
666 if (getrlimit(RLIMIT_STACK, &rlp) == 0
667 && rlp.rlim_cur < ((rlim_t)1 << (sizeof(long_u) * 8 - 1))
668# ifdef RLIM_INFINITY
669 && rlp.rlim_cur != RLIM_INFINITY
670# endif
671 )
672 {
673 lim = (long)rlp.rlim_cur;
674#if defined(_THREAD_SAFE) && defined(HAVE_PTHREAD_NP_H)
675 {
676 pthread_attr_t attr;
677 size_t size;
678
679 /* On FreeBSD the initial thread always has a fixed stack size, no
680 * matter what the limits are set to. Normally it's 1 Mbyte. */
681 pthread_attr_init(&attr);
682 if (pthread_attr_get_np(pthread_self(), &attr) == 0)
683 {
684 pthread_attr_getstacksize(&attr, &size);
685 if (lim > (long)size)
686 lim = (long)size;
687 }
688 pthread_attr_destroy(&attr);
689 }
690#endif
691 if (stack_grows_downwards)
692 {
693 stack_limit = (char *)((long)&i - (lim / 16L * 15L));
694 if (stack_limit >= (char *)&i)
695 /* overflow, set to 1/16 of current stack position */
696 stack_limit = (char *)((long)&i / 16L);
697 }
698 else
699 {
700 stack_limit = (char *)((long)&i + (lim / 16L * 15L));
701 if (stack_limit <= (char *)&i)
702 stack_limit = NULL; /* overflow */
703 }
704 }
705}
706
707/*
708 * Return FAIL when running out of stack space.
709 * "p" must point to any variable local to the caller that's on the stack.
710 */
711 int
712mch_stackcheck(p)
713 char *p;
714{
715 if (stack_limit != NULL)
716 {
717 if (stack_grows_downwards)
718 {
719 if (p < stack_limit)
720 return FAIL;
721 }
722 else if (p > stack_limit)
723 return FAIL;
724 }
725 return OK;
726}
727#endif
728
729#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
730/*
731 * Support for using the signal stack.
732 * This helps when we run out of stack space, which causes a SIGSEGV. The
733 * signal handler then must run on another stack, since the normal stack is
734 * completely full.
735 */
736
737#ifndef SIGSTKSZ
738# define SIGSTKSZ 8000 /* just a guess of how much stack is needed... */
739#endif
740
741# ifdef HAVE_SIGALTSTACK
742static stack_t sigstk; /* for sigaltstack() */
743# else
744static struct sigstack sigstk; /* for sigstack() */
745# endif
746
747static void init_signal_stack __ARGS((void));
748static char *signal_stack;
749
750 static void
751init_signal_stack()
752{
753 if (signal_stack != NULL)
754 {
755# ifdef HAVE_SIGALTSTACK
756# ifdef __APPLE__
757 /* missing prototype. Adding it to osdef?.h.in doesn't work, because
758 * "struct sigaltstack" needs to be declared. */
759 extern int sigaltstack __ARGS((const struct sigaltstack *ss, struct sigaltstack *oss));
760# endif
761
762# ifdef HAVE_SS_BASE
763 sigstk.ss_base = signal_stack;
764# else
765 sigstk.ss_sp = signal_stack;
766# endif
767 sigstk.ss_size = SIGSTKSZ;
768 sigstk.ss_flags = 0;
769 (void)sigaltstack(&sigstk, NULL);
770# else
771 sigstk.ss_sp = signal_stack;
772 if (stack_grows_downwards)
773 sigstk.ss_sp += SIGSTKSZ - 1;
774 sigstk.ss_onstack = 0;
775 (void)sigstack(&sigstk, NULL);
776# endif
777 }
778}
779#endif
780
781/*
782 * We need correct potatotypes for a signal function, otherwise mean compilers
783 * will barf when the second argument to signal() is ``wrong''.
784 * Let me try it with a few tricky defines from my own osdef.h (jw).
785 */
786#if defined(SIGWINCH)
787/* ARGSUSED */
788 static RETSIGTYPE
789sig_winch SIGDEFARG(sigarg)
790{
791 /* this is not required on all systems, but it doesn't hurt anybody */
792 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
793 do_resize = TRUE;
794 SIGRETURN;
795}
796#endif
797
798#if defined(SIGINT)
799/* ARGSUSED */
800 static RETSIGTYPE
801catch_sigint SIGDEFARG(sigarg)
802{
803 /* this is not required on all systems, but it doesn't hurt anybody */
804 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
805 got_int = TRUE;
806 SIGRETURN;
807}
808#endif
809
810#if defined(SIGPWR)
811/* ARGSUSED */
812 static RETSIGTYPE
813catch_sigpwr SIGDEFARG(sigarg)
814{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000815 /* this is not required on all systems, but it doesn't hurt anybody */
816 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000817 /*
818 * I'm not sure we get the SIGPWR signal when the system is really going
819 * down or when the batteries are almost empty. Just preserve the swap
820 * files and don't exit, that can't do any harm.
821 */
822 ml_sync_all(FALSE, FALSE);
823 SIGRETURN;
824}
825#endif
826
827#ifdef SET_SIG_ALARM
828/*
829 * signal function for alarm().
830 */
831/* ARGSUSED */
832 static RETSIGTYPE
833sig_alarm SIGDEFARG(sigarg)
834{
835 /* doesn't do anything, just to break a system call */
836 sig_alarm_called = TRUE;
837 SIGRETURN;
838}
839#endif
840
Bram Moolenaar44ecf652005-03-07 23:09:59 +0000841#if (defined(HAVE_SETJMP_H) \
842 && ((defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) \
843 || defined(FEAT_LIBCALL))) \
844 || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845/*
846 * A simplistic version of setjmp() that only allows one level of using.
847 * Don't call twice before calling mch_endjmp()!.
848 * Usage:
849 * mch_startjmp();
850 * if (SETJMP(lc_jump_env) != 0)
851 * {
852 * mch_didjmp();
853 * EMSG("crash!");
854 * }
855 * else
856 * {
857 * do_the_work;
858 * mch_endjmp();
859 * }
860 * Note: Can't move SETJMP() here, because a function calling setjmp() must
861 * not return before the saved environment is used.
862 * Returns OK for normal return, FAIL when the protected code caused a
863 * problem and LONGJMP() was used.
864 */
865 void
866mch_startjmp()
867{
868#ifdef SIGHASARG
869 lc_signal = 0;
870#endif
871 lc_active = TRUE;
872}
873
874 void
875mch_endjmp()
876{
877 lc_active = FALSE;
878}
879
880 void
881mch_didjmp()
882{
883# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
884 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
885 * otherwise catching the signal only works once. */
886 init_signal_stack();
887# endif
888}
889#endif
890
891/*
892 * This function handles deadly signals.
893 * It tries to preserve any swap file and exit properly.
894 * (partly from Elvis).
895 */
896 static RETSIGTYPE
897deathtrap SIGDEFARG(sigarg)
898{
899 static int entered = 0; /* count the number of times we got here.
900 Note: when memory has been corrupted
901 this may get an arbitrary value! */
902#ifdef SIGHASARG
903 int i;
904#endif
905
906#if defined(HAVE_SETJMP_H)
907 /*
908 * Catch a crash in protected code.
909 * Restores the environment saved in lc_jump_env, which looks like
910 * SETJMP() returns 1.
911 */
912 if (lc_active)
913 {
914# if defined(SIGHASARG)
915 lc_signal = sigarg;
916# endif
917 lc_active = FALSE; /* don't jump again */
918 LONGJMP(lc_jump_env, 1);
919 /* NOTREACHED */
920 }
921#endif
922
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000923#ifdef SIGHASARG
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000924 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
925 * here. This avoids that a non-reentrant function is interrupted, e.g.,
926 * free(). Calling free() again may then cause a crash. */
927 if (entered == 0
928 && (0
929# ifdef SIGHUP
930 || sigarg == SIGHUP
931# endif
932# ifdef SIGQUIT
933 || sigarg == SIGQUIT
934# endif
935# ifdef SIGTERM
936 || sigarg == SIGTERM
937# endif
938# ifdef SIGPWR
939 || sigarg == SIGPWR
940# endif
941# ifdef SIGUSR1
942 || sigarg == SIGUSR1
943# endif
944# ifdef SIGUSR2
945 || sigarg == SIGUSR2
946# endif
947 )
Bram Moolenaar1f28b072005-07-12 22:42:41 +0000948 && !vim_handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000949 SIGRETURN;
950#endif
951
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952 /* Remember how often we have been called. */
953 ++entered;
954
955#ifdef FEAT_EVAL
956 /* Set the v:dying variable. */
957 set_vim_var_nr(VV_DYING, (long)entered);
958#endif
959
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000960#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +0000961 /* Since we are now using the signal stack, need to reset the stack
962 * limit. Otherwise using a regexp will fail. */
963 get_stack_limit();
964#endif
965
Bram Moolenaar1f4d4de2006-03-14 23:00:46 +0000966#if 0
967 /* This is for opening gdb the moment Vim crashes.
968 * You need to manually adjust the file name and Vim executable name.
969 * Suggested by SungHyun Nam. */
970 {
971# define VI_GDB_FILE "/tmp/vimgdb"
972# define VIM_NAME "/usr/bin/vim"
973 FILE *fp = fopen(VI_GDB_FILE, "w");
974 if (fp)
975 {
976 fprintf(fp,
977 "file %s\n"
978 "attach %d\n"
979 "set height 1000\n"
980 "bt full\n"
981 , VIM_NAME, getpid());
982 fclose(fp);
983 system("xterm -e gdb -x "VI_GDB_FILE);
984 unlink(VI_GDB_FILE);
985 }
986 }
987#endif
988
Bram Moolenaar071d4272004-06-13 20:20:40 +0000989#ifdef SIGHASARG
990 /* try to find the name of this signal */
991 for (i = 0; signal_info[i].sig != -1; i++)
992 if (sigarg == signal_info[i].sig)
993 break;
994 deadly_signal = sigarg;
995#endif
996
997 full_screen = FALSE; /* don't write message to the GUI, it might be
998 * part of the problem... */
999 /*
1000 * If something goes wrong after entering here, we may get here again.
1001 * When this happens, give a message and try to exit nicely (resetting the
1002 * terminal mode, etc.)
1003 * When this happens twice, just exit, don't even try to give a message,
1004 * stack may be corrupt or something weird.
1005 * When this still happens again (or memory was corrupted in such a way
1006 * that "entered" was clobbered) use _exit(), don't try freeing resources.
1007 */
1008 if (entered >= 3)
1009 {
1010 reset_signals(); /* don't catch any signals anymore */
1011 may_core_dump();
1012 if (entered >= 4)
1013 _exit(8);
1014 exit(7);
1015 }
1016 if (entered == 2)
1017 {
1018 OUT_STR(_("Vim: Double signal, exiting\n"));
1019 out_flush();
1020 getout(1);
1021 }
1022
1023#ifdef SIGHASARG
1024 sprintf((char *)IObuff, _("Vim: Caught deadly signal %s\n"),
1025 signal_info[i].name);
1026#else
1027 sprintf((char *)IObuff, _("Vim: Caught deadly signal\n"));
1028#endif
1029 preserve_exit(); /* preserve files and exit */
1030
Bram Moolenaar009b2592004-10-24 19:18:58 +00001031#ifdef NBDEBUG
1032 reset_signals();
1033 may_core_dump();
1034 abort();
1035#endif
1036
Bram Moolenaar071d4272004-06-13 20:20:40 +00001037 SIGRETURN;
1038}
1039
1040#ifdef _REENTRANT
1041/*
1042 * On Solaris with multi-threading, suspending might not work immediately.
1043 * Catch the SIGCONT signal, which will be used as an indication whether the
1044 * suspending has been done or not.
1045 */
1046static int sigcont_received;
1047static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1048
1049/*
1050 * signal handler for SIGCONT
1051 */
1052/* ARGSUSED */
1053 static RETSIGTYPE
1054sigcont_handler SIGDEFARG(sigarg)
1055{
1056 sigcont_received = TRUE;
1057 SIGRETURN;
1058}
1059#endif
1060
1061/*
1062 * If the machine has job control, use it to suspend the program,
1063 * otherwise fake it by starting a new shell.
1064 */
1065 void
1066mch_suspend()
1067{
1068 /* BeOS does have SIGTSTP, but it doesn't work. */
1069#if defined(SIGTSTP) && !defined(__BEOS__)
1070 out_flush(); /* needed to make cursor visible on some systems */
1071 settmode(TMODE_COOK);
1072 out_flush(); /* needed to disable mouse on some systems */
1073
1074# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1075 /* Since we are going to sleep, we can't respond to requests for the X
1076 * selections. Lose them, otherwise other applications will hang. But
1077 * first copy the text to cut buffer 0. */
1078 if (clip_star.owned || clip_plus.owned)
1079 {
1080 x11_export_final_selection();
1081 if (clip_star.owned)
1082 clip_lose_selection(&clip_star);
1083 if (clip_plus.owned)
1084 clip_lose_selection(&clip_plus);
1085 if (x11_display != NULL)
1086 XFlush(x11_display);
1087 }
1088# endif
1089
1090# ifdef _REENTRANT
1091 sigcont_received = FALSE;
1092# endif
1093 kill(0, SIGTSTP); /* send ourselves a STOP signal */
1094# ifdef _REENTRANT
1095 /* When we didn't suspend immediately in the kill(), do it now. Happens
1096 * on multi-threaded Solaris. */
1097 if (!sigcont_received)
1098 pause();
1099# endif
1100
1101# ifdef FEAT_TITLE
1102 /*
1103 * Set oldtitle to NULL, so the current title is obtained again.
1104 */
1105 vim_free(oldtitle);
1106 oldtitle = NULL;
1107# endif
1108 settmode(TMODE_RAW);
1109 need_check_timestamps = TRUE;
1110 did_check_timestamps = FALSE;
1111#else
1112 suspend_shell();
1113#endif
1114}
1115
1116 void
1117mch_init()
1118{
1119 Columns = 80;
1120 Rows = 24;
1121
1122 out_flush();
1123 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001124
Bram Moolenaar56718732006-03-15 22:53:57 +00001125#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001126 mac_conv_init();
1127#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128}
1129
1130 static void
1131set_signals()
1132{
1133#if defined(SIGWINCH)
1134 /*
1135 * WINDOW CHANGE signal is handled with sig_winch().
1136 */
1137 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1138#endif
1139
1140 /*
1141 * We want the STOP signal to work, to make mch_suspend() work.
1142 * For "rvim" the STOP signal is ignored.
1143 */
1144#ifdef SIGTSTP
1145 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1146#endif
1147#ifdef _REENTRANT
1148 signal(SIGCONT, sigcont_handler);
1149#endif
1150
1151 /*
1152 * We want to ignore breaking of PIPEs.
1153 */
1154#ifdef SIGPIPE
1155 signal(SIGPIPE, SIG_IGN);
1156#endif
1157
Bram Moolenaar071d4272004-06-13 20:20:40 +00001158#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001159 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001160#endif
1161
1162 /*
1163 * Ignore alarm signals (Perl's alarm() generates it).
1164 */
1165#ifdef SIGALRM
1166 signal(SIGALRM, SIG_IGN);
1167#endif
1168
1169 /*
1170 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1171 * work will be lost.
1172 */
1173#ifdef SIGPWR
1174 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1175#endif
1176
1177 /*
1178 * Arrange for other signals to gracefully shutdown Vim.
1179 */
1180 catch_signals(deathtrap, SIG_ERR);
1181
1182#if defined(FEAT_GUI) && defined(SIGHUP)
1183 /*
1184 * When the GUI is running, ignore the hangup signal.
1185 */
1186 if (gui.in_use)
1187 signal(SIGHUP, SIG_IGN);
1188#endif
1189}
1190
Bram Moolenaardf177f62005-02-22 08:39:57 +00001191#if defined(SIGINT) || defined(PROTO)
1192/*
1193 * Catch CTRL-C (only works while in Cooked mode).
1194 */
1195 static void
1196catch_int_signal()
1197{
1198 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1199}
1200#endif
1201
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202 void
1203reset_signals()
1204{
1205 catch_signals(SIG_DFL, SIG_DFL);
1206#ifdef _REENTRANT
1207 /* SIGCONT isn't in the list, because its default action is ignore */
1208 signal(SIGCONT, SIG_DFL);
1209#endif
1210}
1211
1212 static void
1213catch_signals(func_deadly, func_other)
1214 RETSIGTYPE (*func_deadly)();
1215 RETSIGTYPE (*func_other)();
1216{
1217 int i;
1218
1219 for (i = 0; signal_info[i].sig != -1; i++)
1220 if (signal_info[i].deadly)
1221 {
1222#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1223 struct sigaction sa;
1224
1225 /* Setup to use the alternate stack for the signal function. */
1226 sa.sa_handler = func_deadly;
1227 sigemptyset(&sa.sa_mask);
1228# if defined(__linux__) && defined(_REENTRANT)
1229 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1230 * thread handling in combination with using the alternate stack:
1231 * pthread library functions try to use the stack pointer to
1232 * identify the current thread, causing a SEGV signal, which
1233 * recursively calls deathtrap() and hangs. */
1234 sa.sa_flags = 0;
1235# else
1236 sa.sa_flags = SA_ONSTACK;
1237# endif
1238 sigaction(signal_info[i].sig, &sa, NULL);
1239#else
1240# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1241 struct sigvec sv;
1242
1243 /* Setup to use the alternate stack for the signal function. */
1244 sv.sv_handler = func_deadly;
1245 sv.sv_mask = 0;
1246 sv.sv_flags = SV_ONSTACK;
1247 sigvec(signal_info[i].sig, &sv, NULL);
1248# else
1249 signal(signal_info[i].sig, func_deadly);
1250# endif
1251#endif
1252 }
1253 else if (func_other != SIG_ERR)
1254 signal(signal_info[i].sig, func_other);
1255}
1256
1257/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001258 * Handling of SIGHUP, SIGQUIT and SIGTERM:
1259 * "when" == a signal: when busy, postpone, otherwise return TRUE
1260 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1261 * "when" == SIGNAL_UNBLOCK: Going wait, unblock signals
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001262 * Returns TRUE when Vim should exit.
1263 */
1264 int
Bram Moolenaar1f28b072005-07-12 22:42:41 +00001265vim_handle_signal(sig)
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001266 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001267{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001268 static int got_signal = 0;
1269 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001270
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001271 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001272 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001273 case SIGNAL_BLOCK: blocked = TRUE;
1274 break;
1275
1276 case SIGNAL_UNBLOCK: blocked = FALSE;
1277 if (got_signal != 0)
1278 {
1279 kill(getpid(), got_signal);
1280 got_signal = 0;
1281 }
1282 break;
1283
1284 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001285 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001286 got_signal = sig;
1287#ifdef SIGPWR
1288 if (sig != SIGPWR)
1289#endif
1290 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001291 break;
1292 }
1293 return FALSE;
1294}
1295
1296/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001297 * Check_win checks whether we have an interactive stdout.
1298 */
1299/* ARGSUSED */
1300 int
1301mch_check_win(argc, argv)
1302 int argc;
1303 char **argv;
1304{
1305#ifdef OS2
1306 /*
1307 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1308 * name, mostly it's just "vim" and found in the path, which is unusable.
1309 */
1310 if (mch_isFullName(argv[0]))
1311 exe_name = vim_strsave((char_u *)argv[0]);
1312#endif
1313 if (isatty(1))
1314 return OK;
1315 return FAIL;
1316}
1317
1318/*
1319 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1320 */
1321 int
1322mch_input_isatty()
1323{
1324 if (isatty(read_cmd_fd))
1325 return TRUE;
1326 return FALSE;
1327}
1328
1329#ifdef FEAT_X11
1330
1331# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1332 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1333
1334static void xopen_message __ARGS((struct timeval *tvp));
1335
1336/*
1337 * Give a message about the elapsed time for opening the X window.
1338 */
1339 static void
1340xopen_message(tvp)
1341 struct timeval *tvp; /* must contain start time */
1342{
1343 struct timeval end_tv;
1344
1345 /* Compute elapsed time. */
1346 gettimeofday(&end_tv, NULL);
1347 smsg((char_u *)_("Opening the X display took %ld msec"),
1348 (end_tv.tv_sec - tvp->tv_sec) * 1000L
Bram Moolenaar051b7822005-05-19 21:00:46 +00001349 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001350}
1351# endif
1352#endif
1353
1354#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1355/*
1356 * A few functions shared by X11 title and clipboard code.
1357 */
1358static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1359static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1360static int x_connect_to_server __ARGS((void));
1361static int test_x11_window __ARGS((Display *dpy));
1362
1363static int got_x_error = FALSE;
1364
1365/*
1366 * X Error handler, otherwise X just exits! (very rude) -- webb
1367 */
1368 static int
1369x_error_handler(dpy, error_event)
1370 Display *dpy;
1371 XErrorEvent *error_event;
1372{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001373 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001374 STRCAT(IObuff, _("\nVim: Got X error\n"));
1375
1376 /* We cannot print a message and continue, because no X calls are allowed
1377 * here (causes my system to hang). Silently continuing might be an
1378 * alternative... */
1379 preserve_exit(); /* preserve files and exit */
1380
1381 return 0; /* NOTREACHED */
1382}
1383
1384/*
1385 * Another X Error handler, just used to check for errors.
1386 */
1387/* ARGSUSED */
1388 static int
1389x_error_check(dpy, error_event)
1390 Display *dpy;
1391 XErrorEvent *error_event;
1392{
1393 got_x_error = TRUE;
1394 return 0;
1395}
1396
1397#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1398# if defined(HAVE_SETJMP_H)
1399/*
1400 * An X IO Error handler, used to catch error while opening the display.
1401 */
1402static int x_IOerror_check __ARGS((Display *dpy));
1403
1404/* ARGSUSED */
1405 static int
1406x_IOerror_check(dpy)
1407 Display *dpy;
1408{
1409 /* This function should not return, it causes exit(). Longjump instead. */
1410 LONGJMP(lc_jump_env, 1);
1411 /*NOTREACHED*/
1412 return 0;
1413}
1414# endif
1415
1416/*
1417 * An X IO Error handler, used to catch terminal errors.
1418 */
1419static int x_IOerror_handler __ARGS((Display *dpy));
1420
1421/* ARGSUSED */
1422 static int
1423x_IOerror_handler(dpy)
1424 Display *dpy;
1425{
1426 xterm_dpy = NULL;
1427 x11_window = 0;
1428 x11_display = NULL;
1429 xterm_Shell = (Widget)0;
1430
1431 /* This function should not return, it causes exit(). Longjump instead. */
1432 LONGJMP(x_jump_env, 1);
1433 /*NOTREACHED*/
1434 return 0;
1435}
1436#endif
1437
1438/*
1439 * Return TRUE when connection to the X server is desired.
1440 */
1441 static int
1442x_connect_to_server()
1443{
1444 regmatch_T regmatch;
1445
1446#if defined(FEAT_CLIENTSERVER)
1447 if (x_force_connect)
1448 return TRUE;
1449#endif
1450 if (x_no_connect)
1451 return FALSE;
1452
1453 /* Check for a match with "exclude:" from 'clipboard'. */
1454 if (clip_exclude_prog != NULL)
1455 {
1456 regmatch.rm_ic = FALSE; /* Don't ignore case */
1457 regmatch.regprog = clip_exclude_prog;
1458 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1459 return FALSE;
1460 }
1461 return TRUE;
1462}
1463
1464/*
1465 * Test if "dpy" and x11_window are valid by getting the window title.
1466 * I don't actually want it yet, so there may be a simpler call to use, but
1467 * this will cause the error handler x_error_check() to be called if anything
1468 * is wrong, such as the window pointer being invalid (as can happen when the
1469 * user changes his DISPLAY, but not his WINDOWID) -- webb
1470 */
1471 static int
1472test_x11_window(dpy)
1473 Display *dpy;
1474{
1475 int (*old_handler)();
1476 XTextProperty text_prop;
1477
1478 old_handler = XSetErrorHandler(x_error_check);
1479 got_x_error = FALSE;
1480 if (XGetWMName(dpy, x11_window, &text_prop))
1481 XFree((void *)text_prop.value);
1482 XSync(dpy, False);
1483 (void)XSetErrorHandler(old_handler);
1484
1485 if (p_verbose > 0 && got_x_error)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001486 verb_msg((char_u *)_("Testing the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001487
1488 return (got_x_error ? FAIL : OK);
1489}
1490#endif
1491
1492#ifdef FEAT_TITLE
1493
1494#ifdef FEAT_X11
1495
1496static int get_x11_thing __ARGS((int get_title, int test_only));
1497
1498/*
1499 * try to get x11 window and display
1500 *
1501 * return FAIL for failure, OK otherwise
1502 */
1503 static int
1504get_x11_windis()
1505{
1506 char *winid;
1507 static int result = -1;
1508#define XD_NONE 0 /* x11_display not set here */
1509#define XD_HERE 1 /* x11_display opened here */
1510#define XD_GUI 2 /* x11_display used from gui.dpy */
1511#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1512 static int x11_display_from = XD_NONE;
1513 static int did_set_error_handler = FALSE;
1514
1515 if (!did_set_error_handler)
1516 {
1517 /* X just exits if it finds an error otherwise! */
1518 (void)XSetErrorHandler(x_error_handler);
1519 did_set_error_handler = TRUE;
1520 }
1521
Bram Moolenaar9372a112005-12-06 19:59:18 +00001522#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001523 if (gui.in_use)
1524 {
1525 /*
1526 * If the X11 display was opened here before, for the window where Vim
1527 * was started, close that one now to avoid a memory leak.
1528 */
1529 if (x11_display_from == XD_HERE && x11_display != NULL)
1530 {
1531 XCloseDisplay(x11_display);
1532 x11_display_from = XD_NONE;
1533 }
1534 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1535 {
1536 x11_display_from = XD_GUI;
1537 return OK;
1538 }
1539 x11_display = NULL;
1540 return FAIL;
1541 }
1542 else if (x11_display_from == XD_GUI)
1543 {
1544 /* GUI must have stopped somehow, clear x11_display */
1545 x11_window = 0;
1546 x11_display = NULL;
1547 x11_display_from = XD_NONE;
1548 }
1549#endif
1550
1551 /* When started with the "-X" argument, don't try connecting. */
1552 if (!x_connect_to_server())
1553 return FAIL;
1554
1555 /*
1556 * If WINDOWID not set, should try another method to find out
1557 * what the current window number is. The only code I know for
1558 * this is very complicated.
1559 * We assume that zero is invalid for WINDOWID.
1560 */
1561 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1562 x11_window = (Window)atol(winid);
1563
1564#ifdef FEAT_XCLIPBOARD
1565 if (xterm_dpy != NULL && x11_window != 0)
1566 {
1567 /* Checked it already. */
1568 if (x11_display_from == XD_XTERM)
1569 return OK;
1570
1571 /*
1572 * If the X11 display was opened here before, for the window where Vim
1573 * was started, close that one now to avoid a memory leak.
1574 */
1575 if (x11_display_from == XD_HERE && x11_display != NULL)
1576 XCloseDisplay(x11_display);
1577 x11_display = xterm_dpy;
1578 x11_display_from = XD_XTERM;
1579 if (test_x11_window(x11_display) == FAIL)
1580 {
1581 /* probably bad $WINDOWID */
1582 x11_window = 0;
1583 x11_display = NULL;
1584 x11_display_from = XD_NONE;
1585 return FAIL;
1586 }
1587 return OK;
1588 }
1589#endif
1590
1591 if (x11_window == 0 || x11_display == NULL)
1592 result = -1;
1593
1594 if (result != -1) /* Have already been here and set this */
1595 return result; /* Don't do all these X calls again */
1596
1597 if (x11_window != 0 && x11_display == NULL)
1598 {
1599#ifdef SET_SIG_ALARM
1600 RETSIGTYPE (*sig_save)();
1601#endif
1602#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1603 struct timeval start_tv;
1604
1605 if (p_verbose > 0)
1606 gettimeofday(&start_tv, NULL);
1607#endif
1608
1609#ifdef SET_SIG_ALARM
1610 /*
1611 * Opening the Display may hang if the DISPLAY setting is wrong, or
1612 * the network connection is bad. Set an alarm timer to get out.
1613 */
1614 sig_alarm_called = FALSE;
1615 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1616 (RETSIGTYPE (*)())sig_alarm);
1617 alarm(2);
1618#endif
1619 x11_display = XOpenDisplay(NULL);
1620
1621#ifdef SET_SIG_ALARM
1622 alarm(0);
1623 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1624 if (p_verbose > 0 && sig_alarm_called)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001625 verb_msg((char_u *)_("Opening the X display timed out"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001626#endif
1627 if (x11_display != NULL)
1628 {
1629# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1630 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001631 {
1632 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001633 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00001634 verbose_leave();
1635 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636# endif
1637 if (test_x11_window(x11_display) == FAIL)
1638 {
1639 /* Maybe window id is bad */
1640 x11_window = 0;
1641 XCloseDisplay(x11_display);
1642 x11_display = NULL;
1643 }
1644 else
1645 x11_display_from = XD_HERE;
1646 }
1647 }
1648 if (x11_window == 0 || x11_display == NULL)
1649 return (result = FAIL);
1650 return (result = OK);
1651}
1652
1653/*
1654 * Determine original x11 Window Title
1655 */
1656 static int
1657get_x11_title(test_only)
1658 int test_only;
1659{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001660 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001661}
1662
1663/*
1664 * Determine original x11 Window icon
1665 */
1666 static int
1667get_x11_icon(test_only)
1668 int test_only;
1669{
1670 int retval = FALSE;
1671
1672 retval = get_x11_thing(FALSE, test_only);
1673
1674 /* could not get old icon, use terminal name */
1675 if (oldicon == NULL && !test_only)
1676 {
1677 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1678 oldicon = T_NAME + 8;
1679 else
1680 oldicon = T_NAME;
1681 }
1682
1683 return retval;
1684}
1685
1686 static int
1687get_x11_thing(get_title, test_only)
1688 int get_title; /* get title string */
1689 int test_only;
1690{
1691 XTextProperty text_prop;
1692 int retval = FALSE;
1693 Status status;
1694
1695 if (get_x11_windis() == OK)
1696 {
1697 /* Get window/icon name if any */
1698 if (get_title)
1699 status = XGetWMName(x11_display, x11_window, &text_prop);
1700 else
1701 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1702
1703 /*
1704 * If terminal is xterm, then x11_window may be a child window of the
1705 * outer xterm window that actually contains the window/icon name, so
1706 * keep traversing up the tree until a window with a title/icon is
1707 * found.
1708 */
1709 /* Previously this was only done for xterm and alikes. I don't see a
1710 * reason why it would fail for other terminal emulators.
1711 * if (term_is_xterm) */
1712 {
1713 Window root;
1714 Window parent;
1715 Window win = x11_window;
1716 Window *children;
1717 unsigned int num_children;
1718
1719 while (!status || text_prop.value == NULL)
1720 {
1721 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1722 &num_children))
1723 break;
1724 if (children)
1725 XFree((void *)children);
1726 if (parent == root || parent == 0)
1727 break;
1728
1729 win = parent;
1730 if (get_title)
1731 status = XGetWMName(x11_display, win, &text_prop);
1732 else
1733 status = XGetWMIconName(x11_display, win, &text_prop);
1734 }
1735 }
1736 if (status && text_prop.value != NULL)
1737 {
1738 retval = TRUE;
1739 if (!test_only)
1740 {
1741#ifdef FEAT_XFONTSET
1742 if (text_prop.encoding == XA_STRING)
1743 {
1744#endif
1745 if (get_title)
1746 oldtitle = vim_strsave((char_u *)text_prop.value);
1747 else
1748 oldicon = vim_strsave((char_u *)text_prop.value);
1749#ifdef FEAT_XFONTSET
1750 }
1751 else
1752 {
1753 char **cl;
1754 Status transform_status;
1755 int n = 0;
1756
1757 transform_status = XmbTextPropertyToTextList(x11_display,
1758 &text_prop,
1759 &cl, &n);
1760 if (transform_status >= Success && n > 0 && cl[0])
1761 {
1762 if (get_title)
1763 oldtitle = vim_strsave((char_u *) cl[0]);
1764 else
1765 oldicon = vim_strsave((char_u *) cl[0]);
1766 XFreeStringList(cl);
1767 }
1768 else
1769 {
1770 if (get_title)
1771 oldtitle = vim_strsave((char_u *)text_prop.value);
1772 else
1773 oldicon = vim_strsave((char_u *)text_prop.value);
1774 }
1775 }
1776#endif
1777 }
1778 XFree((void *)text_prop.value);
1779 }
1780 }
1781 return retval;
1782}
1783
1784/* Are Xutf8 functions available? Avoid error from old compilers. */
1785#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1786# if X_HAVE_UTF8_STRING
1787# define USE_UTF8_STRING
1788# endif
1789#endif
1790
1791/*
1792 * Set x11 Window Title
1793 *
1794 * get_x11_windis() must be called before this and have returned OK
1795 */
1796 static void
1797set_x11_title(title)
1798 char_u *title;
1799{
1800 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1801 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1802 * supported everywhere and STRING doesn't work for multi-byte titles.
1803 */
1804#ifdef USE_UTF8_STRING
1805 if (enc_utf8)
1806 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1807 NULL, NULL, 0, NULL, NULL, NULL);
1808 else
1809#endif
1810 {
1811#if XtSpecificationRelease >= 4
1812# ifdef FEAT_XFONTSET
1813 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1814 NULL, NULL, 0, NULL, NULL, NULL);
1815# else
1816 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001817 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001818
1819 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001820 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001821 XSetWMProperties(x11_display, x11_window, &text_prop,
1822 NULL, NULL, 0, NULL, NULL, NULL);
1823# endif
1824#else
1825 XStoreName(x11_display, x11_window, (char *)title);
1826#endif
1827 }
1828 XFlush(x11_display);
1829}
1830
1831/*
1832 * Set x11 Window icon
1833 *
1834 * get_x11_windis() must be called before this and have returned OK
1835 */
1836 static void
1837set_x11_icon(icon)
1838 char_u *icon;
1839{
1840 /* See above for comments about using X*SetWMProperties(). */
1841#ifdef USE_UTF8_STRING
1842 if (enc_utf8)
1843 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1844 NULL, 0, NULL, NULL, NULL);
1845 else
1846#endif
1847 {
1848#if XtSpecificationRelease >= 4
1849# ifdef FEAT_XFONTSET
1850 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1851 NULL, 0, NULL, NULL, NULL);
1852# else
1853 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001854 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001855
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001856 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001857 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
1858 NULL, 0, NULL, NULL, NULL);
1859# endif
1860#else
1861 XSetIconName(x11_display, x11_window, (char *)icon);
1862#endif
1863 }
1864 XFlush(x11_display);
1865}
1866
1867#else /* FEAT_X11 */
1868
1869/*ARGSUSED*/
1870 static int
1871get_x11_title(test_only)
1872 int test_only;
1873{
1874 return FALSE;
1875}
1876
1877 static int
1878get_x11_icon(test_only)
1879 int test_only;
1880{
1881 if (!test_only)
1882 {
1883 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1884 oldicon = T_NAME + 8;
1885 else
1886 oldicon = T_NAME;
1887 }
1888 return FALSE;
1889}
1890
1891#endif /* FEAT_X11 */
1892
1893 int
1894mch_can_restore_title()
1895{
1896 return get_x11_title(TRUE);
1897}
1898
1899 int
1900mch_can_restore_icon()
1901{
1902 return get_x11_icon(TRUE);
1903}
1904
1905/*
1906 * Set the window title and icon.
1907 */
1908 void
1909mch_settitle(title, icon)
1910 char_u *title;
1911 char_u *icon;
1912{
1913 int type = 0;
1914 static int recursive = 0;
1915
1916 if (T_NAME == NULL) /* no terminal name (yet) */
1917 return;
1918 if (title == NULL && icon == NULL) /* nothing to do */
1919 return;
1920
1921 /* When one of the X11 functions causes a deadly signal, we get here again
1922 * recursively. Avoid hanging then (something is probably locked). */
1923 if (recursive)
1924 return;
1925 ++recursive;
1926
1927 /*
1928 * if the window ID and the display is known, we may use X11 calls
1929 */
1930#ifdef FEAT_X11
1931 if (get_x11_windis() == OK)
1932 type = 1;
1933#else
1934# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
1935 if (gui.in_use)
1936 type = 1;
1937# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001938#endif
1939
1940 /*
1941 * Note: if "t_TS" is set, title is set with escape sequence rather
1942 * than x11 calls, because the x11 calls don't always work
1943 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001944 if ((type || *T_TS != NUL) && title != NULL)
1945 {
1946 if (oldtitle == NULL
1947#ifdef FEAT_GUI
1948 && !gui.in_use
1949#endif
1950 ) /* first call but not in GUI, save title */
1951 (void)get_x11_title(FALSE);
1952
1953 if (*T_TS != NUL) /* it's OK if t_fs is empty */
1954 term_settitle(title);
1955#ifdef FEAT_X11
1956 else
1957# ifdef FEAT_GUI_GTK
1958 if (!gui.in_use) /* don't do this if GTK+ is running */
1959# endif
1960 set_x11_title(title); /* x11 */
1961#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00001962#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001963 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
1964 else
1965 gui_mch_settitle(title, icon);
1966#endif
1967 did_set_title = TRUE;
1968 }
1969
1970 if ((type || *T_CIS != NUL) && icon != NULL)
1971 {
1972 if (oldicon == NULL
1973#ifdef FEAT_GUI
1974 && !gui.in_use
1975#endif
1976 ) /* first call, save icon */
1977 get_x11_icon(FALSE);
1978
1979 if (*T_CIS != NUL)
1980 {
1981 out_str(T_CIS); /* set icon start */
1982 out_str_nf(icon);
1983 out_str(T_CIE); /* set icon end */
1984 out_flush();
1985 }
1986#ifdef FEAT_X11
1987 else
1988# ifdef FEAT_GUI_GTK
1989 if (!gui.in_use) /* don't do this if GTK+ is running */
1990# endif
1991 set_x11_icon(icon); /* x11 */
1992#endif
1993 did_set_icon = TRUE;
1994 }
1995 --recursive;
1996}
1997
1998/*
1999 * Restore the window/icon title.
2000 * "which" is one of:
2001 * 1 only restore title
2002 * 2 only restore icon
2003 * 3 restore title and icon
2004 */
2005 void
2006mch_restore_title(which)
2007 int which;
2008{
2009 /* only restore the title or icon when it has been set */
2010 mch_settitle(((which & 1) && did_set_title) ?
2011 (oldtitle ? oldtitle : p_titleold) : NULL,
2012 ((which & 2) && did_set_icon) ? oldicon : NULL);
2013}
2014
2015#endif /* FEAT_TITLE */
2016
2017/*
2018 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002019 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002020 */
2021 int
2022vim_is_xterm(name)
2023 char_u *name;
2024{
2025 if (name == NULL)
2026 return FALSE;
2027 return (STRNICMP(name, "xterm", 5) == 0
2028 || STRNICMP(name, "nxterm", 6) == 0
2029 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002030 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002031 || STRNICMP(name, "rxvt", 4) == 0
2032 || STRCMP(name, "builtin_xterm") == 0);
2033}
2034
2035#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2036/*
2037 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2038 * Return 1 for "xterm".
2039 * Return 2 for "xterm2".
2040 */
2041 int
2042use_xterm_mouse()
2043{
2044 if (ttym_flags == TTYM_XTERM2)
2045 return 2;
2046 if (ttym_flags == TTYM_XTERM)
2047 return 1;
2048 return 0;
2049}
2050#endif
2051
2052 int
2053vim_is_iris(name)
2054 char_u *name;
2055{
2056 if (name == NULL)
2057 return FALSE;
2058 return (STRNICMP(name, "iris-ansi", 9) == 0
2059 || STRCMP(name, "builtin_iris-ansi") == 0);
2060}
2061
2062 int
2063vim_is_vt300(name)
2064 char_u *name;
2065{
2066 if (name == NULL)
2067 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002068 /* catch VT100 - VT5xx */
2069 return ((STRNICMP(name, "vt", 2) == 0
2070 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002071 || STRCMP(name, "builtin_vt320") == 0);
2072}
2073
2074/*
2075 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2076 * This should include all windowed terminal emulators.
2077 */
2078 int
2079vim_is_fastterm(name)
2080 char_u *name;
2081{
2082 if (name == NULL)
2083 return FALSE;
2084 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2085 return TRUE;
2086 return ( STRNICMP(name, "hpterm", 6) == 0
2087 || STRNICMP(name, "sun-cmd", 7) == 0
2088 || STRNICMP(name, "screen", 6) == 0
2089 || STRNICMP(name, "dtterm", 6) == 0);
2090}
2091
2092/*
2093 * Insert user name in s[len].
2094 * Return OK if a name found.
2095 */
2096 int
2097mch_get_user_name(s, len)
2098 char_u *s;
2099 int len;
2100{
2101#ifdef VMS
Bram Moolenaarffb8ab02005-09-07 21:15:32 +00002102 vim_strncpy(s, (char_u *)cuserid(NULL), len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002103 return OK;
2104#else
2105 return mch_get_uname(getuid(), s, len);
2106#endif
2107}
2108
2109/*
2110 * Insert user name for "uid" in s[len].
2111 * Return OK if a name found.
2112 */
2113 int
2114mch_get_uname(uid, s, len)
2115 uid_t uid;
2116 char_u *s;
2117 int len;
2118{
2119#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2120 struct passwd *pw;
2121
2122 if ((pw = getpwuid(uid)) != NULL
2123 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2124 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002125 vim_strncpy(s, (char_u *)pw->pw_name, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002126 return OK;
2127 }
2128#endif
2129 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2130 return FAIL; /* a number is not a name */
2131}
2132
2133/*
2134 * Insert host name is s[len].
2135 */
2136
2137#ifdef HAVE_SYS_UTSNAME_H
2138 void
2139mch_get_host_name(s, len)
2140 char_u *s;
2141 int len;
2142{
2143 struct utsname vutsname;
2144
2145 if (uname(&vutsname) < 0)
2146 *s = NUL;
2147 else
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002148 vim_strncpy(s, (char_u *)vutsname.nodename, len - 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002149}
2150#else /* HAVE_SYS_UTSNAME_H */
2151
2152# ifdef HAVE_SYS_SYSTEMINFO_H
2153# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2154# endif
2155
2156 void
2157mch_get_host_name(s, len)
2158 char_u *s;
2159 int len;
2160{
2161# ifdef VAXC
2162 vaxc$gethostname((char *)s, len);
2163# else
2164 gethostname((char *)s, len);
2165# endif
2166 s[len - 1] = NUL; /* make sure it's terminated */
2167}
2168#endif /* HAVE_SYS_UTSNAME_H */
2169
2170/*
2171 * return process ID
2172 */
2173 long
2174mch_get_pid()
2175{
2176 return (long)getpid();
2177}
2178
2179#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2180static char *strerror __ARGS((int));
2181
2182 static char *
2183strerror(err)
2184 int err;
2185{
2186 extern int sys_nerr;
2187 extern char *sys_errlist[];
2188 static char er[20];
2189
2190 if (err > 0 && err < sys_nerr)
2191 return (sys_errlist[err]);
2192 sprintf(er, "Error %d", err);
2193 return er;
2194}
2195#endif
2196
2197/*
2198 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2199 * Return OK for success, FAIL for failure.
2200 */
2201 int
2202mch_dirname(buf, len)
2203 char_u *buf;
2204 int len;
2205{
2206#if defined(USE_GETCWD)
2207 if (getcwd((char *)buf, len) == NULL)
2208 {
2209 STRCPY(buf, strerror(errno));
2210 return FAIL;
2211 }
2212 return OK;
2213#else
2214 return (getwd((char *)buf) != NULL ? OK : FAIL);
2215#endif
2216}
2217
2218#if defined(OS2) || defined(PROTO)
2219/*
2220 * Replace all slashes by backslashes.
2221 * When 'shellslash' set do it the other way around.
2222 */
2223 void
2224slash_adjust(p)
2225 char_u *p;
2226{
2227 while (*p)
2228 {
2229 if (*p == psepcN)
2230 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002231 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002232 }
2233}
2234#endif
2235
2236/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002237 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002238 *
2239 * return FAIL for failure, OK for success
2240 */
2241 int
2242mch_FullName(fname, buf, len, force)
2243 char_u *fname, *buf;
2244 int len;
2245 int force; /* also expand when already absolute path */
2246{
2247 int l;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002248#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002249 int only_drive; /* file name is only a drive letter */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002250#endif
2251#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002252 int fd = -1;
2253 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002254#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255 char_u olddir[MAXPATHL];
2256 char_u *p;
2257 int retval = OK;
2258
Bram Moolenaar38323e42007-03-06 19:22:53 +00002259#ifdef VMS
2260 fname = vms_fixfilename(fname);
2261#endif
2262
Bram Moolenaara2442432007-04-26 14:26:37 +00002263#ifdef __CYGWIN__
2264 /*
2265 * This helps for when "/etc/hosts" is a symlink to "c:/something/hosts".
2266 */
2267 cygwin_conv_to_posix_path(fname, fname);
2268#endif
2269
Bram Moolenaar071d4272004-06-13 20:20:40 +00002270 /* expand it if forced or not an absolute path */
2271 if (force || !mch_isFullName(fname))
2272 {
2273 /*
2274 * If the file name has a path, change to that directory for a moment,
2275 * and then do the getwd() (and get back to where we were).
2276 * This will get the correct path name with "../" things.
2277 */
Bram Moolenaar38323e42007-03-06 19:22:53 +00002278#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002279 only_drive = 0;
2280 if (((p = vim_strrchr(fname, '/')) != NULL)
2281 || ((p = vim_strrchr(fname, '\\')) != NULL)
2282 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar38323e42007-03-06 19:22:53 +00002283#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002284 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar38323e42007-03-06 19:22:53 +00002285#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002286 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002287#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002288 /*
2289 * Use fchdir() if possible, it's said to be faster and more
2290 * reliable. But on SunOS 4 it might not work. Check this by
2291 * doing a fchdir() right now.
2292 */
2293 if (!dont_fchdir)
2294 {
2295 fd = open(".", O_RDONLY | O_EXTRA, 0);
2296 if (fd >= 0 && fchdir(fd) < 0)
2297 {
2298 close(fd);
2299 fd = -1;
2300 dont_fchdir = TRUE; /* don't try again */
2301 }
2302 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002303#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002304
2305 /* Only change directory when we are sure we can return to where
2306 * we are now. After doing "su" chdir(".") might not work. */
2307 if (
Bram Moolenaar38323e42007-03-06 19:22:53 +00002308#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002309 fd < 0 &&
Bram Moolenaar38323e42007-03-06 19:22:53 +00002310#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002311 (mch_dirname(olddir, MAXPATHL) == FAIL
2312 || mch_chdir((char *)olddir) != 0))
2313 {
2314 p = NULL; /* can't get current dir: don't chdir */
2315 retval = FAIL;
2316 }
2317 else
2318 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002319#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002320 /*
2321 * compensate for case where ':' from "D:" was the only
2322 * path separator detected in the file name; the _next_
2323 * character has to be removed, and then restored later.
2324 */
2325 if (only_drive)
2326 p++;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002327#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002328 /* The directory is copied into buf[], to be able to remove
2329 * the file name without changing it (could be a string in
2330 * read-only memory) */
2331 if (p - fname >= len)
2332 retval = FAIL;
2333 else
2334 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002335 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002336 if (mch_chdir((char *)buf))
2337 retval = FAIL;
2338 else
2339 fname = p + 1;
2340 *buf = NUL;
2341 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002342#ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002343 if (only_drive)
2344 {
2345 p--;
2346 if (retval != FAIL)
2347 fname--;
2348 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002349#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002350 }
2351 }
2352 if (mch_dirname(buf, len) == FAIL)
2353 {
2354 retval = FAIL;
2355 *buf = NUL;
2356 }
2357 if (p != NULL)
2358 {
Bram Moolenaar38323e42007-03-06 19:22:53 +00002359#ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002360 if (fd >= 0)
2361 {
2362 l = fchdir(fd);
2363 close(fd);
2364 }
2365 else
Bram Moolenaar38323e42007-03-06 19:22:53 +00002366#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002367 l = mch_chdir((char *)olddir);
2368 if (l != 0)
2369 EMSG(_(e_prev_dir));
2370 }
2371
2372 l = STRLEN(buf);
2373 if (l >= len)
2374 retval = FAIL;
Bram Moolenaar38323e42007-03-06 19:22:53 +00002375#ifndef VMS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002376 else
2377 {
2378 if (l > 0 && buf[l - 1] != '/' && *fname != NUL
2379 && STRCMP(fname, ".") != 0)
2380 STRCAT(buf, "/");
2381 }
Bram Moolenaar38323e42007-03-06 19:22:53 +00002382#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002383 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002384
Bram Moolenaar071d4272004-06-13 20:20:40 +00002385 /* Catch file names which are too long. */
2386 if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len)
2387 return FAIL;
2388
2389 /* Do not append ".", "/dir/." is equal to "/dir". */
2390 if (STRCMP(fname, ".") != 0)
2391 STRCAT(buf, fname);
2392
2393 return OK;
2394}
2395
2396/*
2397 * Return TRUE if "fname" does not depend on the current directory.
2398 */
2399 int
2400mch_isFullName(fname)
2401 char_u *fname;
2402{
2403#ifdef __EMX__
2404 return _fnisabs(fname);
2405#else
2406# ifdef VMS
2407 return ( fname[0] == '/' || fname[0] == '.' ||
2408 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2409 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2410 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2411# else
2412 return (*fname == '/' || *fname == '~');
2413# endif
2414#endif
2415}
2416
Bram Moolenaar24552be2005-12-10 20:17:30 +00002417#if defined(USE_FNAME_CASE) || defined(PROTO)
2418/*
2419 * Set the case of the file name, if it already exists. This will cause the
2420 * file name to remain exactly the same.
2421 * Only required for file systems where case is ingored and preserved.
2422 */
2423/*ARGSUSED*/
2424 void
2425fname_case(name, len)
2426 char_u *name;
2427 int len; /* buffer size, only used when name gets longer */
2428{
2429 struct stat st;
2430 char_u *slash, *tail;
2431 DIR *dirp;
2432 struct dirent *dp;
2433
2434 if (lstat((char *)name, &st) >= 0)
2435 {
2436 /* Open the directory where the file is located. */
2437 slash = vim_strrchr(name, '/');
2438 if (slash == NULL)
2439 {
2440 dirp = opendir(".");
2441 tail = name;
2442 }
2443 else
2444 {
2445 *slash = NUL;
2446 dirp = opendir((char *)name);
2447 *slash = '/';
2448 tail = slash + 1;
2449 }
2450
2451 if (dirp != NULL)
2452 {
2453 while ((dp = readdir(dirp)) != NULL)
2454 {
2455 /* Only accept names that differ in case and are the same byte
2456 * length. TODO: accept different length name. */
2457 if (STRICMP(tail, dp->d_name) == 0
2458 && STRLEN(tail) == STRLEN(dp->d_name))
2459 {
2460 char_u newname[MAXPATHL + 1];
2461 struct stat st2;
2462
2463 /* Verify the inode is equal. */
2464 vim_strncpy(newname, name, MAXPATHL);
2465 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2466 MAXPATHL - (tail - name));
2467 if (lstat((char *)newname, &st2) >= 0
2468 && st.st_ino == st2.st_ino
2469 && st.st_dev == st2.st_dev)
2470 {
2471 STRCPY(tail, dp->d_name);
2472 break;
2473 }
2474 }
2475 }
2476
2477 closedir(dirp);
2478 }
2479 }
2480}
2481#endif
2482
Bram Moolenaar071d4272004-06-13 20:20:40 +00002483/*
2484 * Get file permissions for 'name'.
2485 * Returns -1 when it doesn't exist.
2486 */
2487 long
2488mch_getperm(name)
2489 char_u *name;
2490{
2491 struct stat statb;
2492
2493 /* Keep the #ifdef outside of stat(), it may be a macro. */
2494#ifdef VMS
2495 if (stat((char *)vms_fixfilename(name), &statb))
2496#else
2497 if (stat((char *)name, &statb))
2498#endif
2499 return -1;
2500 return statb.st_mode;
2501}
2502
2503/*
2504 * set file permission for 'name' to 'perm'
2505 *
2506 * return FAIL for failure, OK otherwise
2507 */
2508 int
2509mch_setperm(name, perm)
2510 char_u *name;
2511 long perm;
2512{
2513 return (chmod((char *)
2514#ifdef VMS
2515 vms_fixfilename(name),
2516#else
2517 name,
2518#endif
2519 (mode_t)perm) == 0 ? OK : FAIL);
2520}
2521
2522#if defined(HAVE_ACL) || defined(PROTO)
2523# ifdef HAVE_SYS_ACL_H
2524# include <sys/acl.h>
2525# endif
2526# ifdef HAVE_SYS_ACCESS_H
2527# include <sys/access.h>
2528# endif
2529
2530# ifdef HAVE_SOLARIS_ACL
2531typedef struct vim_acl_solaris_T {
2532 int acl_cnt;
2533 aclent_t *acl_entry;
2534} vim_acl_solaris_T;
2535# endif
2536
2537/*
2538 * Return a pointer to the ACL of file "fname" in allocated memory.
2539 * Return NULL if the ACL is not available for whatever reason.
2540 */
2541 vim_acl_T
2542mch_get_acl(fname)
2543 char_u *fname;
2544{
2545 vim_acl_T ret = NULL;
2546#ifdef HAVE_POSIX_ACL
2547 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2548#else
2549#ifdef HAVE_SOLARIS_ACL
2550 vim_acl_solaris_T *aclent;
2551
2552 aclent = malloc(sizeof(vim_acl_solaris_T));
2553 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2554 {
2555 free(aclent);
2556 return NULL;
2557 }
2558 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2559 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2560 {
2561 free(aclent->acl_entry);
2562 free(aclent);
2563 return NULL;
2564 }
2565 ret = (vim_acl_T)aclent;
2566#else
2567#if defined(HAVE_AIX_ACL)
2568 int aclsize;
2569 struct acl *aclent;
2570
2571 aclsize = sizeof(struct acl);
2572 aclent = malloc(aclsize);
2573 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2574 {
2575 if (errno == ENOSPC)
2576 {
2577 aclsize = aclent->acl_len;
2578 aclent = realloc(aclent, aclsize);
2579 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2580 {
2581 free(aclent);
2582 return NULL;
2583 }
2584 }
2585 else
2586 {
2587 free(aclent);
2588 return NULL;
2589 }
2590 }
2591 ret = (vim_acl_T)aclent;
2592#endif /* HAVE_AIX_ACL */
2593#endif /* HAVE_SOLARIS_ACL */
2594#endif /* HAVE_POSIX_ACL */
2595 return ret;
2596}
2597
2598/*
2599 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2600 */
2601 void
2602mch_set_acl(fname, aclent)
2603 char_u *fname;
2604 vim_acl_T aclent;
2605{
2606 if (aclent == NULL)
2607 return;
2608#ifdef HAVE_POSIX_ACL
2609 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2610#else
2611#ifdef HAVE_SOLARIS_ACL
2612 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2613 ((vim_acl_solaris_T *)aclent)->acl_entry);
2614#else
2615#ifdef HAVE_AIX_ACL
2616 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2617#endif /* HAVE_AIX_ACL */
2618#endif /* HAVE_SOLARIS_ACL */
2619#endif /* HAVE_POSIX_ACL */
2620}
2621
2622 void
2623mch_free_acl(aclent)
2624 vim_acl_T aclent;
2625{
2626 if (aclent == NULL)
2627 return;
2628#ifdef HAVE_POSIX_ACL
2629 acl_free((acl_t)aclent);
2630#else
2631#ifdef HAVE_SOLARIS_ACL
2632 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2633 free(aclent);
2634#else
2635#ifdef HAVE_AIX_ACL
2636 free(aclent);
2637#endif /* HAVE_AIX_ACL */
2638#endif /* HAVE_SOLARIS_ACL */
2639#endif /* HAVE_POSIX_ACL */
2640}
2641#endif
2642
2643/*
2644 * Set hidden flag for "name".
2645 */
2646/* ARGSUSED */
2647 void
2648mch_hide(name)
2649 char_u *name;
2650{
2651 /* can't hide a file */
2652}
2653
2654/*
2655 * return TRUE if "name" is a directory
2656 * return FALSE if "name" is not a directory
2657 * return FALSE for error
2658 */
2659 int
2660mch_isdir(name)
2661 char_u *name;
2662{
2663 struct stat statb;
2664
2665 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2666 return FALSE;
2667 if (stat((char *)name, &statb))
2668 return FALSE;
2669#ifdef _POSIX_SOURCE
2670 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2671#else
2672 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2673#endif
2674}
2675
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676static int executable_file __ARGS((char_u *name));
2677
2678/*
2679 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2680 */
2681 static int
2682executable_file(name)
2683 char_u *name;
2684{
2685 struct stat st;
2686
2687 if (stat((char *)name, &st))
2688 return 0;
2689 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2690}
2691
2692/*
2693 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2694 * Return -1 if unknown.
2695 */
2696 int
2697mch_can_exe(name)
2698 char_u *name;
2699{
2700 char_u *buf;
2701 char_u *p, *e;
2702 int retval;
2703
2704 /* If it's an absolute or relative path don't need to use $PATH. */
2705 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2706 || (name[1] == '.' && name[2] == '/'))))
2707 return executable_file(name);
2708
2709 p = (char_u *)getenv("PATH");
2710 if (p == NULL || *p == NUL)
2711 return -1;
2712 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2713 if (buf == NULL)
2714 return -1;
2715
2716 /*
2717 * Walk through all entries in $PATH to check if "name" exists there and
2718 * is an executable file.
2719 */
2720 for (;;)
2721 {
2722 e = (char_u *)strchr((char *)p, ':');
2723 if (e == NULL)
2724 e = p + STRLEN(p);
2725 if (e - p <= 1) /* empty entry means current dir */
2726 STRCPY(buf, "./");
2727 else
2728 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002729 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002730 add_pathsep(buf);
2731 }
2732 STRCAT(buf, name);
2733 retval = executable_file(buf);
2734 if (retval == 1)
2735 break;
2736
2737 if (*e != ':')
2738 break;
2739 p = e + 1;
2740 }
2741
2742 vim_free(buf);
2743 return retval;
2744}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002745
2746/*
2747 * Check what "name" is:
2748 * NODE_NORMAL: file or directory (or doesn't exist)
2749 * NODE_WRITABLE: writable device, socket, fifo, etc.
2750 * NODE_OTHER: non-writable things
2751 */
2752 int
2753mch_nodetype(name)
2754 char_u *name;
2755{
2756 struct stat st;
2757
2758 if (stat((char *)name, &st))
2759 return NODE_NORMAL;
2760 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2761 return NODE_NORMAL;
2762#ifndef OS2
2763 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2764 return NODE_OTHER;
2765#endif
2766 /* Everything else is writable? */
2767 return NODE_WRITABLE;
2768}
2769
2770 void
2771mch_early_init()
2772{
2773#ifdef HAVE_CHECK_STACK_GROWTH
2774 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776 check_stack_growth((char *)&i);
2777
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002778# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002779 get_stack_limit();
2780# endif
2781
2782#endif
2783
2784 /*
2785 * Setup an alternative stack for signals. Helps to catch signals when
2786 * running out of stack space.
2787 * Use of sigaltstack() is preferred, it's more portable.
2788 * Ignore any errors.
2789 */
2790#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2791 signal_stack = malloc(SIGSTKSZ);
2792 init_signal_stack();
2793#endif
2794}
2795
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002796#if defined(EXITFREE) || defined(PROTO)
2797 void
2798mch_free_mem()
2799{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002800# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2801 if (clip_star.owned)
2802 clip_lose_selection(&clip_star);
2803 if (clip_plus.owned)
2804 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002805# endif
2806# if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
2807 if (xterm_Shell != (Widget)0)
2808 XtDestroyWidget(xterm_Shell);
2809 if (xterm_dpy != NULL)
2810 XtCloseDisplay(xterm_dpy);
2811 if (app_context != (XtAppContext)NULL)
2812 XtDestroyApplicationContext(app_context);
2813# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002814# ifdef FEAT_X11
2815 if (x11_display != NULL && x11_display != xterm_dpy)
2816 XCloseDisplay(x11_display);
2817# endif
2818# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2819 vim_free(signal_stack);
2820 signal_stack = NULL;
2821# endif
2822# ifdef FEAT_TITLE
2823 vim_free(oldtitle);
2824 vim_free(oldicon);
2825# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002826}
2827#endif
2828
Bram Moolenaar071d4272004-06-13 20:20:40 +00002829static void exit_scroll __ARGS((void));
2830
2831/*
2832 * Output a newline when exiting.
2833 * Make sure the newline goes to the same stream as the text.
2834 */
2835 static void
2836exit_scroll()
2837{
Bram Moolenaardf177f62005-02-22 08:39:57 +00002838 if (silent_mode)
2839 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002840 if (newline_on_exit || msg_didout)
2841 {
2842 if (msg_use_printf())
2843 {
2844 if (info_message)
2845 mch_msg("\n");
2846 else
2847 mch_errmsg("\r\n");
2848 }
2849 else
2850 out_char('\n');
2851 }
2852 else
2853 {
2854 restore_cterm_colors(); /* get original colors back */
2855 msg_clr_eos_force(); /* clear the rest of the display */
2856 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
2857 }
2858}
2859
2860 void
2861mch_exit(r)
2862 int r;
2863{
2864 exiting = TRUE;
2865
2866#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
2867 x11_export_final_selection();
2868#endif
2869
2870#ifdef FEAT_GUI
2871 if (!gui.in_use)
2872#endif
2873 {
2874 settmode(TMODE_COOK);
2875#ifdef FEAT_TITLE
2876 mch_restore_title(3); /* restore xterm title and icon name */
2877#endif
2878 /*
2879 * When t_ti is not empty but it doesn't cause swapping terminal
2880 * pages, need to output a newline when msg_didout is set. But when
2881 * t_ti does swap pages it should not go to the shell page. Do this
2882 * before stoptermcap().
2883 */
2884 if (swapping_screen() && !newline_on_exit)
2885 exit_scroll();
2886
2887 /* Stop termcap: May need to check for T_CRV response, which
2888 * requires RAW mode. */
2889 stoptermcap();
2890
2891 /*
2892 * A newline is only required after a message in the alternate screen.
2893 * This is set to TRUE by wait_return().
2894 */
2895 if (!swapping_screen() || newline_on_exit)
2896 exit_scroll();
2897
2898 /* Cursor may have been switched off without calling starttermcap()
2899 * when doing "vim -u vimrc" and vimrc contains ":q". */
2900 if (full_screen)
2901 cursor_on();
2902 }
2903 out_flush();
2904 ml_close_all(TRUE); /* remove all memfiles */
2905 may_core_dump();
2906#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002907 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002908 gui_exit(r);
2909#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00002910
Bram Moolenaar56718732006-03-15 22:53:57 +00002911#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00002912 mac_conv_cleanup();
2913#endif
2914
Bram Moolenaar071d4272004-06-13 20:20:40 +00002915#ifdef __QNX__
2916 /* A core dump won't be created if the signal handler
2917 * doesn't return, so we can't call exit() */
2918 if (deadly_signal != 0)
2919 return;
2920#endif
2921
Bram Moolenaar009b2592004-10-24 19:18:58 +00002922#ifdef FEAT_NETBEANS_INTG
2923 if (usingNetbeans)
2924 netbeans_send_disconnect();
2925#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002926
2927#ifdef EXITFREE
2928 free_all_mem();
2929#endif
2930
Bram Moolenaar071d4272004-06-13 20:20:40 +00002931 exit(r);
2932}
2933
2934 static void
2935may_core_dump()
2936{
2937 if (deadly_signal != 0)
2938 {
2939 signal(deadly_signal, SIG_DFL);
2940 kill(getpid(), deadly_signal); /* Die using the signal we caught */
2941 }
2942}
2943
2944#ifndef VMS
2945
2946 void
2947mch_settmode(tmode)
2948 int tmode;
2949{
2950 static int first = TRUE;
2951
2952 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2953#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2954 /*
2955 * for "new" tty systems
2956 */
2957# ifdef HAVE_TERMIOS_H
2958 static struct termios told;
2959 struct termios tnew;
2960# else
2961 static struct termio told;
2962 struct termio tnew;
2963# endif
2964
2965 if (first)
2966 {
2967 first = FALSE;
2968# if defined(HAVE_TERMIOS_H)
2969 tcgetattr(read_cmd_fd, &told);
2970# else
2971 ioctl(read_cmd_fd, TCGETA, &told);
2972# endif
2973 }
2974
2975 tnew = told;
2976 if (tmode == TMODE_RAW)
2977 {
2978 /*
2979 * ~ICRNL enables typing ^V^M
2980 */
2981 tnew.c_iflag &= ~ICRNL;
2982 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
2983# if defined(IEXTEN) && !defined(__MINT__)
2984 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
2985 /* but it breaks function keys on MINT */
2986# endif
2987 );
2988# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
2989 tnew.c_oflag &= ~ONLCR;
2990# endif
2991 tnew.c_cc[VMIN] = 1; /* return after 1 char */
2992 tnew.c_cc[VTIME] = 0; /* don't wait */
2993 }
2994 else if (tmode == TMODE_SLEEP)
2995 tnew.c_lflag &= ~(ECHO);
2996
2997# if defined(HAVE_TERMIOS_H)
2998 {
2999 int n = 10;
3000
3001 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
3002 * few times. */
3003 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
3004 && errno == EINTR && n > 0)
3005 --n;
3006 }
3007# else
3008 ioctl(read_cmd_fd, TCSETA, &tnew);
3009# endif
3010
3011#else
3012
3013 /*
3014 * for "old" tty systems
3015 */
3016# ifndef TIOCSETN
3017# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3018# endif
3019 static struct sgttyb ttybold;
3020 struct sgttyb ttybnew;
3021
3022 if (first)
3023 {
3024 first = FALSE;
3025 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3026 }
3027
3028 ttybnew = ttybold;
3029 if (tmode == TMODE_RAW)
3030 {
3031 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3032 ttybnew.sg_flags |= RAW;
3033 }
3034 else if (tmode == TMODE_SLEEP)
3035 ttybnew.sg_flags &= ~(ECHO);
3036 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3037#endif
3038 curr_tmode = tmode;
3039}
3040
3041/*
3042 * Try to get the code for "t_kb" from the stty setting
3043 *
3044 * Even if termcap claims a backspace key, the user's setting *should*
3045 * prevail. stty knows more about reality than termcap does, and if
3046 * somebody's usual erase key is DEL (which, for most BSD users, it will
3047 * be), they're going to get really annoyed if their erase key starts
3048 * doing forward deletes for no reason. (Eric Fischer)
3049 */
3050 void
3051get_stty()
3052{
3053 char_u buf[2];
3054 char_u *p;
3055
3056 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3057#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3058 /* for "new" tty systems */
3059# ifdef HAVE_TERMIOS_H
3060 struct termios keys;
3061# else
3062 struct termio keys;
3063# endif
3064
3065# if defined(HAVE_TERMIOS_H)
3066 if (tcgetattr(read_cmd_fd, &keys) != -1)
3067# else
3068 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3069# endif
3070 {
3071 buf[0] = keys.c_cc[VERASE];
3072 intr_char = keys.c_cc[VINTR];
3073#else
3074 /* for "old" tty systems */
3075 struct sgttyb keys;
3076
3077 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3078 {
3079 buf[0] = keys.sg_erase;
3080 intr_char = keys.sg_kill;
3081#endif
3082 buf[1] = NUL;
3083 add_termcode((char_u *)"kb", buf, FALSE);
3084
3085 /*
3086 * If <BS> and <DEL> are now the same, redefine <DEL>.
3087 */
3088 p = find_termcode((char_u *)"kD");
3089 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3090 do_fixdel(NULL);
3091 }
3092#if 0
3093 } /* to keep cindent happy */
3094#endif
3095}
3096
3097#endif /* VMS */
3098
3099#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3100/*
3101 * Set mouse clicks on or off.
3102 */
3103 void
3104mch_setmouse(on)
3105 int on;
3106{
3107 static int ison = FALSE;
3108 int xterm_mouse_vers;
3109
3110 if (on == ison) /* return quickly if nothing to do */
3111 return;
3112
3113 xterm_mouse_vers = use_xterm_mouse();
3114 if (xterm_mouse_vers > 0)
3115 {
3116 if (on) /* enable mouse events, use mouse tracking if available */
3117 out_str_nf((char_u *)
3118 (xterm_mouse_vers > 1
3119 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3120 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3121 else /* disable mouse events, could probably always send the same */
3122 out_str_nf((char_u *)
3123 (xterm_mouse_vers > 1
3124 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3125 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3126 ison = on;
3127 }
3128
3129# ifdef FEAT_MOUSE_DEC
3130 else if (ttym_flags == TTYM_DEC)
3131 {
3132 if (on) /* enable mouse events */
3133 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3134 else /* disable mouse events */
3135 out_str_nf((char_u *)"\033['z");
3136 ison = on;
3137 }
3138# endif
3139
3140# ifdef FEAT_MOUSE_GPM
3141 else
3142 {
3143 if (on)
3144 {
3145 if (gpm_open())
3146 ison = TRUE;
3147 }
3148 else
3149 {
3150 gpm_close();
3151 ison = FALSE;
3152 }
3153 }
3154# endif
3155
3156# ifdef FEAT_MOUSE_JSB
3157 else
3158 {
3159 if (on)
3160 {
3161 /* D - Enable Mouse up/down messages
3162 * L - Enable Left Button Reporting
3163 * M - Enable Middle Button Reporting
3164 * R - Enable Right Button Reporting
3165 * K - Enable SHIFT and CTRL key Reporting
3166 * + - Enable Advanced messaging of mouse moves and up/down messages
3167 * Q - Quiet No Ack
3168 * # - Numeric value of mouse pointer required
3169 * 0 = Multiview 2000 cursor, used as standard
3170 * 1 = Windows Arrow
3171 * 2 = Windows I Beam
3172 * 3 = Windows Hour Glass
3173 * 4 = Windows Cross Hair
3174 * 5 = Windows UP Arrow
3175 */
3176#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3177 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3178 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3179#else
3180 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3181 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3182#endif
3183 ison = TRUE;
3184 }
3185 else
3186 {
3187 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3188 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3189 ison = FALSE;
3190 }
3191 }
3192# endif
3193# ifdef FEAT_MOUSE_PTERM
3194 else
3195 {
3196 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3197 if (on)
3198 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3199 else
3200 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3201 ison = on;
3202 }
3203# endif
3204}
3205
3206/*
3207 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3208 */
3209 void
3210check_mouse_termcode()
3211{
3212# ifdef FEAT_MOUSE_XTERM
3213 if (use_xterm_mouse()
3214# ifdef FEAT_GUI
3215 && !gui.in_use
3216# endif
3217 )
3218 {
3219 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003220 ? IF_EB("\233M", CSI_STR "M")
3221 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003222 if (*p_mouse != NUL)
3223 {
3224 /* force mouse off and maybe on to send possibly new mouse
3225 * activation sequence to the xterm, with(out) drag tracing. */
3226 mch_setmouse(FALSE);
3227 setmouse();
3228 }
3229 }
3230 else
3231 del_mouse_termcode(KS_MOUSE);
3232# endif
3233
3234# ifdef FEAT_MOUSE_GPM
3235 if (!use_xterm_mouse()
3236# ifdef FEAT_GUI
3237 && !gui.in_use
3238# endif
3239 )
3240 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3241# endif
3242
3243# ifdef FEAT_MOUSE_JSB
3244 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3245 if (!use_xterm_mouse()
3246# ifdef FEAT_GUI
3247 && !gui.in_use
3248# endif
3249 )
3250 set_mouse_termcode(KS_JSBTERM_MOUSE,
3251 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3252 else
3253 del_mouse_termcode(KS_JSBTERM_MOUSE);
3254# endif
3255
3256# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003257 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258 * define it in the GUI or when using an xterm. */
3259 if (!use_xterm_mouse()
3260# ifdef FEAT_GUI
3261 && !gui.in_use
3262# endif
3263 )
3264 set_mouse_termcode(KS_NETTERM_MOUSE,
3265 (char_u *)IF_EB("\033}", ESC_STR "}"));
3266 else
3267 del_mouse_termcode(KS_NETTERM_MOUSE);
3268# endif
3269
3270# ifdef FEAT_MOUSE_DEC
3271 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3272 if (!use_xterm_mouse()
3273# ifdef FEAT_GUI
3274 && !gui.in_use
3275# endif
3276 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003277 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3278 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003279 else
3280 del_mouse_termcode(KS_DEC_MOUSE);
3281# endif
3282# ifdef FEAT_MOUSE_PTERM
3283 /* same as the dec mouse */
3284 if (!use_xterm_mouse()
3285# ifdef FEAT_GUI
3286 && !gui.in_use
3287# endif
3288 )
3289 set_mouse_termcode(KS_PTERM_MOUSE,
3290 (char_u *) IF_EB("\033[", ESC_STR "["));
3291 else
3292 del_mouse_termcode(KS_PTERM_MOUSE);
3293# endif
3294}
3295#endif
3296
3297/*
3298 * set screen mode, always fails.
3299 */
3300/* ARGSUSED */
3301 int
3302mch_screenmode(arg)
3303 char_u *arg;
3304{
3305 EMSG(_(e_screenmode));
3306 return FAIL;
3307}
3308
3309#ifndef VMS
3310
3311/*
3312 * Try to get the current window size:
3313 * 1. with an ioctl(), most accurate method
3314 * 2. from the environment variables LINES and COLUMNS
3315 * 3. from the termcap
3316 * 4. keep using the old values
3317 * Return OK when size could be determined, FAIL otherwise.
3318 */
3319 int
3320mch_get_shellsize()
3321{
3322 long rows = 0;
3323 long columns = 0;
3324 char_u *p;
3325
3326 /*
3327 * For OS/2 use _scrsize().
3328 */
3329# ifdef __EMX__
3330 {
3331 int s[2];
3332
3333 _scrsize(s);
3334 columns = s[0];
3335 rows = s[1];
3336 }
3337# endif
3338
3339 /*
3340 * 1. try using an ioctl. It is the most accurate method.
3341 *
3342 * Try using TIOCGWINSZ first, some systems that have it also define
3343 * TIOCGSIZE but don't have a struct ttysize.
3344 */
3345# ifdef TIOCGWINSZ
3346 {
3347 struct winsize ws;
3348 int fd = 1;
3349
3350 /* When stdout is not a tty, use stdin for the ioctl(). */
3351 if (!isatty(fd) && isatty(read_cmd_fd))
3352 fd = read_cmd_fd;
3353 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3354 {
3355 columns = ws.ws_col;
3356 rows = ws.ws_row;
3357 }
3358 }
3359# else /* TIOCGWINSZ */
3360# ifdef TIOCGSIZE
3361 {
3362 struct ttysize ts;
3363 int fd = 1;
3364
3365 /* When stdout is not a tty, use stdin for the ioctl(). */
3366 if (!isatty(fd) && isatty(read_cmd_fd))
3367 fd = read_cmd_fd;
3368 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3369 {
3370 columns = ts.ts_cols;
3371 rows = ts.ts_lines;
3372 }
3373 }
3374# endif /* TIOCGSIZE */
3375# endif /* TIOCGWINSZ */
3376
3377 /*
3378 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003379 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3380 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003381 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003382 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003383 {
3384 if ((p = (char_u *)getenv("LINES")))
3385 rows = atoi((char *)p);
3386 if ((p = (char_u *)getenv("COLUMNS")))
3387 columns = atoi((char *)p);
3388 }
3389
3390#ifdef HAVE_TGETENT
3391 /*
3392 * 3. try reading "co" and "li" entries from termcap
3393 */
3394 if (columns == 0 || rows == 0)
3395 getlinecol(&columns, &rows);
3396#endif
3397
3398 /*
3399 * 4. If everything fails, use the old values
3400 */
3401 if (columns <= 0 || rows <= 0)
3402 return FAIL;
3403
3404 Rows = rows;
3405 Columns = columns;
3406 return OK;
3407}
3408
3409/*
3410 * Try to set the window size to Rows and Columns.
3411 */
3412 void
3413mch_set_shellsize()
3414{
3415 if (*T_CWS)
3416 {
3417 /*
3418 * NOTE: if you get an error here that term_set_winsize() is
3419 * undefined, check the output of configure. It could probably not
3420 * find a ncurses, termcap or termlib library.
3421 */
3422 term_set_winsize((int)Rows, (int)Columns);
3423 out_flush();
3424 screen_start(); /* don't know where cursor is now */
3425 }
3426}
3427
3428#endif /* VMS */
3429
3430/*
3431 * Rows and/or Columns has changed.
3432 */
3433 void
3434mch_new_shellsize()
3435{
3436 /* Nothing to do. */
3437}
3438
Bram Moolenaardf177f62005-02-22 08:39:57 +00003439#ifndef USE_SYSTEM
3440static void append_ga_line __ARGS((garray_T *gap));
3441
3442/*
3443 * Append the text in "gap" below the cursor line and clear "gap".
3444 */
3445 static void
3446append_ga_line(gap)
3447 garray_T *gap;
3448{
3449 /* Remove trailing CR. */
3450 if (gap->ga_len > 0
3451 && !curbuf->b_p_bin
3452 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3453 --gap->ga_len;
3454 ga_append(gap, NUL);
3455 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3456 gap->ga_len = 0;
3457}
3458#endif
3459
Bram Moolenaar071d4272004-06-13 20:20:40 +00003460 int
3461mch_call_shell(cmd, options)
3462 char_u *cmd;
3463 int options; /* SHELL_*, see vim.h */
3464{
3465#ifdef VMS
3466 char *ifn = NULL;
3467 char *ofn = NULL;
3468#endif
3469 int tmode = cur_tmode;
3470#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3471 int x;
3472# ifndef __EMX__
3473 char_u *newcmd; /* only needed for unix */
3474# else
3475 /*
3476 * Set the preferred shell in the EMXSHELL environment variable (but
3477 * only if it is different from what is already in the environment).
3478 * Emx then takes care of whether to use "/c" or "-c" in an
3479 * intelligent way. Simply pass the whole thing to emx's system() call.
3480 * Emx also starts an interactive shell if system() is passed an empty
3481 * string.
3482 */
3483 char_u *p, *old;
3484
3485 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3486 {
3487 /* should check HAVE_SETENV, but I know we don't have it. */
3488 p = alloc(10 + strlen(p_sh));
3489 if (p)
3490 {
3491 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3492 putenv((char *)p); /* don't free the pointer! */
3493 }
3494 }
3495# endif
3496
3497 out_flush();
3498
3499 if (options & SHELL_COOKED)
3500 settmode(TMODE_COOK); /* set to normal mode */
3501
3502# ifdef __EMX__
3503 if (cmd == NULL)
3504 x = system(""); /* this starts an interactive shell in emx */
3505 else
3506 x = system((char *)cmd);
3507 /* system() returns -1 when error occurs in starting shell */
3508 if (x == -1 && !emsg_silent)
3509 {
3510 MSG_PUTS(_("\nCannot execute shell "));
3511 msg_outtrans(p_sh);
3512 msg_putchar('\n');
3513 }
3514# else /* not __EMX__ */
3515 if (cmd == NULL)
3516 x = system((char *)p_sh);
3517 else
3518 {
3519# ifdef VMS
3520 if (ofn = strchr((char *)cmd, '>'))
3521 *ofn++ = '\0';
3522 if (ifn = strchr((char *)cmd, '<'))
3523 {
3524 char *p;
3525
3526 *ifn++ = '\0';
3527 p = strchr(ifn,' '); /* chop off any trailing spaces */
3528 if (p)
3529 *p = '\0';
3530 }
3531 if (ofn)
3532 x = vms_sys((char *)cmd, ofn, ifn);
3533 else
3534 x = system((char *)cmd);
3535# else
3536 newcmd = lalloc(STRLEN(p_sh)
3537 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3538 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3539 if (newcmd == NULL)
3540 x = 0;
3541 else
3542 {
3543 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3544 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3545 (char *)p_shcf,
3546 (char *)cmd);
3547 x = system((char *)newcmd);
3548 vim_free(newcmd);
3549 }
3550# endif
3551 }
3552# ifdef VMS
3553 x = vms_sys_status(x);
3554# endif
3555 if (emsg_silent)
3556 ;
3557 else if (x == 127)
3558 MSG_PUTS(_("\nCannot execute shell sh\n"));
3559# endif /* __EMX__ */
3560 else if (x && !(options & SHELL_SILENT))
3561 {
3562 MSG_PUTS(_("\nshell returned "));
3563 msg_outnum((long)x);
3564 msg_putchar('\n');
3565 }
3566
3567 if (tmode == TMODE_RAW)
3568 settmode(TMODE_RAW); /* set to raw mode */
3569# ifdef FEAT_TITLE
3570 resettitle();
3571# endif
3572 return x;
3573
3574#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3575
Bram Moolenaardf177f62005-02-22 08:39:57 +00003576# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3577 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003578
3579 char_u *newcmd = NULL;
3580 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003581 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003582 pid_t wait_pid = 0;
3583# ifdef HAVE_UNION_WAIT
3584 union wait status;
3585# else
3586 int status = -1;
3587# endif
3588 int retval = -1;
3589 char **argv = NULL;
3590 int argc;
3591 int i;
3592 char_u *p;
3593 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003594 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003595# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003596 int pty_slave_fd = -1;
3597 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003598# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003599 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003600 int fd_fromshell[2];
3601 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003602# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003603 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003604# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003605 static char envbuf_Rows[20];
3606 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003607# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003608 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003609
3610 out_flush();
3611 if (options & SHELL_COOKED)
3612 settmode(TMODE_COOK); /* set to normal mode */
3613
Bram Moolenaar071d4272004-06-13 20:20:40 +00003614 newcmd = vim_strsave(p_sh);
3615 if (newcmd == NULL) /* out of memory */
3616 goto error;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003617
3618 /*
3619 * Do this loop twice:
3620 * 1: find number of arguments
3621 * 2: separate them and build argv[]
3622 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003623 for (i = 0; i < 2; ++i)
3624 {
3625 p = newcmd;
3626 inquote = FALSE;
3627 argc = 0;
3628 for (;;)
3629 {
3630 if (i == 1)
3631 argv[argc] = (char *)p;
3632 ++argc;
3633 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3634 {
3635 if (*p == '"')
3636 inquote = !inquote;
3637 ++p;
3638 }
3639 if (*p == NUL)
3640 break;
3641 if (i == 1)
3642 *p++ = NUL;
3643 p = skipwhite(p);
3644 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003645 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003646 {
3647 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3648 if (argv == NULL) /* out of memory */
3649 goto error;
3650 }
3651 }
3652 if (cmd != NULL)
3653 {
3654 if (extra_shell_arg != NULL)
3655 argv[argc++] = (char *)extra_shell_arg;
3656 argv[argc++] = (char *)p_shcf;
3657 argv[argc++] = (char *)cmd;
3658 }
3659 argv[argc] = NULL;
3660
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003662 * For the GUI, when writing the output into the buffer and when reading
3663 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3664 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003666 if ((options & (SHELL_READ|SHELL_WRITE))
3667# ifdef FEAT_GUI
3668 || (gui.in_use && show_shell_mess)
3669# endif
3670 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003671 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003672# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003673 /*
3674 * Try to open a master pty.
3675 * If this works, open the slave pty.
3676 * If the slave can't be opened, close the master pty.
3677 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003678 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003679 {
3680 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3681 if (pty_master_fd >= 0 && ((pty_slave_fd =
3682 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3683 {
3684 close(pty_master_fd);
3685 pty_master_fd = -1;
3686 }
3687 }
3688 /*
3689 * If not opening a pty or it didn't work, try using pipes.
3690 */
3691 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003692# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003693 {
3694 pipe_error = (pipe(fd_toshell) < 0);
3695 if (!pipe_error) /* pipe create OK */
3696 {
3697 pipe_error = (pipe(fd_fromshell) < 0);
3698 if (pipe_error) /* pipe create failed */
3699 {
3700 close(fd_toshell[0]);
3701 close(fd_toshell[1]);
3702 }
3703 }
3704 if (pipe_error)
3705 {
3706 MSG_PUTS(_("\nCannot create pipes\n"));
3707 out_flush();
3708 }
3709 }
3710 }
3711
3712 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003713 {
3714# ifdef __BEOS__
3715 beos_cleanup_read_thread();
3716# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003717
Bram Moolenaar071d4272004-06-13 20:20:40 +00003718 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3719 {
3720 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003721 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003722# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003723 || (gui.in_use && show_shell_mess)
3724# endif
3725 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003726 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003727# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003728 if (pty_master_fd >= 0) /* close the pseudo tty */
3729 {
3730 close(pty_master_fd);
3731 close(pty_slave_fd);
3732 }
3733 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003734# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003735 {
3736 close(fd_toshell[0]);
3737 close(fd_toshell[1]);
3738 close(fd_fromshell[0]);
3739 close(fd_fromshell[1]);
3740 }
3741 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003742 }
3743 else if (pid == 0) /* child */
3744 {
3745 reset_signals(); /* handle signals normally */
3746
3747 if (!show_shell_mess || (options & SHELL_EXPAND))
3748 {
3749 int fd;
3750
3751 /*
3752 * Don't want to show any message from the shell. Can't just
3753 * close stdout and stderr though, because some systems will
3754 * break if you try to write to them after that, so we must
3755 * use dup() to replace them with something else -- webb
3756 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3757 * waiting for input.
3758 */
3759 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3760 fclose(stdin);
3761 fclose(stdout);
3762 fclose(stderr);
3763
3764 /*
3765 * If any of these open()'s and dup()'s fail, we just continue
3766 * anyway. It's not fatal, and on most systems it will make
3767 * no difference at all. On a few it will cause the execvp()
3768 * to exit with a non-zero status even when the completion
3769 * could be done, which is nothing too serious. If the open()
3770 * or dup() failed we'd just do the same thing ourselves
3771 * anyway -- webb
3772 */
3773 if (fd >= 0)
3774 {
3775 dup(fd); /* To replace stdin (file descriptor 0) */
3776 dup(fd); /* To replace stdout (file descriptor 1) */
3777 dup(fd); /* To replace stderr (file descriptor 2) */
3778
3779 /* Don't need this now that we've duplicated it */
3780 close(fd);
3781 }
3782 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003783 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003784# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003785 || gui.in_use
3786# endif
3787 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003788 {
3789
Bram Moolenaardf177f62005-02-22 08:39:57 +00003790# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003791 /* Create our own process group, so that the child and all its
3792 * children can be kill()ed. Don't do this when using pipes,
3793 * because stdin is not a tty, we would loose /dev/tty. */
3794 if (p_stmp)
3795 (void)setsid();
Bram Moolenaardf177f62005-02-22 08:39:57 +00003796# endif
3797# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003798 if (pty_slave_fd >= 0)
3799 {
3800 /* push stream discipline modules */
3801 if (options & SHELL_COOKED)
3802 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003803# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003804 /* Try to become controlling tty (probably doesn't work,
3805 * unless run by root) */
3806 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003807# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003808 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003809# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003810 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003811# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812 setenv("TERM", "dumb", 1);
3813 sprintf((char *)envbuf, "%ld", Rows);
3814 setenv("ROWS", (char *)envbuf, 1);
3815 sprintf((char *)envbuf, "%ld", Rows);
3816 setenv("LINES", (char *)envbuf, 1);
3817 sprintf((char *)envbuf, "%ld", Columns);
3818 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003819# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 /*
3821 * Putenv does not copy the string, it has to remain valid.
3822 * Use a static array to avoid loosing allocated memory.
3823 */
3824 putenv("TERM=dumb");
3825 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
3826 putenv(envbuf_Rows);
3827 sprintf(envbuf_Rows, "LINES=%ld", Rows);
3828 putenv(envbuf_Rows);
3829 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
3830 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003831# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003832
Bram Moolenaara5792f52005-11-23 21:25:05 +00003833 /*
3834 * stderr is only redirected when using the GUI, so that a
3835 * program like gpg can still access the terminal to get a
3836 * passphrase using stderr.
3837 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003838# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003839 if (pty_master_fd >= 0)
3840 {
3841 close(pty_master_fd); /* close master side of pty */
3842
3843 /* set up stdin/stdout/stderr for the child */
3844 close(0);
3845 dup(pty_slave_fd);
3846 close(1);
3847 dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003848 if (gui.in_use)
3849 {
3850 close(2);
3851 dup(pty_slave_fd);
3852 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003853
3854 close(pty_slave_fd); /* has been dupped, close it now */
3855 }
3856 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003857# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003858 {
3859 /* set up stdin for the child */
3860 close(fd_toshell[1]);
3861 close(0);
3862 dup(fd_toshell[0]);
3863 close(fd_toshell[0]);
3864
3865 /* set up stdout for the child */
3866 close(fd_fromshell[0]);
3867 close(1);
3868 dup(fd_fromshell[1]);
3869 close(fd_fromshell[1]);
3870
Bram Moolenaara5792f52005-11-23 21:25:05 +00003871# ifdef FEAT_GUI
3872 if (gui.in_use)
3873 {
3874 /* set up stderr for the child */
3875 close(2);
3876 dup(1);
3877 }
3878# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003879 }
3880 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003881
Bram Moolenaar071d4272004-06-13 20:20:40 +00003882 /*
3883 * There is no type cast for the argv, because the type may be
3884 * different on different machines. This may cause a warning
3885 * message with strict compilers, don't worry about it.
3886 * Call _exit() instead of exit() to avoid closing the connection
3887 * to the X server (esp. with GTK, which uses atexit()).
3888 */
3889 execvp(argv[0], argv);
3890 _exit(EXEC_FAILED); /* exec failed, return failure code */
3891 }
3892 else /* parent */
3893 {
3894 /*
3895 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003896 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003897 */
3898 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003899 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003900
3901 /*
3902 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003903 * This is also used to pipe stdin/stdout to/from the external
3904 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003906 if ((options & (SHELL_READ|SHELL_WRITE))
3907# ifdef FEAT_GUI
3908 || (gui.in_use && show_shell_mess)
3909# endif
3910 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003911 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003912# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003913 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003914# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003915 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003916# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003917 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
3918 int ta_len = 0; /* valid bytes in ta_buf[] */
3919 int len;
3920 int p_more_save;
3921 int old_State;
3922 int c;
3923 int toshell_fd;
3924 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003925 garray_T ga;
3926 int noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927
Bram Moolenaardf177f62005-02-22 08:39:57 +00003928# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003929 if (pty_master_fd >= 0)
3930 {
3931 close(pty_slave_fd); /* close slave side of pty */
3932 fromshell_fd = pty_master_fd;
3933 toshell_fd = dup(pty_master_fd);
3934 }
3935 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003936# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003937 {
3938 close(fd_toshell[0]);
3939 close(fd_fromshell[1]);
3940 toshell_fd = fd_toshell[1];
3941 fromshell_fd = fd_fromshell[0];
3942 }
3943
3944 /*
3945 * Write to the child if there are typed characters.
3946 * Read from the child if there are characters available.
3947 * Repeat the reading a few times if more characters are
3948 * available. Need to check for typed keys now and then, but
3949 * not too often (delays when no chars are available).
3950 * This loop is quit if no characters can be read from the pty
3951 * (WaitForChar detected special condition), or there are no
3952 * characters available and the child has exited.
3953 * Only check if the child has exited when there is no more
3954 * output. The child may exit before all the output has
3955 * been printed.
3956 *
3957 * Currently this busy loops!
3958 * This can probably dead-lock when the write blocks!
3959 */
3960 p_more_save = p_more;
3961 p_more = FALSE;
3962 old_State = State;
3963 State = EXTERNCMD; /* don't redraw at window resize */
3964
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003965 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003966 {
3967 /* Fork a process that will write the lines to the
3968 * external program. */
3969 if ((wpid = fork()) == -1)
3970 {
3971 MSG_PUTS(_("\nCannot fork\n"));
3972 }
3973 else if (wpid == 0)
3974 {
3975 linenr_T lnum = curbuf->b_op_start.lnum;
3976 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00003977 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003978 char_u *s;
3979 size_t l;
3980
3981 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00003982 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003983 for (;;)
3984 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00003985 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003986 if (l == 0)
3987 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00003988 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003989 /* NL -> NUL translation */
3990 len = write(toshell_fd, "", (size_t)1);
3991 else
3992 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00003993 s = vim_strchr(lp + written, NL);
3994 len = write(toshell_fd, (char *)lp + written,
3995 s == NULL ? l : s - (lp + written));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003996 }
3997 if (len == l)
3998 {
3999 /* Finished a line, add a NL, unless this line
4000 * should not have one. */
4001 if (lnum != curbuf->b_op_end.lnum
4002 || !curbuf->b_p_bin
4003 || (lnum != write_no_eol_lnum
4004 && (lnum !=
4005 curbuf->b_ml.ml_line_count
4006 || curbuf->b_p_eol)))
4007 write(toshell_fd, "\n", (size_t)1);
4008 ++lnum;
4009 if (lnum > curbuf->b_op_end.lnum)
4010 {
4011 /* finished all the lines, close pipe */
4012 close(toshell_fd);
4013 toshell_fd = -1;
4014 break;
4015 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004016 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004017 written = 0;
4018 }
4019 else if (len > 0)
4020 written += len;
4021 }
4022 _exit(0);
4023 }
4024 else
4025 {
4026 close(toshell_fd);
4027 toshell_fd = -1;
4028 }
4029 }
4030
4031 if (options & SHELL_READ)
4032 ga_init2(&ga, 1, BUFLEN);
4033
4034 noread_cnt = 0;
4035
Bram Moolenaar071d4272004-06-13 20:20:40 +00004036 for (;;)
4037 {
4038 /*
4039 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004040 * if there are any.
4041 * Don't do this if we are expanding wild cards (would eat
4042 * typeahead).
4043 * Don't do this when filtering and terminal is in cooked
4044 * mode, the shell command will handle the I/O. Avoids
4045 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004046 * Don't get characters when the child has already
4047 * finished (wait_pid == 0).
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004048 * Don't get extra characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004049 * Don't read characters unless we didn't get output for a
4050 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004051 */
4052 len = 0;
4053 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004054 && ((options &
4055 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4056 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
4057#ifdef FEAT_GUI
4058 || gui.in_use
4059#endif
4060 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004061 && wait_pid == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004062 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00004063 || (noread_cnt > 4
4064 && (len = ui_inchar(ta_buf,
4065 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004066 {
4067 /*
4068 * For pipes:
4069 * Check for CTRL-C: send interrupt signal to child.
4070 * Check for CTRL-D: EOF, close pipe to child.
4071 */
4072 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4073 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004074# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004075 /*
4076 * Send SIGINT to the child's group or all
4077 * processes in our group.
4078 */
4079 if (ta_buf[ta_len] == Ctrl_C
4080 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004081 {
4082# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004083 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004084# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004086# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004087 if (wpid > 0)
4088 kill(wpid, SIGINT);
4089 }
4090# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004091 if (pty_master_fd < 0 && toshell_fd >= 0
4092 && ta_buf[ta_len] == Ctrl_D)
4093 {
4094 close(toshell_fd);
4095 toshell_fd = -1;
4096 }
4097 }
4098
4099 /* replace K_BS by <BS> and K_DEL by <DEL> */
4100 for (i = ta_len; i < ta_len + len; ++i)
4101 {
4102 if (ta_buf[i] == CSI && len - i > 2)
4103 {
4104 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4105 if (c == K_DEL || c == K_KDEL || c == K_BS)
4106 {
4107 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4108 (size_t)(len - i - 2));
4109 if (c == K_DEL || c == K_KDEL)
4110 ta_buf[i] = DEL;
4111 else
4112 ta_buf[i] = Ctrl_H;
4113 len -= 2;
4114 }
4115 }
4116 else if (ta_buf[i] == '\r')
4117 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004118# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004120 i += (*mb_ptr2len)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004121# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004122 }
4123
4124 /*
4125 * For pipes: echo the typed characters.
4126 * For a pty this does not seem to work.
4127 */
4128 if (pty_master_fd < 0)
4129 {
4130 for (i = ta_len; i < ta_len + len; ++i)
4131 {
4132 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4133 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004134# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004135 else if (has_mbyte)
4136 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004137 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138
4139 msg_outtrans_len(ta_buf + i, l);
4140 i += l - 1;
4141 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004142# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004143 else
4144 msg_outtrans_len(ta_buf + i, 1);
4145 }
4146 windgoto(msg_row, msg_col);
4147 out_flush();
4148 }
4149
4150 ta_len += len;
4151
4152 /*
4153 * Write the characters to the child, unless EOF has
4154 * been typed for pipes. Write one character at a
4155 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004156 * When writing buffer lines, drop the typed
4157 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004158 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004159 if (options & SHELL_WRITE)
4160 ta_len = 0;
4161 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162 {
4163 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4164 if (len > 0)
4165 {
4166 ta_len -= len;
4167 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004168 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169 }
4170 }
4171 }
4172
Bram Moolenaardf177f62005-02-22 08:39:57 +00004173 if (got_int)
4174 {
4175 /* CTRL-C sends a signal to the child, we ignore it
4176 * ourselves */
4177# ifdef HAVE_SETSID
4178 kill(-pid, SIGINT);
4179# else
4180 kill(0, SIGINT);
4181# endif
4182 if (wpid > 0)
4183 kill(wpid, SIGINT);
4184 got_int = FALSE;
4185 }
4186
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187 /*
4188 * Check if the child has any characters to be printed.
4189 * Read them and write them to our window. Repeat this as
4190 * long as there is something to do, avoid the 10ms wait
4191 * for mch_inchar(), or sending typeahead characters to
4192 * the external process.
4193 * TODO: This should handle escape sequences, compatible
4194 * to some terminal (vt52?).
4195 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004196 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004197 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4198 {
4199 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004200# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004201 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004202# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004203 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004204# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004205 );
4206 if (len <= 0) /* end of file or error */
4207 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004208
4209 noread_cnt = 0;
4210 if (options & SHELL_READ)
4211 {
4212 /* Do NUL -> NL translation, append NL separated
4213 * lines to the current buffer. */
4214 for (i = 0; i < len; ++i)
4215 {
4216 if (buffer[i] == NL)
4217 append_ga_line(&ga);
4218 else if (buffer[i] == NUL)
4219 ga_append(&ga, NL);
4220 else
4221 ga_append(&ga, buffer[i]);
4222 }
4223 }
4224# ifdef FEAT_MBYTE
4225 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004226 {
4227 int l;
4228
Bram Moolenaardf177f62005-02-22 08:39:57 +00004229 len += buffer_off;
4230 buffer[len] = NUL;
4231
Bram Moolenaar071d4272004-06-13 20:20:40 +00004232 /* Check if the last character in buffer[] is
4233 * incomplete, keep these bytes for the next
4234 * round. */
4235 for (p = buffer; p < buffer + len; p += l)
4236 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004237 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004238 if (l == 0)
4239 l = 1; /* NUL byte? */
4240 else if (MB_BYTE2LEN(*p) != l)
4241 break;
4242 }
4243 if (p == buffer) /* no complete character */
4244 {
4245 /* avoid getting stuck at an illegal byte */
4246 if (len >= 12)
4247 ++p;
4248 else
4249 {
4250 buffer_off = len;
4251 continue;
4252 }
4253 }
4254 c = *p;
4255 *p = NUL;
4256 msg_puts(buffer);
4257 if (p < buffer + len)
4258 {
4259 *p = c;
4260 buffer_off = (buffer + len) - p;
4261 mch_memmove(buffer, p, buffer_off);
4262 continue;
4263 }
4264 buffer_off = 0;
4265 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004266# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004267 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004268 {
4269 buffer[len] = NUL;
4270 msg_puts(buffer);
4271 }
4272
4273 windgoto(msg_row, msg_col);
4274 cursor_on();
4275 out_flush();
4276 if (got_int)
4277 break;
4278 }
4279
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004280 /* If we already detected the child has finished break the
4281 * loop now. */
4282 if (wait_pid == pid)
4283 break;
4284
Bram Moolenaar071d4272004-06-13 20:20:40 +00004285 /*
4286 * Check if the child still exists, before checking for
4287 * typed characters (otherwise we would loose typeahead).
4288 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004289# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004290 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004291# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004292 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004293# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004294 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4295 || (wait_pid == pid && WIFEXITED(status)))
4296 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004297 /* Don't break the loop yet, try reading more
4298 * characters from "fromshell_fd" first. When using
4299 * pipes there might still be something to read and
4300 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004302 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004303 else
4304 wait_pid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004305 }
4306finished:
4307 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004308 if (options & SHELL_READ)
4309 {
4310 if (ga.ga_len > 0)
4311 {
4312 append_ga_line(&ga);
4313 /* remember that the NL was missing */
4314 write_no_eol_lnum = curwin->w_cursor.lnum;
4315 }
4316 else
4317 write_no_eol_lnum = 0;
4318 ga_clear(&ga);
4319 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 /*
4322 * Give all typeahead that wasn't used back to ui_inchar().
4323 */
4324 if (ta_len)
4325 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004326 State = old_State;
4327 if (toshell_fd >= 0)
4328 close(toshell_fd);
4329 close(fromshell_fd);
4330 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004331
4332 /*
4333 * Wait until our child has exited.
4334 * Ignore wait() returning pids of other children and returning
4335 * because of some signal like SIGWINCH.
4336 * Don't wait if wait_pid was already set above, indicating the
4337 * child already exited.
4338 */
4339 while (wait_pid != pid)
4340 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004341# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342 /* Ugly hack: when compiled with Python threads are probably
4343 * used, in which case wait() sometimes hangs for no obvious
4344 * reason. Use waitpid() instead and loop (like the GUI). */
4345# ifdef __NeXT__
4346 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4347# else
4348 wait_pid = waitpid(pid, &status, WNOHANG);
4349# endif
4350 if (wait_pid == 0)
4351 {
4352 /* Wait for 1/100 sec before trying again. */
4353 mch_delay(10L, TRUE);
4354 continue;
4355 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004356# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004357 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004358# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359 if (wait_pid <= 0
4360# ifdef ECHILD
4361 && errno == ECHILD
4362# endif
4363 )
4364 break;
4365 }
4366
Bram Moolenaardf177f62005-02-22 08:39:57 +00004367 /* Make sure the child that writes to the external program is
4368 * dead. */
4369 if (wpid > 0)
4370 kill(wpid, SIGKILL);
4371
Bram Moolenaar071d4272004-06-13 20:20:40 +00004372 /*
4373 * Set to raw mode right now, otherwise a CTRL-C after
4374 * catch_signals() will kill Vim.
4375 */
4376 if (tmode == TMODE_RAW)
4377 settmode(TMODE_RAW);
4378 did_settmode = TRUE;
4379 set_signals();
4380
4381 if (WIFEXITED(status))
4382 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004383 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004384 retval = WEXITSTATUS(status);
4385 if (retval && !emsg_silent)
4386 {
4387 if (retval == EXEC_FAILED)
4388 {
4389 MSG_PUTS(_("\nCannot execute shell "));
4390 msg_outtrans(p_sh);
4391 msg_putchar('\n');
4392 }
4393 else if (!(options & SHELL_SILENT))
4394 {
4395 MSG_PUTS(_("\nshell returned "));
4396 msg_outnum((long)retval);
4397 msg_putchar('\n');
4398 }
4399 }
4400 }
4401 else
4402 MSG_PUTS(_("\nCommand terminated\n"));
4403 }
4404 }
4405 vim_free(argv);
4406
4407error:
4408 if (!did_settmode)
4409 if (tmode == TMODE_RAW)
4410 settmode(TMODE_RAW); /* set to raw mode */
4411# ifdef FEAT_TITLE
4412 resettitle();
4413# endif
4414 vim_free(newcmd);
4415
4416 return retval;
4417
4418#endif /* USE_SYSTEM */
4419}
4420
4421/*
4422 * Check for CTRL-C typed by reading all available characters.
4423 * In cooked mode we should get SIGINT, no need to check.
4424 */
4425 void
4426mch_breakcheck()
4427{
4428 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4429 fill_input_buf(FALSE);
4430}
4431
4432/*
4433 * Wait "msec" msec until a character is available from the keyboard or from
4434 * inbuf[]. msec == -1 will block forever.
4435 * When a GUI is being used, this will never get called -- webb
4436 */
4437 static int
4438WaitForChar(msec)
4439 long msec;
4440{
4441#ifdef FEAT_MOUSE_GPM
4442 int gpm_process_wanted;
4443#endif
4444#ifdef FEAT_XCLIPBOARD
4445 int rest;
4446#endif
4447 int avail;
4448
4449 if (input_available()) /* something in inbuf[] */
4450 return 1;
4451
4452#if defined(FEAT_MOUSE_DEC)
4453 /* May need to query the mouse position. */
4454 if (WantQueryMouse)
4455 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004456 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004457 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4458 }
4459#endif
4460
4461 /*
4462 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4463 * events. This is a bit complicated, because they might both be defined.
4464 */
4465#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4466# ifdef FEAT_XCLIPBOARD
4467 rest = 0;
4468 if (do_xterm_trace())
4469 rest = msec;
4470# endif
4471 do
4472 {
4473# ifdef FEAT_XCLIPBOARD
4474 if (rest != 0)
4475 {
4476 msec = XT_TRACE_DELAY;
4477 if (rest >= 0 && rest < XT_TRACE_DELAY)
4478 msec = rest;
4479 if (rest >= 0)
4480 rest -= msec;
4481 }
4482# endif
4483# ifdef FEAT_MOUSE_GPM
4484 gpm_process_wanted = 0;
4485 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4486# else
4487 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4488# endif
4489 if (!avail)
4490 {
4491 if (input_available())
4492 return 1;
4493# ifdef FEAT_XCLIPBOARD
4494 if (rest == 0 || !do_xterm_trace())
4495# endif
4496 break;
4497 }
4498 }
4499 while (FALSE
4500# ifdef FEAT_MOUSE_GPM
4501 || (gpm_process_wanted && mch_gpm_process() == 0)
4502# endif
4503# ifdef FEAT_XCLIPBOARD
4504 || (!avail && rest != 0)
4505# endif
4506 );
4507
4508#else
4509 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4510#endif
4511 return avail;
4512}
4513
4514/*
4515 * Wait "msec" msec until a character is available from file descriptor "fd".
4516 * Time == -1 will block forever.
4517 * When a GUI is being used, this will not be used for input -- webb
4518 * Returns also, when a request from Sniff is waiting -- toni.
4519 * Or when a Linux GPM mouse event is waiting.
4520 */
4521/* ARGSUSED */
4522#if defined(__BEOS__)
4523 int
4524#else
4525 static int
4526#endif
4527RealWaitForChar(fd, msec, check_for_gpm)
4528 int fd;
4529 long msec;
4530 int *check_for_gpm;
4531{
4532 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004533#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 static int busy = FALSE;
4535
4536 /* May retry getting characters after an event was handled. */
4537# define MAY_LOOP
4538
4539# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4540 /* Remember at what time we started, so that we know how much longer we
4541 * should wait after being interrupted. */
4542# define USE_START_TV
4543 struct timeval start_tv;
4544
4545 if (msec > 0 && (
4546# ifdef FEAT_XCLIPBOARD
4547 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004548# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549 ||
4550# endif
4551# endif
4552# ifdef USE_XSMP
4553 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004554# ifdef FEAT_MZSCHEME
4555 ||
4556# endif
4557# endif
4558# ifdef FEAT_MZSCHEME
4559 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560# endif
4561 ))
4562 gettimeofday(&start_tv, NULL);
4563# endif
4564
4565 /* Handle being called recursively. This may happen for the session
4566 * manager stuff, it may save the file, which does a breakcheck. */
4567 if (busy)
4568 return 0;
4569#endif
4570
4571#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00004572 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004573#endif
4574 {
4575#ifdef MAY_LOOP
4576 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004577# ifdef FEAT_MZSCHEME
4578 int mzquantum_used = FALSE;
4579# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004580#endif
4581#ifndef HAVE_SELECT
4582 struct pollfd fds[5];
4583 int nfd;
4584# ifdef FEAT_XCLIPBOARD
4585 int xterm_idx = -1;
4586# endif
4587# ifdef FEAT_MOUSE_GPM
4588 int gpm_idx = -1;
4589# endif
4590# ifdef USE_XSMP
4591 int xsmp_idx = -1;
4592# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004593 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004594
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004595# ifdef FEAT_MZSCHEME
4596 mzvim_check_threads();
4597 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4598 {
4599 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4600 mzquantum_used = TRUE;
4601 }
4602# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004603 fds[0].fd = fd;
4604 fds[0].events = POLLIN;
4605 nfd = 1;
4606
4607# ifdef FEAT_SNIFF
4608# define SNIFF_IDX 1
4609 if (want_sniff_request)
4610 {
4611 fds[SNIFF_IDX].fd = fd_from_sniff;
4612 fds[SNIFF_IDX].events = POLLIN;
4613 nfd++;
4614 }
4615# endif
4616# ifdef FEAT_XCLIPBOARD
4617 if (xterm_Shell != (Widget)0)
4618 {
4619 xterm_idx = nfd;
4620 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4621 fds[nfd].events = POLLIN;
4622 nfd++;
4623 }
4624# endif
4625# ifdef FEAT_MOUSE_GPM
4626 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4627 {
4628 gpm_idx = nfd;
4629 fds[nfd].fd = gpm_fd;
4630 fds[nfd].events = POLLIN;
4631 nfd++;
4632 }
4633# endif
4634# ifdef USE_XSMP
4635 if (xsmp_icefd != -1)
4636 {
4637 xsmp_idx = nfd;
4638 fds[nfd].fd = xsmp_icefd;
4639 fds[nfd].events = POLLIN;
4640 nfd++;
4641 }
4642# endif
4643
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004644 ret = poll(fds, nfd, towait);
4645# ifdef FEAT_MZSCHEME
4646 if (ret == 0 && mzquantum_used)
4647 /* MzThreads scheduling is required and timeout occured */
4648 finished = FALSE;
4649# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004650
4651# ifdef FEAT_SNIFF
4652 if (ret < 0)
4653 sniff_disconnect(1);
4654 else if (want_sniff_request)
4655 {
4656 if (fds[SNIFF_IDX].revents & POLLHUP)
4657 sniff_disconnect(1);
4658 if (fds[SNIFF_IDX].revents & POLLIN)
4659 sniff_request_waiting = 1;
4660 }
4661# endif
4662# ifdef FEAT_XCLIPBOARD
4663 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4664 {
4665 xterm_update(); /* Maybe we should hand out clipboard */
4666 if (--ret == 0 && !input_available())
4667 /* Try again */
4668 finished = FALSE;
4669 }
4670# endif
4671# ifdef FEAT_MOUSE_GPM
4672 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4673 {
4674 *check_for_gpm = 1;
4675 }
4676# endif
4677# ifdef USE_XSMP
4678 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4679 {
4680 if (fds[xsmp_idx].revents & POLLIN)
4681 {
4682 busy = TRUE;
4683 xsmp_handle_requests();
4684 busy = FALSE;
4685 }
4686 else if (fds[xsmp_idx].revents & POLLHUP)
4687 {
4688 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004689 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690 xsmp_close();
4691 }
4692 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004693 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004694 }
4695# endif
4696
4697
4698#else /* HAVE_SELECT */
4699
4700 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004701 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702 fd_set rfds, efds;
4703 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004704 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004705
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004706# ifdef FEAT_MZSCHEME
4707 mzvim_check_threads();
4708 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4709 {
4710 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4711 mzquantum_used = TRUE;
4712 }
4713# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714# ifdef __EMX__
4715 /* don't check for incoming chars if not in raw mode, because select()
4716 * always returns TRUE then (in some version of emx.dll) */
4717 if (curr_tmode != TMODE_RAW)
4718 return 0;
4719# endif
4720
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004721 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004722 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004723 tv.tv_sec = towait / 1000;
4724 tv.tv_usec = (towait % 1000) * (1000000/1000);
4725 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004726 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004727 else
4728 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004729
4730 /*
4731 * Select on ready for reading and exceptional condition (end of file).
4732 */
4733 FD_ZERO(&rfds); /* calls bzero() on a sun */
4734 FD_ZERO(&efds);
4735 FD_SET(fd, &rfds);
4736# if !defined(__QNX__) && !defined(__CYGWIN32__)
4737 /* For QNX select() always returns 1 if this is set. Why? */
4738 FD_SET(fd, &efds);
4739# endif
4740 maxfd = fd;
4741
4742# ifdef FEAT_SNIFF
4743 if (want_sniff_request)
4744 {
4745 FD_SET(fd_from_sniff, &rfds);
4746 FD_SET(fd_from_sniff, &efds);
4747 if (maxfd < fd_from_sniff)
4748 maxfd = fd_from_sniff;
4749 }
4750# endif
4751# ifdef FEAT_XCLIPBOARD
4752 if (xterm_Shell != (Widget)0)
4753 {
4754 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4755 if (maxfd < ConnectionNumber(xterm_dpy))
4756 maxfd = ConnectionNumber(xterm_dpy);
4757 }
4758# endif
4759# ifdef FEAT_MOUSE_GPM
4760 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4761 {
4762 FD_SET(gpm_fd, &rfds);
4763 FD_SET(gpm_fd, &efds);
4764 if (maxfd < gpm_fd)
4765 maxfd = gpm_fd;
4766 }
4767# endif
4768# ifdef USE_XSMP
4769 if (xsmp_icefd != -1)
4770 {
4771 FD_SET(xsmp_icefd, &rfds);
4772 FD_SET(xsmp_icefd, &efds);
4773 if (maxfd < xsmp_icefd)
4774 maxfd = xsmp_icefd;
4775 }
4776# endif
4777
4778# ifdef OLD_VMS
4779 /* Old VMS as v6.2 and older have broken select(). It waits more than
4780 * required. Should not be used */
4781 ret = 0;
4782# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004783 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4784# endif
Bram Moolenaar311d9822007-02-27 15:48:28 +00004785# ifdef __TANDEM
4786 if (ret == -1 && errno == ENOTSUP)
4787 {
4788 FD_ZERO(&rfds);
4789 FD_ZERO(&efds);
4790 ret = 0;
4791 }
4792#endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004793# ifdef FEAT_MZSCHEME
4794 if (ret == 0 && mzquantum_used)
4795 /* loop if MzThreads must be scheduled and timeout occured */
4796 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004797# endif
4798
4799# ifdef FEAT_SNIFF
4800 if (ret < 0 )
4801 sniff_disconnect(1);
4802 else if (ret > 0 && want_sniff_request)
4803 {
4804 if (FD_ISSET(fd_from_sniff, &efds))
4805 sniff_disconnect(1);
4806 if (FD_ISSET(fd_from_sniff, &rfds))
4807 sniff_request_waiting = 1;
4808 }
4809# endif
4810# ifdef FEAT_XCLIPBOARD
4811 if (ret > 0 && xterm_Shell != (Widget)0
4812 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4813 {
4814 xterm_update(); /* Maybe we should hand out clipboard */
4815 /* continue looping when we only got the X event and the input
4816 * buffer is empty */
4817 if (--ret == 0 && !input_available())
4818 {
4819 /* Try again */
4820 finished = FALSE;
4821 }
4822 }
4823# endif
4824# ifdef FEAT_MOUSE_GPM
4825 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4826 {
4827 if (FD_ISSET(gpm_fd, &efds))
4828 gpm_close();
4829 else if (FD_ISSET(gpm_fd, &rfds))
4830 *check_for_gpm = 1;
4831 }
4832# endif
4833# ifdef USE_XSMP
4834 if (ret > 0 && xsmp_icefd != -1)
4835 {
4836 if (FD_ISSET(xsmp_icefd, &efds))
4837 {
4838 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004839 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004840 xsmp_close();
4841 if (--ret == 0)
4842 finished = FALSE; /* keep going if event was only one */
4843 }
4844 else if (FD_ISSET(xsmp_icefd, &rfds))
4845 {
4846 busy = TRUE;
4847 xsmp_handle_requests();
4848 busy = FALSE;
4849 if (--ret == 0)
4850 finished = FALSE; /* keep going if event was only one */
4851 }
4852 }
4853# endif
4854
4855#endif /* HAVE_SELECT */
4856
4857#ifdef MAY_LOOP
4858 if (finished || msec == 0)
4859 break;
4860
4861 /* We're going to loop around again, find out for how long */
4862 if (msec > 0)
4863 {
4864# ifdef USE_START_TV
4865 struct timeval mtv;
4866
4867 /* Compute remaining wait time. */
4868 gettimeofday(&mtv, NULL);
4869 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
4870 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
4871# else
4872 /* Guess we got interrupted halfway. */
4873 msec = msec / 2;
4874# endif
4875 if (msec <= 0)
4876 break; /* waited long enough */
4877 }
4878#endif
4879 }
4880
4881 return (ret > 0);
4882}
4883
4884#ifndef VMS
4885
4886#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004887/*
Bram Moolenaar02743632005-07-25 20:42:36 +00004888 * Expand a path into all matching files and/or directories. Handles "*",
4889 * "?", "[a-z]", "**", etc.
4890 * "path" has backslashes before chars that are not to be expanded.
4891 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004892 */
4893 int
4894mch_expandpath(gap, path, flags)
4895 garray_T *gap;
4896 char_u *path;
4897 int flags; /* EW_* flags */
4898{
Bram Moolenaar02743632005-07-25 20:42:36 +00004899 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004900}
4901#endif
4902
4903/*
4904 * mch_expand_wildcards() - this code does wild-card pattern matching using
4905 * the shell
4906 *
4907 * return OK for success, FAIL for error (you may lose some memory) and put
4908 * an error message in *file.
4909 *
4910 * num_pat is number of input patterns
4911 * pat is array of pointers to input patterns
4912 * num_file is pointer to number of matched file names
4913 * file is pointer to array of pointers to matched file names
4914 */
4915
4916#ifndef SEEK_SET
4917# define SEEK_SET 0
4918#endif
4919#ifndef SEEK_END
4920# define SEEK_END 2
4921#endif
4922
Bram Moolenaar5555acc2006-04-07 21:33:12 +00004923#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00004924
Bram Moolenaar071d4272004-06-13 20:20:40 +00004925/* ARGSUSED */
4926 int
4927mch_expand_wildcards(num_pat, pat, num_file, file, flags)
4928 int num_pat;
4929 char_u **pat;
4930 int *num_file;
4931 char_u ***file;
4932 int flags; /* EW_* flags */
4933{
4934 int i;
4935 size_t len;
4936 char_u *p;
4937 int dir;
4938#ifdef __EMX__
4939# define EXPL_ALLOC_INC 16
4940 char_u **expl_files;
4941 size_t files_alloced, files_free;
4942 char_u *buf;
4943 int has_wildcard;
4944
4945 *num_file = 0; /* default: no files found */
4946 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
4947 files_free = EXPL_ALLOC_INC; /* how much space is not used */
4948 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
4949 if (*file == NULL)
4950 return FAIL;
4951
4952 for (; num_pat > 0; num_pat--, pat++)
4953 {
4954 expl_files = NULL;
4955 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
4956 /* expand environment var or home dir */
4957 buf = expand_env_save(*pat);
4958 else
4959 buf = vim_strsave(*pat);
4960 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00004961 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004962 if (has_wildcard) /* yes, so expand them */
4963 expl_files = (char_u **)_fnexplode(buf);
4964
4965 /*
4966 * return value of buf if no wildcards left,
4967 * OR if no match AND EW_NOTFOUND is set.
4968 */
4969 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
4970 || (expl_files == NULL && (flags & EW_NOTFOUND)))
4971 { /* simply save the current contents of *buf */
4972 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
4973 if (expl_files != NULL)
4974 {
4975 expl_files[0] = vim_strsave(buf);
4976 expl_files[1] = NULL;
4977 }
4978 }
4979 vim_free(buf);
4980
4981 /*
4982 * Count number of names resulting from expansion,
4983 * At the same time add a backslash to the end of names that happen to
4984 * be directories, and replace slashes with backslashes.
4985 */
4986 if (expl_files)
4987 {
4988 for (i = 0; (p = expl_files[i]) != NULL; i++)
4989 {
4990 dir = mch_isdir(p);
4991 /* If we don't want dirs and this is one, skip it */
4992 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
4993 continue;
4994
Bram Moolenaara2031822006-03-07 22:29:51 +00004995 /* Skip files that are not executable if we check for that. */
4996 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
4997 continue;
4998
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999 if (--files_free == 0)
5000 {
5001 /* need more room in table of pointers */
5002 files_alloced += EXPL_ALLOC_INC;
5003 *file = (char_u **)vim_realloc(*file,
5004 sizeof(char_u **) * files_alloced);
5005 if (*file == NULL)
5006 {
5007 EMSG(_(e_outofmem));
5008 *num_file = 0;
5009 return FAIL;
5010 }
5011 files_free = EXPL_ALLOC_INC;
5012 }
5013 slash_adjust(p);
5014 if (dir)
5015 {
5016 /* For a directory we add a '/', unless it's already
5017 * there. */
5018 len = STRLEN(p);
5019 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5020 {
5021 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005022 if (!after_pathsep((*file)[*num_file],
5023 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005024 {
5025 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005026 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005027 }
5028 }
5029 }
5030 else
5031 {
5032 (*file)[*num_file] = vim_strsave(p);
5033 }
5034
5035 /*
5036 * Error message already given by either alloc or vim_strsave.
5037 * Should return FAIL, but returning OK works also.
5038 */
5039 if ((*file)[*num_file] == NULL)
5040 break;
5041 (*num_file)++;
5042 }
5043 _fnexplodefree((char **)expl_files);
5044 }
5045 }
5046 return OK;
5047
5048#else /* __EMX__ */
5049
5050 int j;
5051 char_u *tempname;
5052 char_u *command;
5053 FILE *fd;
5054 char_u *buffer;
5055#define STYLE_ECHO 0 /* use "echo" to expand */
5056#define STYLE_GLOB 1 /* use "glob" to expand, for csh */
5057#define STYLE_PRINT 2 /* use "print -N" to expand, for zsh */
5058#define STYLE_BT 3 /* `cmd` expansion, execute the pattern directly */
5059 int shell_style = STYLE_ECHO;
5060 int check_spaces;
5061 static int did_find_nul = FALSE;
5062 int ampersent = FALSE;
5063
5064 *num_file = 0; /* default: no files found */
5065 *file = NULL;
5066
5067 /*
5068 * If there are no wildcards, just copy the names to allocated memory.
5069 * Saves a lot of time, because we don't have to start a new shell.
5070 */
5071 if (!have_wildcard(num_pat, pat))
5072 return save_patterns(num_pat, pat, num_file, file);
5073
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005074# ifdef HAVE_SANDBOX
5075 /* Don't allow any shell command in the sandbox. */
5076 if (sandbox != 0 && check_secure())
5077 return FAIL;
5078# endif
5079
Bram Moolenaar071d4272004-06-13 20:20:40 +00005080 /*
5081 * Don't allow the use of backticks in secure and restricted mode.
5082 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005083 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005084 for (i = 0; i < num_pat; ++i)
5085 if (vim_strchr(pat[i], '`') != NULL
5086 && (check_restricted() || check_secure()))
5087 return FAIL;
5088
5089 /*
5090 * get a name for the temp file
5091 */
5092 if ((tempname = vim_tempname('o')) == NULL)
5093 {
5094 EMSG(_(e_notmp));
5095 return FAIL;
5096 }
5097
5098 /*
5099 * Let the shell expand the patterns and write the result into the temp
5100 * file. if expanding `cmd` execute it directly.
5101 * If we use csh, glob will work better than echo.
5102 * If we use zsh, print -N will work better than glob.
5103 */
5104 if (num_pat == 1 && *pat[0] == '`'
5105 && (len = STRLEN(pat[0])) > 2
5106 && *(pat[0] + len - 1) == '`')
5107 shell_style = STYLE_BT;
5108 else if ((len = STRLEN(p_sh)) >= 3)
5109 {
5110 if (STRCMP(p_sh + len - 3, "csh") == 0)
5111 shell_style = STYLE_GLOB;
5112 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5113 shell_style = STYLE_PRINT;
5114 }
5115
5116 /* "unset nonomatch; print -N >" plus two is 29 */
5117 len = STRLEN(tempname) + 29;
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005118 for (i = 0; i < num_pat; ++i)
5119 {
5120 /* Count the length of the patterns in the same way as they are put in
5121 * "command" below. */
5122#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005123 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005124#else
5125 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005126 for (j = 0; pat[i][j] != NUL; ++j)
5127 {
5128 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5129 ++len; /* may add a backslash */
5130 ++len;
5131 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005132#endif
5133 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005134 command = alloc(len);
5135 if (command == NULL)
5136 {
5137 /* out of memory */
5138 vim_free(tempname);
5139 return FAIL;
5140 }
5141
5142 /*
5143 * Build the shell command:
5144 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5145 * recognizes this).
5146 * - Add the shell command to print the expanded names.
5147 * - Add the temp file name.
5148 * - Add the file name patterns.
5149 */
5150 if (shell_style == STYLE_BT)
5151 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005152 /* change `command; command& ` to (command; command ) */
5153 STRCPY(command, "(");
5154 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005155 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005156 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005157 while (p > command && vim_iswhite(*p))
5158 --p;
5159 if (*p == '&') /* remove trailing '&' */
5160 {
5161 ampersent = TRUE;
5162 *p = ' ';
5163 }
5164 STRCAT(command, ">");
5165 }
5166 else
5167 {
5168 if (flags & EW_NOTFOUND)
5169 STRCPY(command, "set nonomatch; ");
5170 else
5171 STRCPY(command, "unset nonomatch; ");
5172 if (shell_style == STYLE_GLOB)
5173 STRCAT(command, "glob >");
5174 else if (shell_style == STYLE_PRINT)
5175 STRCAT(command, "print -N >");
5176 else
5177 STRCAT(command, "echo >");
5178 }
5179 STRCAT(command, tempname);
5180 if (shell_style != STYLE_BT)
5181 for (i = 0; i < num_pat; ++i)
5182 {
5183 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005184 * is started twice. Otherwise put a backslash before special
5185 * characters, except insice ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005186#ifdef USE_SYSTEM
5187 STRCAT(command, " \"");
5188 STRCAT(command, pat[i]);
5189 STRCAT(command, "\"");
5190#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005191 int intick = FALSE;
5192
Bram Moolenaar071d4272004-06-13 20:20:40 +00005193 p = command + STRLEN(command);
5194 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005195 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005196 {
5197 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005198 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005199 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5200 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005201 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005202 * backslash inside backticks, before a special character
5203 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005204 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005205 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5206 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005207 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005208 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005209 }
5210 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005211 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005212 /* Put a backslash before a special character, but not
5213 * when inside ``. */
5214 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005215
5216 /* Copy one character. */
5217 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005218 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005219 *p = NUL;
5220#endif
5221 }
5222 if (flags & EW_SILENT)
5223 show_shell_mess = FALSE;
5224 if (ampersent)
5225 STRCAT(command, "&"); /* put the '&' back after the
5226 redirection */
5227
5228 /*
5229 * Using zsh -G: If a pattern has no matches, it is just deleted from
5230 * the argument list, otherwise zsh gives an error message and doesn't
5231 * expand any other pattern.
5232 */
5233 if (shell_style == STYLE_PRINT)
5234 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5235
5236 /*
5237 * If we use -f then shell variables set in .cshrc won't get expanded.
5238 * vi can do it, so we will too, but it is only necessary if there is a "$"
5239 * in one of the patterns, otherwise we can still use the fast option.
5240 */
5241 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5242 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5243
5244 /*
5245 * execute the shell command
5246 */
5247 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5248
5249 /* When running in the background, give it some time to create the temp
5250 * file, but don't wait for it to finish. */
5251 if (ampersent)
5252 mch_delay(10L, TRUE);
5253
5254 extra_shell_arg = NULL; /* cleanup */
5255 show_shell_mess = TRUE;
5256 vim_free(command);
5257
5258 if (i) /* mch_call_shell() failed */
5259 {
5260 mch_remove(tempname);
5261 vim_free(tempname);
5262 /*
5263 * With interactive completion, the error message is not printed.
5264 * However with USE_SYSTEM, I don't know how to turn off error messages
5265 * from the shell, so screen may still get messed up -- webb.
5266 */
5267#ifndef USE_SYSTEM
5268 if (!(flags & EW_SILENT))
5269#endif
5270 {
5271 redraw_later_clear(); /* probably messed up screen */
5272 msg_putchar('\n'); /* clear bottom line quickly */
5273 cmdline_row = Rows - 1; /* continue on last line */
5274#ifdef USE_SYSTEM
5275 if (!(flags & EW_SILENT))
5276#endif
5277 {
5278 MSG(_(e_wildexpand));
5279 msg_start(); /* don't overwrite this message */
5280 }
5281 }
5282 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5283 * EW_NOTFOUND is given */
5284 if (shell_style == STYLE_BT)
5285 return FAIL;
5286 goto notfound;
5287 }
5288
5289 /*
5290 * read the names from the file into memory
5291 */
5292 fd = fopen((char *)tempname, READBIN);
5293 if (fd == NULL)
5294 {
5295 /* Something went wrong, perhaps a file name with a special char. */
5296 if (!(flags & EW_SILENT))
5297 {
5298 MSG(_(e_wildexpand));
5299 msg_start(); /* don't overwrite this message */
5300 }
5301 vim_free(tempname);
5302 goto notfound;
5303 }
5304 fseek(fd, 0L, SEEK_END);
5305 len = ftell(fd); /* get size of temp file */
5306 fseek(fd, 0L, SEEK_SET);
5307 buffer = alloc(len + 1);
5308 if (buffer == NULL)
5309 {
5310 /* out of memory */
5311 mch_remove(tempname);
5312 vim_free(tempname);
5313 fclose(fd);
5314 return FAIL;
5315 }
5316 i = fread((char *)buffer, 1, len, fd);
5317 fclose(fd);
5318 mch_remove(tempname);
5319 if (i != len)
5320 {
5321 /* unexpected read error */
5322 EMSG2(_(e_notread), tempname);
5323 vim_free(tempname);
5324 vim_free(buffer);
5325 return FAIL;
5326 }
5327 vim_free(tempname);
5328
5329#if defined(__CYGWIN__) || defined(__CYGWIN32__)
5330 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5331 p = buffer;
5332 for (i = 0; i < len; ++i)
5333 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5334 *p++ = buffer[i];
5335 len = p - buffer;
5336# endif
5337
5338
5339 /* file names are separated with Space */
5340 if (shell_style == STYLE_ECHO)
5341 {
5342 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5343 p = buffer;
5344 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5345 {
5346 while (*p != ' ' && *p != '\n')
5347 ++p;
5348 p = skipwhite(p); /* skip to next entry */
5349 }
5350 }
5351 /* file names are separated with NL */
5352 else if (shell_style == STYLE_BT)
5353 {
5354 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5355 p = buffer;
5356 for (i = 0; *p != NUL; ++i) /* count number of entries */
5357 {
5358 while (*p != '\n' && *p != NUL)
5359 ++p;
5360 if (*p != NUL)
5361 ++p;
5362 p = skipwhite(p); /* skip leading white space */
5363 }
5364 }
5365 /* file names are separated with NUL */
5366 else
5367 {
5368 /*
5369 * Some versions of zsh use spaces instead of NULs to separate
5370 * results. Only do this when there is no NUL before the end of the
5371 * buffer, otherwise we would never be able to use file names with
5372 * embedded spaces when zsh does use NULs.
5373 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5374 * don't check for spaces again.
5375 */
5376 check_spaces = FALSE;
5377 if (shell_style == STYLE_PRINT && !did_find_nul)
5378 {
5379 /* If there is a NUL, set did_find_nul, else set check_spaces */
5380 if (len && (int)STRLEN(buffer) < len - 1)
5381 did_find_nul = TRUE;
5382 else
5383 check_spaces = TRUE;
5384 }
5385
5386 /*
5387 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5388 * already is one, for STYLE_GLOB it needs to be added.
5389 */
5390 if (len && buffer[len - 1] == NUL)
5391 --len;
5392 else
5393 buffer[len] = NUL;
5394 i = 0;
5395 for (p = buffer; p < buffer + len; ++p)
5396 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5397 {
5398 ++i;
5399 *p = NUL;
5400 }
5401 if (len)
5402 ++i; /* count last entry */
5403 }
5404 if (i == 0)
5405 {
5406 /*
5407 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5408 * /bin/sh will happily expand it to nothing rather than returning an
5409 * error; and hey, it's good to check anyway -- webb.
5410 */
5411 vim_free(buffer);
5412 goto notfound;
5413 }
5414 *num_file = i;
5415 *file = (char_u **)alloc(sizeof(char_u *) * i);
5416 if (*file == NULL)
5417 {
5418 /* out of memory */
5419 vim_free(buffer);
5420 return FAIL;
5421 }
5422
5423 /*
5424 * Isolate the individual file names.
5425 */
5426 p = buffer;
5427 for (i = 0; i < *num_file; ++i)
5428 {
5429 (*file)[i] = p;
5430 /* Space or NL separates */
5431 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT)
5432 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00005433 while (!(shell_style == STYLE_ECHO && *p == ' ')
5434 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005435 ++p;
5436 if (p == buffer + len) /* last entry */
5437 *p = NUL;
5438 else
5439 {
5440 *p++ = NUL;
5441 p = skipwhite(p); /* skip to next entry */
5442 }
5443 }
5444 else /* NUL separates */
5445 {
5446 while (*p && p < buffer + len) /* skip entry */
5447 ++p;
5448 ++p; /* skip NUL */
5449 }
5450 }
5451
5452 /*
5453 * Move the file names to allocated memory.
5454 */
5455 for (j = 0, i = 0; i < *num_file; ++i)
5456 {
5457 /* Require the files to exist. Helps when using /bin/sh */
5458 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5459 continue;
5460
5461 /* check if this entry should be included */
5462 dir = (mch_isdir((*file)[i]));
5463 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5464 continue;
5465
Bram Moolenaara2031822006-03-07 22:29:51 +00005466 /* Skip files that are not executable if we check for that. */
5467 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
5468 continue;
5469
Bram Moolenaar071d4272004-06-13 20:20:40 +00005470 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5471 if (p)
5472 {
5473 STRCPY(p, (*file)[i]);
5474 if (dir)
5475 STRCAT(p, "/"); /* add '/' to a directory name */
5476 (*file)[j++] = p;
5477 }
5478 }
5479 vim_free(buffer);
5480 *num_file = j;
5481
5482 if (*num_file == 0) /* rejected all entries */
5483 {
5484 vim_free(*file);
5485 *file = NULL;
5486 goto notfound;
5487 }
5488
5489 return OK;
5490
5491notfound:
5492 if (flags & EW_NOTFOUND)
5493 return save_patterns(num_pat, pat, num_file, file);
5494 return FAIL;
5495
5496#endif /* __EMX__ */
5497}
5498
5499#endif /* VMS */
5500
5501#ifndef __EMX__
5502 static int
5503save_patterns(num_pat, pat, num_file, file)
5504 int num_pat;
5505 char_u **pat;
5506 int *num_file;
5507 char_u ***file;
5508{
5509 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005510 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005511
5512 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5513 if (*file == NULL)
5514 return FAIL;
5515 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005516 {
5517 s = vim_strsave(pat[i]);
5518 if (s != NULL)
5519 /* Be compatible with expand_filename(): halve the number of
5520 * backslashes. */
5521 backslash_halve(s);
5522 (*file)[i] = s;
5523 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005524 *num_file = num_pat;
5525 return OK;
5526}
5527#endif
5528
5529
5530/*
5531 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5532 * expand.
5533 */
5534 int
5535mch_has_exp_wildcard(p)
5536 char_u *p;
5537{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005538 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005539 {
5540#ifndef OS2
5541 if (*p == '\\' && p[1] != NUL)
5542 ++p;
5543 else
5544#endif
5545 if (vim_strchr((char_u *)
5546#ifdef VMS
5547 "*?%"
5548#else
5549# ifdef OS2
5550 "*?"
5551# else
5552 "*?[{'"
5553# endif
5554#endif
5555 , *p) != NULL)
5556 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005557 }
5558 return FALSE;
5559}
5560
5561/*
5562 * Return TRUE if the string "p" contains a wildcard.
5563 * Don't recognize '~' at the end as a wildcard.
5564 */
5565 int
5566mch_has_wildcard(p)
5567 char_u *p;
5568{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005569 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005570 {
5571#ifndef OS2
5572 if (*p == '\\' && p[1] != NUL)
5573 ++p;
5574 else
5575#endif
5576 if (vim_strchr((char_u *)
5577#ifdef VMS
5578 "*?%$"
5579#else
5580# ifdef OS2
5581# ifdef VIM_BACKTICK
5582 "*?$`"
5583# else
5584 "*?$"
5585# endif
5586# else
5587 "*?[{`'$"
5588# endif
5589#endif
5590 , *p) != NULL
5591 || (*p == '~' && p[1] != NUL))
5592 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005593 }
5594 return FALSE;
5595}
5596
5597#ifndef __EMX__
5598 static int
5599have_wildcard(num, file)
5600 int num;
5601 char_u **file;
5602{
5603 int i;
5604
5605 for (i = 0; i < num; i++)
5606 if (mch_has_wildcard(file[i]))
5607 return 1;
5608 return 0;
5609}
5610
5611 static int
5612have_dollars(num, file)
5613 int num;
5614 char_u **file;
5615{
5616 int i;
5617
5618 for (i = 0; i < num; i++)
5619 if (vim_strchr(file[i], '$') != NULL)
5620 return TRUE;
5621 return FALSE;
5622}
5623#endif /* ifndef __EMX__ */
5624
5625#ifndef HAVE_RENAME
5626/*
5627 * Scaled-down version of rename(), which is missing in Xenix.
5628 * This version can only move regular files and will fail if the
5629 * destination exists.
5630 */
5631 int
5632mch_rename(src, dest)
5633 const char *src, *dest;
5634{
5635 struct stat st;
5636
5637 if (stat(dest, &st) >= 0) /* fail if destination exists */
5638 return -1;
5639 if (link(src, dest) != 0) /* link file to new name */
5640 return -1;
5641 if (mch_remove(src) == 0) /* delete link to old name */
5642 return 0;
5643 return -1;
5644}
5645#endif /* !HAVE_RENAME */
5646
5647#ifdef FEAT_MOUSE_GPM
5648/*
5649 * Initializes connection with gpm (if it isn't already opened)
5650 * Return 1 if succeeded (or connection already opened), 0 if failed
5651 */
5652 static int
5653gpm_open()
5654{
5655 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5656
5657 if (!gpm_flag)
5658 {
5659 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5660 gpm_connect.defaultMask = ~GPM_HARD;
5661 /* Default handling for mouse move*/
5662 gpm_connect.minMod = 0; /* Handle any modifier keys */
5663 gpm_connect.maxMod = 0xffff;
5664 if (Gpm_Open(&gpm_connect, 0) > 0)
5665 {
5666 /* gpm library tries to handling TSTP causes
5667 * problems. Anyways, we close connection to Gpm whenever
5668 * we are going to suspend or starting an external process
5669 * so we should'nt have problem with this
5670 */
5671 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5672 return 1; /* succeed */
5673 }
5674 if (gpm_fd == -2)
5675 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5676 return 0;
5677 }
5678 return 1; /* already open */
5679}
5680
5681/*
5682 * Closes connection to gpm
5683 * returns non-zero if connection succesfully closed
5684 */
5685 static void
5686gpm_close()
5687{
5688 if (gpm_flag && gpm_fd >= 0) /* if Open */
5689 Gpm_Close();
5690}
5691
5692/* Reads gpm event and adds special keys to input buf. Returns length of
5693 * generated key sequence.
5694 * This function is made after gui_send_mouse_event
5695 */
5696 static int
5697mch_gpm_process()
5698{
5699 int button;
5700 static Gpm_Event gpm_event;
5701 char_u string[6];
5702 int_u vim_modifiers;
5703 int row,col;
5704 unsigned char buttons_mask;
5705 unsigned char gpm_modifiers;
5706 static unsigned char old_buttons = 0;
5707
5708 Gpm_GetEvent(&gpm_event);
5709
5710#ifdef FEAT_GUI
5711 /* Don't put events in the input queue now. */
5712 if (hold_gui_events)
5713 return 0;
5714#endif
5715
5716 row = gpm_event.y - 1;
5717 col = gpm_event.x - 1;
5718
5719 string[0] = ESC; /* Our termcode */
5720 string[1] = 'M';
5721 string[2] = 'G';
5722 switch (GPM_BARE_EVENTS(gpm_event.type))
5723 {
5724 case GPM_DRAG:
5725 string[3] = MOUSE_DRAG;
5726 break;
5727 case GPM_DOWN:
5728 buttons_mask = gpm_event.buttons & ~old_buttons;
5729 old_buttons = gpm_event.buttons;
5730 switch (buttons_mask)
5731 {
5732 case GPM_B_LEFT:
5733 button = MOUSE_LEFT;
5734 break;
5735 case GPM_B_MIDDLE:
5736 button = MOUSE_MIDDLE;
5737 break;
5738 case GPM_B_RIGHT:
5739 button = MOUSE_RIGHT;
5740 break;
5741 default:
5742 return 0;
5743 /*Don't know what to do. Can more than one button be
5744 * reported in one event? */
5745 }
5746 string[3] = (char_u)(button | 0x20);
5747 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5748 break;
5749 case GPM_UP:
5750 string[3] = MOUSE_RELEASE;
5751 old_buttons &= ~gpm_event.buttons;
5752 break;
5753 default:
5754 return 0;
5755 }
5756 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5757 gpm_modifiers = gpm_event.modifiers;
5758 vim_modifiers = 0x0;
5759 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5760 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5761 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5762 */
5763 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5764 vim_modifiers |= MOUSE_SHIFT;
5765
5766 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5767 vim_modifiers |= MOUSE_CTRL;
5768 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5769 vim_modifiers |= MOUSE_ALT;
5770 string[3] |= vim_modifiers;
5771 string[4] = (char_u)(col + ' ' + 1);
5772 string[5] = (char_u)(row + ' ' + 1);
5773 add_to_input_buf(string, 6);
5774 return 6;
5775}
5776#endif /* FEAT_MOUSE_GPM */
5777
5778#if defined(FEAT_LIBCALL) || defined(PROTO)
5779typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
5780typedef char_u * (*INTPROCSTR)__ARGS((int));
5781typedef int (*STRPROCINT)__ARGS((char_u *));
5782typedef int (*INTPROCINT)__ARGS((int));
5783
5784/*
5785 * Call a DLL routine which takes either a string or int param
5786 * and returns an allocated string.
5787 */
5788 int
5789mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
5790 char_u *libname;
5791 char_u *funcname;
5792 char_u *argstring; /* NULL when using a argint */
5793 int argint;
5794 char_u **string_result;/* NULL when using number_result */
5795 int *number_result;
5796{
5797# if defined(USE_DLOPEN)
5798 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005799 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005800# else
5801 shl_t hinstLib;
5802# endif
5803 STRPROCSTR ProcAdd;
5804 INTPROCSTR ProcAddI;
5805 char_u *retval_str = NULL;
5806 int retval_int = 0;
5807 int success = FALSE;
5808
Bram Moolenaarb39ef122006-06-22 16:19:31 +00005809 /*
5810 * Get a handle to the DLL module.
5811 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005812# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00005813 /* First clear any error, it's not cleared by the dlopen() call. */
5814 (void)dlerror();
5815
Bram Moolenaar071d4272004-06-13 20:20:40 +00005816 hinstLib = dlopen((char *)libname, RTLD_LAZY
5817# ifdef RTLD_LOCAL
5818 | RTLD_LOCAL
5819# endif
5820 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005821 if (hinstLib == NULL)
5822 {
5823 /* "dlerr" must be used before dlclose() */
5824 dlerr = (char *)dlerror();
5825 if (dlerr != NULL)
5826 EMSG2(_("dlerror = \"%s\""), dlerr);
5827 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005828# else
5829 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
5830# endif
5831
5832 /* If the handle is valid, try to get the function address. */
5833 if (hinstLib != NULL)
5834 {
5835# ifdef HAVE_SETJMP_H
5836 /*
5837 * Catch a crash when calling the library function. For example when
5838 * using a number where a string pointer is expected.
5839 */
5840 mch_startjmp();
5841 if (SETJMP(lc_jump_env) != 0)
5842 {
5843 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00005844# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005845 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00005846# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005847 mch_didjmp();
5848 }
5849 else
5850# endif
5851 {
5852 retval_str = NULL;
5853 retval_int = 0;
5854
5855 if (argstring != NULL)
5856 {
5857# if defined(USE_DLOPEN)
5858 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005859 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005860# else
5861 if (shl_findsym(&hinstLib, (const char *)funcname,
5862 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
5863 ProcAdd = NULL;
5864# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005865 if ((success = (ProcAdd != NULL
5866# if defined(USE_DLOPEN)
5867 && dlerr == NULL
5868# endif
5869 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005870 {
5871 if (string_result == NULL)
5872 retval_int = ((STRPROCINT)ProcAdd)(argstring);
5873 else
5874 retval_str = (ProcAdd)(argstring);
5875 }
5876 }
5877 else
5878 {
5879# if defined(USE_DLOPEN)
5880 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005881 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005882# else
5883 if (shl_findsym(&hinstLib, (const char *)funcname,
5884 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
5885 ProcAddI = NULL;
5886# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005887 if ((success = (ProcAddI != NULL
5888# if defined(USE_DLOPEN)
5889 && dlerr == NULL
5890# endif
5891 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005892 {
5893 if (string_result == NULL)
5894 retval_int = ((INTPROCINT)ProcAddI)(argint);
5895 else
5896 retval_str = (ProcAddI)(argint);
5897 }
5898 }
5899
5900 /* Save the string before we free the library. */
5901 /* Assume that a "1" or "-1" result is an illegal pointer. */
5902 if (string_result == NULL)
5903 *number_result = retval_int;
5904 else if (retval_str != NULL
5905 && retval_str != (char_u *)1
5906 && retval_str != (char_u *)-1)
5907 *string_result = vim_strsave(retval_str);
5908 }
5909
5910# ifdef HAVE_SETJMP_H
5911 mch_endjmp();
5912# ifdef SIGHASARG
5913 if (lc_signal != 0)
5914 {
5915 int i;
5916
5917 /* try to find the name of this signal */
5918 for (i = 0; signal_info[i].sig != -1; i++)
5919 if (lc_signal == signal_info[i].sig)
5920 break;
5921 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
5922 }
5923# endif
5924# endif
5925
Bram Moolenaar071d4272004-06-13 20:20:40 +00005926# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005927 /* "dlerr" must be used before dlclose() */
5928 if (dlerr != NULL)
5929 EMSG2(_("dlerror = \"%s\""), dlerr);
5930
5931 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005932 (void)dlclose(hinstLib);
5933# else
5934 (void)shl_unload(hinstLib);
5935# endif
5936 }
5937
5938 if (!success)
5939 {
5940 EMSG2(_(e_libcall), funcname);
5941 return FAIL;
5942 }
5943
5944 return OK;
5945}
5946#endif
5947
5948#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
5949static int xterm_trace = -1; /* default: disabled */
5950static int xterm_button;
5951
5952/*
5953 * Setup a dummy window for X selections in a terminal.
5954 */
5955 void
5956setup_term_clip()
5957{
5958 int z = 0;
5959 char *strp = "";
5960 Widget AppShell;
5961
5962 if (!x_connect_to_server())
5963 return;
5964
5965 open_app_context();
5966 if (app_context != NULL && xterm_Shell == (Widget)0)
5967 {
5968 int (*oldhandler)();
5969#if defined(HAVE_SETJMP_H)
5970 int (*oldIOhandler)();
5971#endif
5972# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5973 struct timeval start_tv;
5974
5975 if (p_verbose > 0)
5976 gettimeofday(&start_tv, NULL);
5977# endif
5978
5979 /* Ignore X errors while opening the display */
5980 oldhandler = XSetErrorHandler(x_error_check);
5981
5982#if defined(HAVE_SETJMP_H)
5983 /* Ignore X IO errors while opening the display */
5984 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
5985 mch_startjmp();
5986 if (SETJMP(lc_jump_env) != 0)
5987 {
5988 mch_didjmp();
5989 xterm_dpy = NULL;
5990 }
5991 else
5992#endif
5993 {
5994 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
5995 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
5996#if defined(HAVE_SETJMP_H)
5997 mch_endjmp();
5998#endif
5999 }
6000
6001#if defined(HAVE_SETJMP_H)
6002 /* Now handle X IO errors normally. */
6003 (void)XSetIOErrorHandler(oldIOhandler);
6004#endif
6005 /* Now handle X errors normally. */
6006 (void)XSetErrorHandler(oldhandler);
6007
6008 if (xterm_dpy == NULL)
6009 {
6010 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006011 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006012 return;
6013 }
6014
6015 /* Catch terminating error of the X server connection. */
6016 (void)XSetIOErrorHandler(x_IOerror_handler);
6017
6018# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6019 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006020 {
6021 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006022 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006023 verbose_leave();
6024 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006025# endif
6026
6027 /* Create a Shell to make converters work. */
6028 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6029 applicationShellWidgetClass, xterm_dpy,
6030 NULL);
6031 if (AppShell == (Widget)0)
6032 return;
6033 xterm_Shell = XtVaCreatePopupShell("VIM",
6034 topLevelShellWidgetClass, AppShell,
6035 XtNmappedWhenManaged, 0,
6036 XtNwidth, 1,
6037 XtNheight, 1,
6038 NULL);
6039 if (xterm_Shell == (Widget)0)
6040 return;
6041
6042 x11_setup_atoms(xterm_dpy);
6043 if (x11_display == NULL)
6044 x11_display = xterm_dpy;
6045
6046 XtRealizeWidget(xterm_Shell);
6047 XSync(xterm_dpy, False);
6048 xterm_update();
6049 }
6050 if (xterm_Shell != (Widget)0)
6051 {
6052 clip_init(TRUE);
6053 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6054 x11_window = (Window)atol(strp);
6055 /* Check if $WINDOWID is valid. */
6056 if (test_x11_window(xterm_dpy) == FAIL)
6057 x11_window = 0;
6058 if (x11_window != 0)
6059 xterm_trace = 0;
6060 }
6061}
6062
6063 void
6064start_xterm_trace(button)
6065 int button;
6066{
6067 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6068 return;
6069 xterm_trace = 1;
6070 xterm_button = button;
6071 do_xterm_trace();
6072}
6073
6074
6075 void
6076stop_xterm_trace()
6077{
6078 if (xterm_trace < 0)
6079 return;
6080 xterm_trace = 0;
6081}
6082
6083/*
6084 * Query the xterm pointer and generate mouse termcodes if necessary
6085 * return TRUE if dragging is active, else FALSE
6086 */
6087 static int
6088do_xterm_trace()
6089{
6090 Window root, child;
6091 int root_x, root_y;
6092 int win_x, win_y;
6093 int row, col;
6094 int_u mask_return;
6095 char_u buf[50];
6096 char_u *strp;
6097 long got_hints;
6098 static char_u *mouse_code;
6099 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6100 static int prev_row = 0, prev_col = 0;
6101 static XSizeHints xterm_hints;
6102
6103 if (xterm_trace <= 0)
6104 return FALSE;
6105
6106 if (xterm_trace == 1)
6107 {
6108 /* Get the hints just before tracking starts. The font size might
6109 * have changed recently */
6110 XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints);
6111 if (!(got_hints & PResizeInc)
6112 || xterm_hints.width_inc <= 1
6113 || xterm_hints.height_inc <= 1)
6114 {
6115 xterm_trace = -1; /* Not enough data -- disable tracing */
6116 return FALSE;
6117 }
6118
6119 /* Rely on the same mouse code for the duration of this */
6120 mouse_code = find_termcode(mouse_name);
6121 prev_row = mouse_row;
6122 prev_row = mouse_col;
6123 xterm_trace = 2;
6124
6125 /* Find the offset of the chars, there might be a scrollbar on the
6126 * left of the window and/or a menu on the top (eterm etc.) */
6127 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6128 &win_x, &win_y, &mask_return);
6129 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6130 - (xterm_hints.height_inc / 2);
6131 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6132 xterm_hints.y = 2;
6133 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6134 - (xterm_hints.width_inc / 2);
6135 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6136 xterm_hints.x = 2;
6137 return TRUE;
6138 }
6139 if (mouse_code == NULL)
6140 {
6141 xterm_trace = 0;
6142 return FALSE;
6143 }
6144
6145 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6146 &win_x, &win_y, &mask_return);
6147
6148 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6149 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6150 if (row == prev_row && col == prev_col)
6151 return TRUE;
6152
6153 STRCPY(buf, mouse_code);
6154 strp = buf + STRLEN(buf);
6155 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6156 *strp++ = (char_u)(col + ' ' + 1);
6157 *strp++ = (char_u)(row + ' ' + 1);
6158 *strp = 0;
6159 add_to_input_buf(buf, STRLEN(buf));
6160
6161 prev_row = row;
6162 prev_col = col;
6163 return TRUE;
6164}
6165
6166# if defined(FEAT_GUI) || defined(PROTO)
6167/*
6168 * Destroy the display, window and app_context. Required for GTK.
6169 */
6170 void
6171clear_xterm_clip()
6172{
6173 if (xterm_Shell != (Widget)0)
6174 {
6175 XtDestroyWidget(xterm_Shell);
6176 xterm_Shell = (Widget)0;
6177 }
6178 if (xterm_dpy != NULL)
6179 {
6180#if 0
6181 /* Lesstif and Solaris crash here, lose some memory */
6182 XtCloseDisplay(xterm_dpy);
6183#endif
6184 if (x11_display == xterm_dpy)
6185 x11_display = NULL;
6186 xterm_dpy = NULL;
6187 }
6188#if 0
6189 if (app_context != (XtAppContext)NULL)
6190 {
6191 /* Lesstif and Solaris crash here, lose some memory */
6192 XtDestroyApplicationContext(app_context);
6193 app_context = (XtAppContext)NULL;
6194 }
6195#endif
6196}
6197# endif
6198
6199/*
6200 * Catch up with any queued X events. This may put keyboard input into the
6201 * input buffer, call resize call-backs, trigger timers etc. If there is
6202 * nothing in the X event queue (& no timers pending), then we return
6203 * immediately.
6204 */
6205 static void
6206xterm_update()
6207{
6208 XEvent event;
6209
6210 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6211 {
6212 XtAppNextEvent(app_context, &event);
6213#ifdef FEAT_CLIENTSERVER
6214 {
6215 XPropertyEvent *e = (XPropertyEvent *)&event;
6216
6217 if (e->type == PropertyNotify && e->window == commWindow
6218 && e->atom == commProperty && e->state == PropertyNewValue)
6219 serverEventProc(xterm_dpy, &event);
6220 }
6221#endif
6222 XtDispatchEvent(&event);
6223 }
6224}
6225
6226 int
6227clip_xterm_own_selection(cbd)
6228 VimClipboard *cbd;
6229{
6230 if (xterm_Shell != (Widget)0)
6231 return clip_x11_own_selection(xterm_Shell, cbd);
6232 return FAIL;
6233}
6234
6235 void
6236clip_xterm_lose_selection(cbd)
6237 VimClipboard *cbd;
6238{
6239 if (xterm_Shell != (Widget)0)
6240 clip_x11_lose_selection(xterm_Shell, cbd);
6241}
6242
6243 void
6244clip_xterm_request_selection(cbd)
6245 VimClipboard *cbd;
6246{
6247 if (xterm_Shell != (Widget)0)
6248 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6249}
6250
6251 void
6252clip_xterm_set_selection(cbd)
6253 VimClipboard *cbd;
6254{
6255 clip_x11_set_selection(cbd);
6256}
6257#endif
6258
6259
6260#if defined(USE_XSMP) || defined(PROTO)
6261/*
6262 * Code for X Session Management Protocol.
6263 */
6264static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6265static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6266static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6267static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6268static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6269
6270
6271# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6272static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6273
6274/*
6275 * This is our chance to ask the user if they want to save,
6276 * or abort the logout
6277 */
6278/*ARGSUSED*/
6279 static void
6280xsmp_handle_interaction(smc_conn, client_data)
6281 SmcConn smc_conn;
6282 SmPointer client_data;
6283{
6284 cmdmod_T save_cmdmod;
6285 int cancel_shutdown = False;
6286
6287 save_cmdmod = cmdmod;
6288 cmdmod.confirm = TRUE;
6289 if (check_changed_any(FALSE))
6290 /* Mustn't logout */
6291 cancel_shutdown = True;
6292 cmdmod = save_cmdmod;
6293 setcursor(); /* position cursor */
6294 out_flush();
6295
6296 /* Done interaction */
6297 SmcInteractDone(smc_conn, cancel_shutdown);
6298
6299 /* Finish off
6300 * Only end save-yourself here if we're not cancelling shutdown;
6301 * we'll get a cancelled callback later in which we'll end it.
6302 * Hopefully get around glitchy SMs (like GNOME-1)
6303 */
6304 if (!cancel_shutdown)
6305 {
6306 xsmp.save_yourself = False;
6307 SmcSaveYourselfDone(smc_conn, True);
6308 }
6309}
6310# endif
6311
6312/*
6313 * Callback that starts save-yourself.
6314 */
6315/*ARGSUSED*/
6316 static void
6317xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6318 shutdown, interact_style, fast)
6319 SmcConn smc_conn;
6320 SmPointer client_data;
6321 int save_type;
6322 Bool shutdown;
6323 int interact_style;
6324 Bool fast;
6325{
6326 /* Handle already being in saveyourself */
6327 if (xsmp.save_yourself)
6328 SmcSaveYourselfDone(smc_conn, True);
6329 xsmp.save_yourself = True;
6330 xsmp.shutdown = shutdown;
6331
6332 /* First up, preserve all files */
6333 out_flush();
6334 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6335
6336 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006337 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006338
6339# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6340 /* Now see if we can ask about unsaved files */
6341 if (shutdown && !fast && gui.in_use)
6342 /* Need to interact with user, but need SM's permission */
6343 SmcInteractRequest(smc_conn, SmDialogError,
6344 xsmp_handle_interaction, client_data);
6345 else
6346# endif
6347 {
6348 /* Can stop the cycle here */
6349 SmcSaveYourselfDone(smc_conn, True);
6350 xsmp.save_yourself = False;
6351 }
6352}
6353
6354
6355/*
6356 * Callback to warn us of imminent death.
6357 */
6358/*ARGSUSED*/
6359 static void
6360xsmp_die(smc_conn, client_data)
6361 SmcConn smc_conn;
6362 SmPointer client_data;
6363{
6364 xsmp_close();
6365
6366 /* quit quickly leaving swapfiles for modified buffers behind */
6367 getout_preserve_modified(0);
6368}
6369
6370
6371/*
6372 * Callback to tell us that save-yourself has completed.
6373 */
6374/*ARGSUSED*/
6375 static void
6376xsmp_save_complete(smc_conn, client_data)
6377 SmcConn smc_conn;
6378 SmPointer client_data;
6379{
6380 xsmp.save_yourself = False;
6381}
6382
6383
6384/*
6385 * Callback to tell us that an instigated shutdown was cancelled
6386 * (maybe even by us)
6387 */
6388/*ARGSUSED*/
6389 static void
6390xsmp_shutdown_cancelled(smc_conn, client_data)
6391 SmcConn smc_conn;
6392 SmPointer client_data;
6393{
6394 if (xsmp.save_yourself)
6395 SmcSaveYourselfDone(smc_conn, True);
6396 xsmp.save_yourself = False;
6397 xsmp.shutdown = False;
6398}
6399
6400
6401/*
6402 * Callback to tell us that a new ICE connection has been established.
6403 */
6404/*ARGSUSED*/
6405 static void
6406xsmp_ice_connection(iceConn, clientData, opening, watchData)
6407 IceConn iceConn;
6408 IcePointer clientData;
6409 Bool opening;
6410 IcePointer *watchData;
6411{
6412 /* Intercept creation of ICE connection fd */
6413 if (opening)
6414 {
6415 xsmp_icefd = IceConnectionNumber(iceConn);
6416 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6417 }
6418}
6419
6420
6421/* Handle any ICE processing that's required; return FAIL if SM lost */
6422 int
6423xsmp_handle_requests()
6424{
6425 Bool rep;
6426
6427 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6428 == IceProcessMessagesIOError)
6429 {
6430 /* Lost ICE */
6431 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006432 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006433 xsmp_close();
6434 return FAIL;
6435 }
6436 else
6437 return OK;
6438}
6439
6440static int dummy;
6441
6442/* Set up X Session Management Protocol */
6443 void
6444xsmp_init(void)
6445{
6446 char errorstring[80];
6447 char *clientid;
6448 SmcCallbacks smcallbacks;
6449#if 0
6450 SmPropValue smname;
6451 SmProp smnameprop;
6452 SmProp *smprops[1];
6453#endif
6454
6455 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006456 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006457
6458 xsmp.save_yourself = xsmp.shutdown = False;
6459
6460 /* Set up SM callbacks - must have all, even if they're not used */
6461 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6462 smcallbacks.save_yourself.client_data = NULL;
6463 smcallbacks.die.callback = xsmp_die;
6464 smcallbacks.die.client_data = NULL;
6465 smcallbacks.save_complete.callback = xsmp_save_complete;
6466 smcallbacks.save_complete.client_data = NULL;
6467 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6468 smcallbacks.shutdown_cancelled.client_data = NULL;
6469
6470 /* Set up a watch on ICE connection creations. The "dummy" argument is
6471 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6472 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6473 {
6474 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006475 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006476 return;
6477 }
6478
6479 /* Create an SM connection */
6480 xsmp.smcconn = SmcOpenConnection(
6481 NULL,
6482 NULL,
6483 SmProtoMajor,
6484 SmProtoMinor,
6485 SmcSaveYourselfProcMask | SmcDieProcMask
6486 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6487 &smcallbacks,
6488 NULL,
6489 &clientid,
6490 sizeof(errorstring),
6491 errorstring);
6492 if (xsmp.smcconn == NULL)
6493 {
6494 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00006495
Bram Moolenaar071d4272004-06-13 20:20:40 +00006496 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006497 {
6498 vim_snprintf(errorreport, sizeof(errorreport),
6499 _("XSMP SmcOpenConnection failed: %s"), errorstring);
6500 verb_msg((char_u *)errorreport);
6501 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006502 return;
6503 }
6504 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6505
6506#if 0
6507 /* ID ourselves */
6508 smname.value = "vim";
6509 smname.length = 3;
6510 smnameprop.name = "SmProgram";
6511 smnameprop.type = "SmARRAY8";
6512 smnameprop.num_vals = 1;
6513 smnameprop.vals = &smname;
6514
6515 smprops[0] = &smnameprop;
6516 SmcSetProperties(xsmp.smcconn, 1, smprops);
6517#endif
6518}
6519
6520
6521/* Shut down XSMP comms. */
6522 void
6523xsmp_close()
6524{
6525 if (xsmp_icefd != -1)
6526 {
6527 SmcCloseConnection(xsmp.smcconn, 0, NULL);
6528 xsmp_icefd = -1;
6529 }
6530}
6531#endif /* USE_XSMP */
6532
6533
6534#ifdef EBCDIC
6535/* Translate character to its CTRL- value */
6536char CtrlTable[] =
6537{
6538/* 00 - 5E */
6539 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6540 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6541 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6542 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6543 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6544 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6545/* ^ */ 0x1E,
6546/* - */ 0x1F,
6547/* 61 - 6C */
6548 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6549/* _ */ 0x1F,
6550/* 6E - 80 */
6551 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6552/* a */ 0x01,
6553/* b */ 0x02,
6554/* c */ 0x03,
6555/* d */ 0x37,
6556/* e */ 0x2D,
6557/* f */ 0x2E,
6558/* g */ 0x2F,
6559/* h */ 0x16,
6560/* i */ 0x05,
6561/* 8A - 90 */
6562 0, 0, 0, 0, 0, 0, 0,
6563/* j */ 0x15,
6564/* k */ 0x0B,
6565/* l */ 0x0C,
6566/* m */ 0x0D,
6567/* n */ 0x0E,
6568/* o */ 0x0F,
6569/* p */ 0x10,
6570/* q */ 0x11,
6571/* r */ 0x12,
6572/* 9A - A1 */
6573 0, 0, 0, 0, 0, 0, 0, 0,
6574/* s */ 0x13,
6575/* t */ 0x3C,
6576/* u */ 0x3D,
6577/* v */ 0x32,
6578/* w */ 0x26,
6579/* x */ 0x18,
6580/* y */ 0x19,
6581/* z */ 0x3F,
6582/* AA - AC */
6583 0, 0, 0,
6584/* [ */ 0x27,
6585/* AE - BC */
6586 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6587/* ] */ 0x1D,
6588/* BE - C0 */ 0, 0, 0,
6589/* A */ 0x01,
6590/* B */ 0x02,
6591/* C */ 0x03,
6592/* D */ 0x37,
6593/* E */ 0x2D,
6594/* F */ 0x2E,
6595/* G */ 0x2F,
6596/* H */ 0x16,
6597/* I */ 0x05,
6598/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6599/* J */ 0x15,
6600/* K */ 0x0B,
6601/* L */ 0x0C,
6602/* M */ 0x0D,
6603/* N */ 0x0E,
6604/* O */ 0x0F,
6605/* P */ 0x10,
6606/* Q */ 0x11,
6607/* R */ 0x12,
6608/* DA - DF */ 0, 0, 0, 0, 0, 0,
6609/* \ */ 0x1C,
6610/* E1 */ 0,
6611/* S */ 0x13,
6612/* T */ 0x3C,
6613/* U */ 0x3D,
6614/* V */ 0x32,
6615/* W */ 0x26,
6616/* X */ 0x18,
6617/* Y */ 0x19,
6618/* Z */ 0x3F,
6619/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6620 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6621};
6622
6623char MetaCharTable[]=
6624{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6625 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6626 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6627 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6628 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6629};
6630
6631
6632/* TODO: Use characters NOT numbers!!! */
6633char CtrlCharTable[]=
6634{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6635 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6636 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6637 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6638 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6639};
6640
6641
6642#endif