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