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