blob: a80bd21807fcd6580edbc899e41fe08b15e0a840 [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
Bram Moolenaar071d4272004-06-13 20:20:40 +00002613static int executable_file __ARGS((char_u *name));
2614
2615/*
2616 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2617 */
2618 static int
2619executable_file(name)
2620 char_u *name;
2621{
2622 struct stat st;
2623
2624 if (stat((char *)name, &st))
2625 return 0;
2626 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2627}
2628
2629/*
2630 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2631 * Return -1 if unknown.
2632 */
2633 int
2634mch_can_exe(name)
2635 char_u *name;
2636{
2637 char_u *buf;
2638 char_u *p, *e;
2639 int retval;
2640
2641 /* If it's an absolute or relative path don't need to use $PATH. */
2642 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2643 || (name[1] == '.' && name[2] == '/'))))
2644 return executable_file(name);
2645
2646 p = (char_u *)getenv("PATH");
2647 if (p == NULL || *p == NUL)
2648 return -1;
2649 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2650 if (buf == NULL)
2651 return -1;
2652
2653 /*
2654 * Walk through all entries in $PATH to check if "name" exists there and
2655 * is an executable file.
2656 */
2657 for (;;)
2658 {
2659 e = (char_u *)strchr((char *)p, ':');
2660 if (e == NULL)
2661 e = p + STRLEN(p);
2662 if (e - p <= 1) /* empty entry means current dir */
2663 STRCPY(buf, "./");
2664 else
2665 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002666 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002667 add_pathsep(buf);
2668 }
2669 STRCAT(buf, name);
2670 retval = executable_file(buf);
2671 if (retval == 1)
2672 break;
2673
2674 if (*e != ':')
2675 break;
2676 p = e + 1;
2677 }
2678
2679 vim_free(buf);
2680 return retval;
2681}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682
2683/*
2684 * Check what "name" is:
2685 * NODE_NORMAL: file or directory (or doesn't exist)
2686 * NODE_WRITABLE: writable device, socket, fifo, etc.
2687 * NODE_OTHER: non-writable things
2688 */
2689 int
2690mch_nodetype(name)
2691 char_u *name;
2692{
2693 struct stat st;
2694
2695 if (stat((char *)name, &st))
2696 return NODE_NORMAL;
2697 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2698 return NODE_NORMAL;
2699#ifndef OS2
2700 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2701 return NODE_OTHER;
2702#endif
2703 /* Everything else is writable? */
2704 return NODE_WRITABLE;
2705}
2706
2707 void
2708mch_early_init()
2709{
2710#ifdef HAVE_CHECK_STACK_GROWTH
2711 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002712
Bram Moolenaar071d4272004-06-13 20:20:40 +00002713 check_stack_growth((char *)&i);
2714
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002715# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002716 get_stack_limit();
2717# endif
2718
2719#endif
2720
2721 /*
2722 * Setup an alternative stack for signals. Helps to catch signals when
2723 * running out of stack space.
2724 * Use of sigaltstack() is preferred, it's more portable.
2725 * Ignore any errors.
2726 */
2727#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2728 signal_stack = malloc(SIGSTKSZ);
2729 init_signal_stack();
2730#endif
2731}
2732
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002733#if defined(EXITFREE) || defined(PROTO)
2734 void
2735mch_free_mem()
2736{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002737# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2738 if (clip_star.owned)
2739 clip_lose_selection(&clip_star);
2740 if (clip_plus.owned)
2741 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002742# endif
2743# if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
2744 if (xterm_Shell != (Widget)0)
2745 XtDestroyWidget(xterm_Shell);
2746 if (xterm_dpy != NULL)
2747 XtCloseDisplay(xterm_dpy);
2748 if (app_context != (XtAppContext)NULL)
2749 XtDestroyApplicationContext(app_context);
2750# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002751# ifdef FEAT_X11
2752 if (x11_display != NULL && x11_display != xterm_dpy)
2753 XCloseDisplay(x11_display);
2754# endif
2755# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2756 vim_free(signal_stack);
2757 signal_stack = NULL;
2758# endif
2759# ifdef FEAT_TITLE
2760 vim_free(oldtitle);
2761 vim_free(oldicon);
2762# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002763}
2764#endif
2765
Bram Moolenaar071d4272004-06-13 20:20:40 +00002766static void exit_scroll __ARGS((void));
2767
2768/*
2769 * Output a newline when exiting.
2770 * Make sure the newline goes to the same stream as the text.
2771 */
2772 static void
2773exit_scroll()
2774{
Bram Moolenaardf177f62005-02-22 08:39:57 +00002775 if (silent_mode)
2776 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002777 if (newline_on_exit || msg_didout)
2778 {
2779 if (msg_use_printf())
2780 {
2781 if (info_message)
2782 mch_msg("\n");
2783 else
2784 mch_errmsg("\r\n");
2785 }
2786 else
2787 out_char('\n');
2788 }
2789 else
2790 {
2791 restore_cterm_colors(); /* get original colors back */
2792 msg_clr_eos_force(); /* clear the rest of the display */
2793 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
2794 }
2795}
2796
2797 void
2798mch_exit(r)
2799 int r;
2800{
2801 exiting = TRUE;
2802
2803#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
2804 x11_export_final_selection();
2805#endif
2806
2807#ifdef FEAT_GUI
2808 if (!gui.in_use)
2809#endif
2810 {
2811 settmode(TMODE_COOK);
2812#ifdef FEAT_TITLE
2813 mch_restore_title(3); /* restore xterm title and icon name */
2814#endif
2815 /*
2816 * When t_ti is not empty but it doesn't cause swapping terminal
2817 * pages, need to output a newline when msg_didout is set. But when
2818 * t_ti does swap pages it should not go to the shell page. Do this
2819 * before stoptermcap().
2820 */
2821 if (swapping_screen() && !newline_on_exit)
2822 exit_scroll();
2823
2824 /* Stop termcap: May need to check for T_CRV response, which
2825 * requires RAW mode. */
2826 stoptermcap();
2827
2828 /*
2829 * A newline is only required after a message in the alternate screen.
2830 * This is set to TRUE by wait_return().
2831 */
2832 if (!swapping_screen() || newline_on_exit)
2833 exit_scroll();
2834
2835 /* Cursor may have been switched off without calling starttermcap()
2836 * when doing "vim -u vimrc" and vimrc contains ":q". */
2837 if (full_screen)
2838 cursor_on();
2839 }
2840 out_flush();
2841 ml_close_all(TRUE); /* remove all memfiles */
2842 may_core_dump();
2843#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002844 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002845 gui_exit(r);
2846#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00002847
2848#if defined(MACOS_X) && defined(FEAT_MBYTE)
2849 mac_conv_cleanup();
2850#endif
2851
Bram Moolenaar071d4272004-06-13 20:20:40 +00002852#ifdef __QNX__
2853 /* A core dump won't be created if the signal handler
2854 * doesn't return, so we can't call exit() */
2855 if (deadly_signal != 0)
2856 return;
2857#endif
2858
Bram Moolenaar009b2592004-10-24 19:18:58 +00002859#ifdef FEAT_NETBEANS_INTG
2860 if (usingNetbeans)
2861 netbeans_send_disconnect();
2862#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002863
2864#ifdef EXITFREE
2865 free_all_mem();
2866#endif
2867
Bram Moolenaar071d4272004-06-13 20:20:40 +00002868 exit(r);
2869}
2870
2871 static void
2872may_core_dump()
2873{
2874 if (deadly_signal != 0)
2875 {
2876 signal(deadly_signal, SIG_DFL);
2877 kill(getpid(), deadly_signal); /* Die using the signal we caught */
2878 }
2879}
2880
2881#ifndef VMS
2882
2883 void
2884mch_settmode(tmode)
2885 int tmode;
2886{
2887 static int first = TRUE;
2888
2889 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2890#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2891 /*
2892 * for "new" tty systems
2893 */
2894# ifdef HAVE_TERMIOS_H
2895 static struct termios told;
2896 struct termios tnew;
2897# else
2898 static struct termio told;
2899 struct termio tnew;
2900# endif
2901
2902 if (first)
2903 {
2904 first = FALSE;
2905# if defined(HAVE_TERMIOS_H)
2906 tcgetattr(read_cmd_fd, &told);
2907# else
2908 ioctl(read_cmd_fd, TCGETA, &told);
2909# endif
2910 }
2911
2912 tnew = told;
2913 if (tmode == TMODE_RAW)
2914 {
2915 /*
2916 * ~ICRNL enables typing ^V^M
2917 */
2918 tnew.c_iflag &= ~ICRNL;
2919 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
2920# if defined(IEXTEN) && !defined(__MINT__)
2921 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
2922 /* but it breaks function keys on MINT */
2923# endif
2924 );
2925# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
2926 tnew.c_oflag &= ~ONLCR;
2927# endif
2928 tnew.c_cc[VMIN] = 1; /* return after 1 char */
2929 tnew.c_cc[VTIME] = 0; /* don't wait */
2930 }
2931 else if (tmode == TMODE_SLEEP)
2932 tnew.c_lflag &= ~(ECHO);
2933
2934# if defined(HAVE_TERMIOS_H)
2935 {
2936 int n = 10;
2937
2938 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
2939 * few times. */
2940 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
2941 && errno == EINTR && n > 0)
2942 --n;
2943 }
2944# else
2945 ioctl(read_cmd_fd, TCSETA, &tnew);
2946# endif
2947
2948#else
2949
2950 /*
2951 * for "old" tty systems
2952 */
2953# ifndef TIOCSETN
2954# define TIOCSETN TIOCSETP /* for hpux 9.0 */
2955# endif
2956 static struct sgttyb ttybold;
2957 struct sgttyb ttybnew;
2958
2959 if (first)
2960 {
2961 first = FALSE;
2962 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
2963 }
2964
2965 ttybnew = ttybold;
2966 if (tmode == TMODE_RAW)
2967 {
2968 ttybnew.sg_flags &= ~(CRMOD | ECHO);
2969 ttybnew.sg_flags |= RAW;
2970 }
2971 else if (tmode == TMODE_SLEEP)
2972 ttybnew.sg_flags &= ~(ECHO);
2973 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
2974#endif
2975 curr_tmode = tmode;
2976}
2977
2978/*
2979 * Try to get the code for "t_kb" from the stty setting
2980 *
2981 * Even if termcap claims a backspace key, the user's setting *should*
2982 * prevail. stty knows more about reality than termcap does, and if
2983 * somebody's usual erase key is DEL (which, for most BSD users, it will
2984 * be), they're going to get really annoyed if their erase key starts
2985 * doing forward deletes for no reason. (Eric Fischer)
2986 */
2987 void
2988get_stty()
2989{
2990 char_u buf[2];
2991 char_u *p;
2992
2993 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2994#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2995 /* for "new" tty systems */
2996# ifdef HAVE_TERMIOS_H
2997 struct termios keys;
2998# else
2999 struct termio keys;
3000# endif
3001
3002# if defined(HAVE_TERMIOS_H)
3003 if (tcgetattr(read_cmd_fd, &keys) != -1)
3004# else
3005 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3006# endif
3007 {
3008 buf[0] = keys.c_cc[VERASE];
3009 intr_char = keys.c_cc[VINTR];
3010#else
3011 /* for "old" tty systems */
3012 struct sgttyb keys;
3013
3014 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3015 {
3016 buf[0] = keys.sg_erase;
3017 intr_char = keys.sg_kill;
3018#endif
3019 buf[1] = NUL;
3020 add_termcode((char_u *)"kb", buf, FALSE);
3021
3022 /*
3023 * If <BS> and <DEL> are now the same, redefine <DEL>.
3024 */
3025 p = find_termcode((char_u *)"kD");
3026 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3027 do_fixdel(NULL);
3028 }
3029#if 0
3030 } /* to keep cindent happy */
3031#endif
3032}
3033
3034#endif /* VMS */
3035
3036#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3037/*
3038 * Set mouse clicks on or off.
3039 */
3040 void
3041mch_setmouse(on)
3042 int on;
3043{
3044 static int ison = FALSE;
3045 int xterm_mouse_vers;
3046
3047 if (on == ison) /* return quickly if nothing to do */
3048 return;
3049
3050 xterm_mouse_vers = use_xterm_mouse();
3051 if (xterm_mouse_vers > 0)
3052 {
3053 if (on) /* enable mouse events, use mouse tracking if available */
3054 out_str_nf((char_u *)
3055 (xterm_mouse_vers > 1
3056 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3057 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3058 else /* disable mouse events, could probably always send the same */
3059 out_str_nf((char_u *)
3060 (xterm_mouse_vers > 1
3061 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3062 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3063 ison = on;
3064 }
3065
3066# ifdef FEAT_MOUSE_DEC
3067 else if (ttym_flags == TTYM_DEC)
3068 {
3069 if (on) /* enable mouse events */
3070 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3071 else /* disable mouse events */
3072 out_str_nf((char_u *)"\033['z");
3073 ison = on;
3074 }
3075# endif
3076
3077# ifdef FEAT_MOUSE_GPM
3078 else
3079 {
3080 if (on)
3081 {
3082 if (gpm_open())
3083 ison = TRUE;
3084 }
3085 else
3086 {
3087 gpm_close();
3088 ison = FALSE;
3089 }
3090 }
3091# endif
3092
3093# ifdef FEAT_MOUSE_JSB
3094 else
3095 {
3096 if (on)
3097 {
3098 /* D - Enable Mouse up/down messages
3099 * L - Enable Left Button Reporting
3100 * M - Enable Middle Button Reporting
3101 * R - Enable Right Button Reporting
3102 * K - Enable SHIFT and CTRL key Reporting
3103 * + - Enable Advanced messaging of mouse moves and up/down messages
3104 * Q - Quiet No Ack
3105 * # - Numeric value of mouse pointer required
3106 * 0 = Multiview 2000 cursor, used as standard
3107 * 1 = Windows Arrow
3108 * 2 = Windows I Beam
3109 * 3 = Windows Hour Glass
3110 * 4 = Windows Cross Hair
3111 * 5 = Windows UP Arrow
3112 */
3113#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3114 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3115 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3116#else
3117 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3118 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3119#endif
3120 ison = TRUE;
3121 }
3122 else
3123 {
3124 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3125 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3126 ison = FALSE;
3127 }
3128 }
3129# endif
3130# ifdef FEAT_MOUSE_PTERM
3131 else
3132 {
3133 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3134 if (on)
3135 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3136 else
3137 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3138 ison = on;
3139 }
3140# endif
3141}
3142
3143/*
3144 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3145 */
3146 void
3147check_mouse_termcode()
3148{
3149# ifdef FEAT_MOUSE_XTERM
3150 if (use_xterm_mouse()
3151# ifdef FEAT_GUI
3152 && !gui.in_use
3153# endif
3154 )
3155 {
3156 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003157 ? IF_EB("\233M", CSI_STR "M")
3158 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003159 if (*p_mouse != NUL)
3160 {
3161 /* force mouse off and maybe on to send possibly new mouse
3162 * activation sequence to the xterm, with(out) drag tracing. */
3163 mch_setmouse(FALSE);
3164 setmouse();
3165 }
3166 }
3167 else
3168 del_mouse_termcode(KS_MOUSE);
3169# endif
3170
3171# ifdef FEAT_MOUSE_GPM
3172 if (!use_xterm_mouse()
3173# ifdef FEAT_GUI
3174 && !gui.in_use
3175# endif
3176 )
3177 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3178# endif
3179
3180# ifdef FEAT_MOUSE_JSB
3181 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3182 if (!use_xterm_mouse()
3183# ifdef FEAT_GUI
3184 && !gui.in_use
3185# endif
3186 )
3187 set_mouse_termcode(KS_JSBTERM_MOUSE,
3188 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3189 else
3190 del_mouse_termcode(KS_JSBTERM_MOUSE);
3191# endif
3192
3193# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003194 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003195 * define it in the GUI or when using an xterm. */
3196 if (!use_xterm_mouse()
3197# ifdef FEAT_GUI
3198 && !gui.in_use
3199# endif
3200 )
3201 set_mouse_termcode(KS_NETTERM_MOUSE,
3202 (char_u *)IF_EB("\033}", ESC_STR "}"));
3203 else
3204 del_mouse_termcode(KS_NETTERM_MOUSE);
3205# endif
3206
3207# ifdef FEAT_MOUSE_DEC
3208 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3209 if (!use_xterm_mouse()
3210# ifdef FEAT_GUI
3211 && !gui.in_use
3212# endif
3213 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003214 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3215 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003216 else
3217 del_mouse_termcode(KS_DEC_MOUSE);
3218# endif
3219# ifdef FEAT_MOUSE_PTERM
3220 /* same as the dec mouse */
3221 if (!use_xterm_mouse()
3222# ifdef FEAT_GUI
3223 && !gui.in_use
3224# endif
3225 )
3226 set_mouse_termcode(KS_PTERM_MOUSE,
3227 (char_u *) IF_EB("\033[", ESC_STR "["));
3228 else
3229 del_mouse_termcode(KS_PTERM_MOUSE);
3230# endif
3231}
3232#endif
3233
3234/*
3235 * set screen mode, always fails.
3236 */
3237/* ARGSUSED */
3238 int
3239mch_screenmode(arg)
3240 char_u *arg;
3241{
3242 EMSG(_(e_screenmode));
3243 return FAIL;
3244}
3245
3246#ifndef VMS
3247
3248/*
3249 * Try to get the current window size:
3250 * 1. with an ioctl(), most accurate method
3251 * 2. from the environment variables LINES and COLUMNS
3252 * 3. from the termcap
3253 * 4. keep using the old values
3254 * Return OK when size could be determined, FAIL otherwise.
3255 */
3256 int
3257mch_get_shellsize()
3258{
3259 long rows = 0;
3260 long columns = 0;
3261 char_u *p;
3262
3263 /*
3264 * For OS/2 use _scrsize().
3265 */
3266# ifdef __EMX__
3267 {
3268 int s[2];
3269
3270 _scrsize(s);
3271 columns = s[0];
3272 rows = s[1];
3273 }
3274# endif
3275
3276 /*
3277 * 1. try using an ioctl. It is the most accurate method.
3278 *
3279 * Try using TIOCGWINSZ first, some systems that have it also define
3280 * TIOCGSIZE but don't have a struct ttysize.
3281 */
3282# ifdef TIOCGWINSZ
3283 {
3284 struct winsize ws;
3285 int fd = 1;
3286
3287 /* When stdout is not a tty, use stdin for the ioctl(). */
3288 if (!isatty(fd) && isatty(read_cmd_fd))
3289 fd = read_cmd_fd;
3290 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3291 {
3292 columns = ws.ws_col;
3293 rows = ws.ws_row;
3294 }
3295 }
3296# else /* TIOCGWINSZ */
3297# ifdef TIOCGSIZE
3298 {
3299 struct ttysize ts;
3300 int fd = 1;
3301
3302 /* When stdout is not a tty, use stdin for the ioctl(). */
3303 if (!isatty(fd) && isatty(read_cmd_fd))
3304 fd = read_cmd_fd;
3305 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3306 {
3307 columns = ts.ts_cols;
3308 rows = ts.ts_lines;
3309 }
3310 }
3311# endif /* TIOCGSIZE */
3312# endif /* TIOCGWINSZ */
3313
3314 /*
3315 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003316 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3317 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003318 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003319 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003320 {
3321 if ((p = (char_u *)getenv("LINES")))
3322 rows = atoi((char *)p);
3323 if ((p = (char_u *)getenv("COLUMNS")))
3324 columns = atoi((char *)p);
3325 }
3326
3327#ifdef HAVE_TGETENT
3328 /*
3329 * 3. try reading "co" and "li" entries from termcap
3330 */
3331 if (columns == 0 || rows == 0)
3332 getlinecol(&columns, &rows);
3333#endif
3334
3335 /*
3336 * 4. If everything fails, use the old values
3337 */
3338 if (columns <= 0 || rows <= 0)
3339 return FAIL;
3340
3341 Rows = rows;
3342 Columns = columns;
3343 return OK;
3344}
3345
3346/*
3347 * Try to set the window size to Rows and Columns.
3348 */
3349 void
3350mch_set_shellsize()
3351{
3352 if (*T_CWS)
3353 {
3354 /*
3355 * NOTE: if you get an error here that term_set_winsize() is
3356 * undefined, check the output of configure. It could probably not
3357 * find a ncurses, termcap or termlib library.
3358 */
3359 term_set_winsize((int)Rows, (int)Columns);
3360 out_flush();
3361 screen_start(); /* don't know where cursor is now */
3362 }
3363}
3364
3365#endif /* VMS */
3366
3367/*
3368 * Rows and/or Columns has changed.
3369 */
3370 void
3371mch_new_shellsize()
3372{
3373 /* Nothing to do. */
3374}
3375
Bram Moolenaardf177f62005-02-22 08:39:57 +00003376#ifndef USE_SYSTEM
3377static void append_ga_line __ARGS((garray_T *gap));
3378
3379/*
3380 * Append the text in "gap" below the cursor line and clear "gap".
3381 */
3382 static void
3383append_ga_line(gap)
3384 garray_T *gap;
3385{
3386 /* Remove trailing CR. */
3387 if (gap->ga_len > 0
3388 && !curbuf->b_p_bin
3389 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3390 --gap->ga_len;
3391 ga_append(gap, NUL);
3392 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3393 gap->ga_len = 0;
3394}
3395#endif
3396
Bram Moolenaar071d4272004-06-13 20:20:40 +00003397 int
3398mch_call_shell(cmd, options)
3399 char_u *cmd;
3400 int options; /* SHELL_*, see vim.h */
3401{
3402#ifdef VMS
3403 char *ifn = NULL;
3404 char *ofn = NULL;
3405#endif
3406 int tmode = cur_tmode;
3407#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3408 int x;
3409# ifndef __EMX__
3410 char_u *newcmd; /* only needed for unix */
3411# else
3412 /*
3413 * Set the preferred shell in the EMXSHELL environment variable (but
3414 * only if it is different from what is already in the environment).
3415 * Emx then takes care of whether to use "/c" or "-c" in an
3416 * intelligent way. Simply pass the whole thing to emx's system() call.
3417 * Emx also starts an interactive shell if system() is passed an empty
3418 * string.
3419 */
3420 char_u *p, *old;
3421
3422 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3423 {
3424 /* should check HAVE_SETENV, but I know we don't have it. */
3425 p = alloc(10 + strlen(p_sh));
3426 if (p)
3427 {
3428 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3429 putenv((char *)p); /* don't free the pointer! */
3430 }
3431 }
3432# endif
3433
3434 out_flush();
3435
3436 if (options & SHELL_COOKED)
3437 settmode(TMODE_COOK); /* set to normal mode */
3438
3439# ifdef __EMX__
3440 if (cmd == NULL)
3441 x = system(""); /* this starts an interactive shell in emx */
3442 else
3443 x = system((char *)cmd);
3444 /* system() returns -1 when error occurs in starting shell */
3445 if (x == -1 && !emsg_silent)
3446 {
3447 MSG_PUTS(_("\nCannot execute shell "));
3448 msg_outtrans(p_sh);
3449 msg_putchar('\n');
3450 }
3451# else /* not __EMX__ */
3452 if (cmd == NULL)
3453 x = system((char *)p_sh);
3454 else
3455 {
3456# ifdef VMS
3457 if (ofn = strchr((char *)cmd, '>'))
3458 *ofn++ = '\0';
3459 if (ifn = strchr((char *)cmd, '<'))
3460 {
3461 char *p;
3462
3463 *ifn++ = '\0';
3464 p = strchr(ifn,' '); /* chop off any trailing spaces */
3465 if (p)
3466 *p = '\0';
3467 }
3468 if (ofn)
3469 x = vms_sys((char *)cmd, ofn, ifn);
3470 else
3471 x = system((char *)cmd);
3472# else
3473 newcmd = lalloc(STRLEN(p_sh)
3474 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3475 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3476 if (newcmd == NULL)
3477 x = 0;
3478 else
3479 {
3480 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3481 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3482 (char *)p_shcf,
3483 (char *)cmd);
3484 x = system((char *)newcmd);
3485 vim_free(newcmd);
3486 }
3487# endif
3488 }
3489# ifdef VMS
3490 x = vms_sys_status(x);
3491# endif
3492 if (emsg_silent)
3493 ;
3494 else if (x == 127)
3495 MSG_PUTS(_("\nCannot execute shell sh\n"));
3496# endif /* __EMX__ */
3497 else if (x && !(options & SHELL_SILENT))
3498 {
3499 MSG_PUTS(_("\nshell returned "));
3500 msg_outnum((long)x);
3501 msg_putchar('\n');
3502 }
3503
3504 if (tmode == TMODE_RAW)
3505 settmode(TMODE_RAW); /* set to raw mode */
3506# ifdef FEAT_TITLE
3507 resettitle();
3508# endif
3509 return x;
3510
3511#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3512
Bram Moolenaardf177f62005-02-22 08:39:57 +00003513# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3514 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003515
3516 char_u *newcmd = NULL;
3517 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003518 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519 pid_t wait_pid = 0;
3520# ifdef HAVE_UNION_WAIT
3521 union wait status;
3522# else
3523 int status = -1;
3524# endif
3525 int retval = -1;
3526 char **argv = NULL;
3527 int argc;
3528 int i;
3529 char_u *p;
3530 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003531 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003532# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003533 int pty_slave_fd = -1;
3534 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003535# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003536 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003537 int fd_fromshell[2];
3538 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003539# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003541# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542 static char envbuf_Rows[20];
3543 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003544# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003545 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546
3547 out_flush();
3548 if (options & SHELL_COOKED)
3549 settmode(TMODE_COOK); /* set to normal mode */
3550
Bram Moolenaar071d4272004-06-13 20:20:40 +00003551 newcmd = vim_strsave(p_sh);
3552 if (newcmd == NULL) /* out of memory */
3553 goto error;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003554
3555 /*
3556 * Do this loop twice:
3557 * 1: find number of arguments
3558 * 2: separate them and build argv[]
3559 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003560 for (i = 0; i < 2; ++i)
3561 {
3562 p = newcmd;
3563 inquote = FALSE;
3564 argc = 0;
3565 for (;;)
3566 {
3567 if (i == 1)
3568 argv[argc] = (char *)p;
3569 ++argc;
3570 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3571 {
3572 if (*p == '"')
3573 inquote = !inquote;
3574 ++p;
3575 }
3576 if (*p == NUL)
3577 break;
3578 if (i == 1)
3579 *p++ = NUL;
3580 p = skipwhite(p);
3581 }
3582 if (i == 0)
3583 {
3584 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3585 if (argv == NULL) /* out of memory */
3586 goto error;
3587 }
3588 }
3589 if (cmd != NULL)
3590 {
3591 if (extra_shell_arg != NULL)
3592 argv[argc++] = (char *)extra_shell_arg;
3593 argv[argc++] = (char *)p_shcf;
3594 argv[argc++] = (char *)cmd;
3595 }
3596 argv[argc] = NULL;
3597
Bram Moolenaar071d4272004-06-13 20:20:40 +00003598 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003599 * For the GUI, when writing the output into the buffer and when reading
3600 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3601 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003603 if ((options & (SHELL_READ|SHELL_WRITE))
3604# ifdef FEAT_GUI
3605 || (gui.in_use && show_shell_mess)
3606# endif
3607 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003608 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003609# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003610 /*
3611 * Try to open a master pty.
3612 * If this works, open the slave pty.
3613 * If the slave can't be opened, close the master pty.
3614 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003615 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003616 {
3617 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3618 if (pty_master_fd >= 0 && ((pty_slave_fd =
3619 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3620 {
3621 close(pty_master_fd);
3622 pty_master_fd = -1;
3623 }
3624 }
3625 /*
3626 * If not opening a pty or it didn't work, try using pipes.
3627 */
3628 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003629# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003630 {
3631 pipe_error = (pipe(fd_toshell) < 0);
3632 if (!pipe_error) /* pipe create OK */
3633 {
3634 pipe_error = (pipe(fd_fromshell) < 0);
3635 if (pipe_error) /* pipe create failed */
3636 {
3637 close(fd_toshell[0]);
3638 close(fd_toshell[1]);
3639 }
3640 }
3641 if (pipe_error)
3642 {
3643 MSG_PUTS(_("\nCannot create pipes\n"));
3644 out_flush();
3645 }
3646 }
3647 }
3648
3649 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003650 {
3651# ifdef __BEOS__
3652 beos_cleanup_read_thread();
3653# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003654
Bram Moolenaar071d4272004-06-13 20:20:40 +00003655 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3656 {
3657 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003658 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003659# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003660 || (gui.in_use && show_shell_mess)
3661# endif
3662 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003664# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665 if (pty_master_fd >= 0) /* close the pseudo tty */
3666 {
3667 close(pty_master_fd);
3668 close(pty_slave_fd);
3669 }
3670 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003671# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003672 {
3673 close(fd_toshell[0]);
3674 close(fd_toshell[1]);
3675 close(fd_fromshell[0]);
3676 close(fd_fromshell[1]);
3677 }
3678 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003679 }
3680 else if (pid == 0) /* child */
3681 {
3682 reset_signals(); /* handle signals normally */
3683
3684 if (!show_shell_mess || (options & SHELL_EXPAND))
3685 {
3686 int fd;
3687
3688 /*
3689 * Don't want to show any message from the shell. Can't just
3690 * close stdout and stderr though, because some systems will
3691 * break if you try to write to them after that, so we must
3692 * use dup() to replace them with something else -- webb
3693 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3694 * waiting for input.
3695 */
3696 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3697 fclose(stdin);
3698 fclose(stdout);
3699 fclose(stderr);
3700
3701 /*
3702 * If any of these open()'s and dup()'s fail, we just continue
3703 * anyway. It's not fatal, and on most systems it will make
3704 * no difference at all. On a few it will cause the execvp()
3705 * to exit with a non-zero status even when the completion
3706 * could be done, which is nothing too serious. If the open()
3707 * or dup() failed we'd just do the same thing ourselves
3708 * anyway -- webb
3709 */
3710 if (fd >= 0)
3711 {
3712 dup(fd); /* To replace stdin (file descriptor 0) */
3713 dup(fd); /* To replace stdout (file descriptor 1) */
3714 dup(fd); /* To replace stderr (file descriptor 2) */
3715
3716 /* Don't need this now that we've duplicated it */
3717 close(fd);
3718 }
3719 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003720 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003721# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003722 || gui.in_use
3723# endif
3724 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003725 {
3726
Bram Moolenaardf177f62005-02-22 08:39:57 +00003727# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003728 /* Create our own process group, so that the child and all its
3729 * children can be kill()ed. Don't do this when using pipes,
3730 * because stdin is not a tty, we would loose /dev/tty. */
3731 if (p_stmp)
3732 (void)setsid();
Bram Moolenaardf177f62005-02-22 08:39:57 +00003733# endif
3734# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003735 if (pty_slave_fd >= 0)
3736 {
3737 /* push stream discipline modules */
3738 if (options & SHELL_COOKED)
3739 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003740# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003741 /* Try to become controlling tty (probably doesn't work,
3742 * unless run by root) */
3743 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003744# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003745 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003746# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003747 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003748# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003749 setenv("TERM", "dumb", 1);
3750 sprintf((char *)envbuf, "%ld", Rows);
3751 setenv("ROWS", (char *)envbuf, 1);
3752 sprintf((char *)envbuf, "%ld", Rows);
3753 setenv("LINES", (char *)envbuf, 1);
3754 sprintf((char *)envbuf, "%ld", Columns);
3755 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003756# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003757 /*
3758 * Putenv does not copy the string, it has to remain valid.
3759 * Use a static array to avoid loosing allocated memory.
3760 */
3761 putenv("TERM=dumb");
3762 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
3763 putenv(envbuf_Rows);
3764 sprintf(envbuf_Rows, "LINES=%ld", Rows);
3765 putenv(envbuf_Rows);
3766 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
3767 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003768# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769
Bram Moolenaara5792f52005-11-23 21:25:05 +00003770 /*
3771 * stderr is only redirected when using the GUI, so that a
3772 * program like gpg can still access the terminal to get a
3773 * passphrase using stderr.
3774 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003775# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003776 if (pty_master_fd >= 0)
3777 {
3778 close(pty_master_fd); /* close master side of pty */
3779
3780 /* set up stdin/stdout/stderr for the child */
3781 close(0);
3782 dup(pty_slave_fd);
3783 close(1);
3784 dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003785 if (gui.in_use)
3786 {
3787 close(2);
3788 dup(pty_slave_fd);
3789 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003790
3791 close(pty_slave_fd); /* has been dupped, close it now */
3792 }
3793 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003794# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795 {
3796 /* set up stdin for the child */
3797 close(fd_toshell[1]);
3798 close(0);
3799 dup(fd_toshell[0]);
3800 close(fd_toshell[0]);
3801
3802 /* set up stdout for the child */
3803 close(fd_fromshell[0]);
3804 close(1);
3805 dup(fd_fromshell[1]);
3806 close(fd_fromshell[1]);
3807
Bram Moolenaara5792f52005-11-23 21:25:05 +00003808# ifdef FEAT_GUI
3809 if (gui.in_use)
3810 {
3811 /* set up stderr for the child */
3812 close(2);
3813 dup(1);
3814 }
3815# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003816 }
3817 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003818
Bram Moolenaar071d4272004-06-13 20:20:40 +00003819 /*
3820 * There is no type cast for the argv, because the type may be
3821 * different on different machines. This may cause a warning
3822 * message with strict compilers, don't worry about it.
3823 * Call _exit() instead of exit() to avoid closing the connection
3824 * to the X server (esp. with GTK, which uses atexit()).
3825 */
3826 execvp(argv[0], argv);
3827 _exit(EXEC_FAILED); /* exec failed, return failure code */
3828 }
3829 else /* parent */
3830 {
3831 /*
3832 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003833 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003834 */
3835 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003836 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003837
3838 /*
3839 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003840 * This is also used to pipe stdin/stdout to/from the external
3841 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003842 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003843 if ((options & (SHELL_READ|SHELL_WRITE))
3844# ifdef FEAT_GUI
3845 || (gui.in_use && show_shell_mess)
3846# endif
3847 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003848 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003849# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003850 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003851# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003852 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003853# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003854 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
3855 int ta_len = 0; /* valid bytes in ta_buf[] */
3856 int len;
3857 int p_more_save;
3858 int old_State;
3859 int c;
3860 int toshell_fd;
3861 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003862 garray_T ga;
3863 int noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003864
Bram Moolenaardf177f62005-02-22 08:39:57 +00003865# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003866 if (pty_master_fd >= 0)
3867 {
3868 close(pty_slave_fd); /* close slave side of pty */
3869 fromshell_fd = pty_master_fd;
3870 toshell_fd = dup(pty_master_fd);
3871 }
3872 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003873# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003874 {
3875 close(fd_toshell[0]);
3876 close(fd_fromshell[1]);
3877 toshell_fd = fd_toshell[1];
3878 fromshell_fd = fd_fromshell[0];
3879 }
3880
3881 /*
3882 * Write to the child if there are typed characters.
3883 * Read from the child if there are characters available.
3884 * Repeat the reading a few times if more characters are
3885 * available. Need to check for typed keys now and then, but
3886 * not too often (delays when no chars are available).
3887 * This loop is quit if no characters can be read from the pty
3888 * (WaitForChar detected special condition), or there are no
3889 * characters available and the child has exited.
3890 * Only check if the child has exited when there is no more
3891 * output. The child may exit before all the output has
3892 * been printed.
3893 *
3894 * Currently this busy loops!
3895 * This can probably dead-lock when the write blocks!
3896 */
3897 p_more_save = p_more;
3898 p_more = FALSE;
3899 old_State = State;
3900 State = EXTERNCMD; /* don't redraw at window resize */
3901
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003902 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003903 {
3904 /* Fork a process that will write the lines to the
3905 * external program. */
3906 if ((wpid = fork()) == -1)
3907 {
3908 MSG_PUTS(_("\nCannot fork\n"));
3909 }
3910 else if (wpid == 0)
3911 {
3912 linenr_T lnum = curbuf->b_op_start.lnum;
3913 int written = 0;
3914 char_u *p = ml_get(lnum);
3915 char_u *s;
3916 size_t l;
3917
3918 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00003919 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003920 for (;;)
3921 {
3922 l = STRLEN(p + written);
3923 if (l == 0)
3924 len = 0;
3925 else if (p[written] == NL)
3926 /* NL -> NUL translation */
3927 len = write(toshell_fd, "", (size_t)1);
3928 else
3929 {
3930 s = vim_strchr(p + written, NL);
3931 len = write(toshell_fd, (char *)p + written,
3932 s == NULL ? l : s - (p + written));
3933 }
3934 if (len == l)
3935 {
3936 /* Finished a line, add a NL, unless this line
3937 * should not have one. */
3938 if (lnum != curbuf->b_op_end.lnum
3939 || !curbuf->b_p_bin
3940 || (lnum != write_no_eol_lnum
3941 && (lnum !=
3942 curbuf->b_ml.ml_line_count
3943 || curbuf->b_p_eol)))
3944 write(toshell_fd, "\n", (size_t)1);
3945 ++lnum;
3946 if (lnum > curbuf->b_op_end.lnum)
3947 {
3948 /* finished all the lines, close pipe */
3949 close(toshell_fd);
3950 toshell_fd = -1;
3951 break;
3952 }
3953 p = ml_get(lnum);
3954 written = 0;
3955 }
3956 else if (len > 0)
3957 written += len;
3958 }
3959 _exit(0);
3960 }
3961 else
3962 {
3963 close(toshell_fd);
3964 toshell_fd = -1;
3965 }
3966 }
3967
3968 if (options & SHELL_READ)
3969 ga_init2(&ga, 1, BUFLEN);
3970
3971 noread_cnt = 0;
3972
Bram Moolenaar071d4272004-06-13 20:20:40 +00003973 for (;;)
3974 {
3975 /*
3976 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00003977 * if there are any.
3978 * Don't do this if we are expanding wild cards (would eat
3979 * typeahead).
3980 * Don't do this when filtering and terminal is in cooked
3981 * mode, the shell command will handle the I/O. Avoids
3982 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003983 * Don't get characters when the child has already
3984 * finished (wait_pid == 0).
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00003985 * Don't get extra characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003986 * Don't read characters unless we didn't get output for a
3987 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003988 */
3989 len = 0;
3990 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00003991 && ((options &
3992 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
3993 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
3994#ifdef FEAT_GUI
3995 || gui.in_use
3996#endif
3997 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003998 && wait_pid == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003999 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00004000 || (noread_cnt > 4
4001 && (len = ui_inchar(ta_buf,
4002 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004003 {
4004 /*
4005 * For pipes:
4006 * Check for CTRL-C: send interrupt signal to child.
4007 * Check for CTRL-D: EOF, close pipe to child.
4008 */
4009 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4010 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004011# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004012 /*
4013 * Send SIGINT to the child's group or all
4014 * processes in our group.
4015 */
4016 if (ta_buf[ta_len] == Ctrl_C
4017 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004018 {
4019# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004020 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004021# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004024 if (wpid > 0)
4025 kill(wpid, SIGINT);
4026 }
4027# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028 if (pty_master_fd < 0 && toshell_fd >= 0
4029 && ta_buf[ta_len] == Ctrl_D)
4030 {
4031 close(toshell_fd);
4032 toshell_fd = -1;
4033 }
4034 }
4035
4036 /* replace K_BS by <BS> and K_DEL by <DEL> */
4037 for (i = ta_len; i < ta_len + len; ++i)
4038 {
4039 if (ta_buf[i] == CSI && len - i > 2)
4040 {
4041 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4042 if (c == K_DEL || c == K_KDEL || c == K_BS)
4043 {
4044 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4045 (size_t)(len - i - 2));
4046 if (c == K_DEL || c == K_KDEL)
4047 ta_buf[i] = DEL;
4048 else
4049 ta_buf[i] = Ctrl_H;
4050 len -= 2;
4051 }
4052 }
4053 else if (ta_buf[i] == '\r')
4054 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004055# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004056 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004057 i += (*mb_ptr2len)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004058# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004059 }
4060
4061 /*
4062 * For pipes: echo the typed characters.
4063 * For a pty this does not seem to work.
4064 */
4065 if (pty_master_fd < 0)
4066 {
4067 for (i = ta_len; i < ta_len + len; ++i)
4068 {
4069 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4070 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004071# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072 else if (has_mbyte)
4073 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004074 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004075
4076 msg_outtrans_len(ta_buf + i, l);
4077 i += l - 1;
4078 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004079# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004080 else
4081 msg_outtrans_len(ta_buf + i, 1);
4082 }
4083 windgoto(msg_row, msg_col);
4084 out_flush();
4085 }
4086
4087 ta_len += len;
4088
4089 /*
4090 * Write the characters to the child, unless EOF has
4091 * been typed for pipes. Write one character at a
4092 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004093 * When writing buffer lines, drop the typed
4094 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004095 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004096 if (options & SHELL_WRITE)
4097 ta_len = 0;
4098 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004099 {
4100 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4101 if (len > 0)
4102 {
4103 ta_len -= len;
4104 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004105 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106 }
4107 }
4108 }
4109
Bram Moolenaardf177f62005-02-22 08:39:57 +00004110 if (got_int)
4111 {
4112 /* CTRL-C sends a signal to the child, we ignore it
4113 * ourselves */
4114# ifdef HAVE_SETSID
4115 kill(-pid, SIGINT);
4116# else
4117 kill(0, SIGINT);
4118# endif
4119 if (wpid > 0)
4120 kill(wpid, SIGINT);
4121 got_int = FALSE;
4122 }
4123
Bram Moolenaar071d4272004-06-13 20:20:40 +00004124 /*
4125 * Check if the child has any characters to be printed.
4126 * Read them and write them to our window. Repeat this as
4127 * long as there is something to do, avoid the 10ms wait
4128 * for mch_inchar(), or sending typeahead characters to
4129 * the external process.
4130 * TODO: This should handle escape sequences, compatible
4131 * to some terminal (vt52?).
4132 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004133 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004134 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4135 {
4136 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004137# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004139# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004141# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004142 );
4143 if (len <= 0) /* end of file or error */
4144 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004145
4146 noread_cnt = 0;
4147 if (options & SHELL_READ)
4148 {
4149 /* Do NUL -> NL translation, append NL separated
4150 * lines to the current buffer. */
4151 for (i = 0; i < len; ++i)
4152 {
4153 if (buffer[i] == NL)
4154 append_ga_line(&ga);
4155 else if (buffer[i] == NUL)
4156 ga_append(&ga, NL);
4157 else
4158 ga_append(&ga, buffer[i]);
4159 }
4160 }
4161# ifdef FEAT_MBYTE
4162 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004163 {
4164 int l;
4165
Bram Moolenaardf177f62005-02-22 08:39:57 +00004166 len += buffer_off;
4167 buffer[len] = NUL;
4168
Bram Moolenaar071d4272004-06-13 20:20:40 +00004169 /* Check if the last character in buffer[] is
4170 * incomplete, keep these bytes for the next
4171 * round. */
4172 for (p = buffer; p < buffer + len; p += l)
4173 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004174 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175 if (l == 0)
4176 l = 1; /* NUL byte? */
4177 else if (MB_BYTE2LEN(*p) != l)
4178 break;
4179 }
4180 if (p == buffer) /* no complete character */
4181 {
4182 /* avoid getting stuck at an illegal byte */
4183 if (len >= 12)
4184 ++p;
4185 else
4186 {
4187 buffer_off = len;
4188 continue;
4189 }
4190 }
4191 c = *p;
4192 *p = NUL;
4193 msg_puts(buffer);
4194 if (p < buffer + len)
4195 {
4196 *p = c;
4197 buffer_off = (buffer + len) - p;
4198 mch_memmove(buffer, p, buffer_off);
4199 continue;
4200 }
4201 buffer_off = 0;
4202 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004203# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004204 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004205 {
4206 buffer[len] = NUL;
4207 msg_puts(buffer);
4208 }
4209
4210 windgoto(msg_row, msg_col);
4211 cursor_on();
4212 out_flush();
4213 if (got_int)
4214 break;
4215 }
4216
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004217 /* If we already detected the child has finished break the
4218 * loop now. */
4219 if (wait_pid == pid)
4220 break;
4221
Bram Moolenaar071d4272004-06-13 20:20:40 +00004222 /*
4223 * Check if the child still exists, before checking for
4224 * typed characters (otherwise we would loose typeahead).
4225 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004226# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004227 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004228# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004229 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004230# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004231 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4232 || (wait_pid == pid && WIFEXITED(status)))
4233 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004234 /* Don't break the loop yet, try reading more
4235 * characters from "fromshell_fd" first. When using
4236 * pipes there might still be something to read and
4237 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004238 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004239 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004240 else
4241 wait_pid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004242 }
4243finished:
4244 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004245 if (options & SHELL_READ)
4246 {
4247 if (ga.ga_len > 0)
4248 {
4249 append_ga_line(&ga);
4250 /* remember that the NL was missing */
4251 write_no_eol_lnum = curwin->w_cursor.lnum;
4252 }
4253 else
4254 write_no_eol_lnum = 0;
4255 ga_clear(&ga);
4256 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257
Bram Moolenaar071d4272004-06-13 20:20:40 +00004258 /*
4259 * Give all typeahead that wasn't used back to ui_inchar().
4260 */
4261 if (ta_len)
4262 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263 State = old_State;
4264 if (toshell_fd >= 0)
4265 close(toshell_fd);
4266 close(fromshell_fd);
4267 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004268
4269 /*
4270 * Wait until our child has exited.
4271 * Ignore wait() returning pids of other children and returning
4272 * because of some signal like SIGWINCH.
4273 * Don't wait if wait_pid was already set above, indicating the
4274 * child already exited.
4275 */
4276 while (wait_pid != pid)
4277 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004278# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004279 /* Ugly hack: when compiled with Python threads are probably
4280 * used, in which case wait() sometimes hangs for no obvious
4281 * reason. Use waitpid() instead and loop (like the GUI). */
4282# ifdef __NeXT__
4283 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4284# else
4285 wait_pid = waitpid(pid, &status, WNOHANG);
4286# endif
4287 if (wait_pid == 0)
4288 {
4289 /* Wait for 1/100 sec before trying again. */
4290 mch_delay(10L, TRUE);
4291 continue;
4292 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004293# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004294 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004295# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004296 if (wait_pid <= 0
4297# ifdef ECHILD
4298 && errno == ECHILD
4299# endif
4300 )
4301 break;
4302 }
4303
Bram Moolenaardf177f62005-02-22 08:39:57 +00004304 /* Make sure the child that writes to the external program is
4305 * dead. */
4306 if (wpid > 0)
4307 kill(wpid, SIGKILL);
4308
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309 /*
4310 * Set to raw mode right now, otherwise a CTRL-C after
4311 * catch_signals() will kill Vim.
4312 */
4313 if (tmode == TMODE_RAW)
4314 settmode(TMODE_RAW);
4315 did_settmode = TRUE;
4316 set_signals();
4317
4318 if (WIFEXITED(status))
4319 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004320 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321 retval = WEXITSTATUS(status);
4322 if (retval && !emsg_silent)
4323 {
4324 if (retval == EXEC_FAILED)
4325 {
4326 MSG_PUTS(_("\nCannot execute shell "));
4327 msg_outtrans(p_sh);
4328 msg_putchar('\n');
4329 }
4330 else if (!(options & SHELL_SILENT))
4331 {
4332 MSG_PUTS(_("\nshell returned "));
4333 msg_outnum((long)retval);
4334 msg_putchar('\n');
4335 }
4336 }
4337 }
4338 else
4339 MSG_PUTS(_("\nCommand terminated\n"));
4340 }
4341 }
4342 vim_free(argv);
4343
4344error:
4345 if (!did_settmode)
4346 if (tmode == TMODE_RAW)
4347 settmode(TMODE_RAW); /* set to raw mode */
4348# ifdef FEAT_TITLE
4349 resettitle();
4350# endif
4351 vim_free(newcmd);
4352
4353 return retval;
4354
4355#endif /* USE_SYSTEM */
4356}
4357
4358/*
4359 * Check for CTRL-C typed by reading all available characters.
4360 * In cooked mode we should get SIGINT, no need to check.
4361 */
4362 void
4363mch_breakcheck()
4364{
4365 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4366 fill_input_buf(FALSE);
4367}
4368
4369/*
4370 * Wait "msec" msec until a character is available from the keyboard or from
4371 * inbuf[]. msec == -1 will block forever.
4372 * When a GUI is being used, this will never get called -- webb
4373 */
4374 static int
4375WaitForChar(msec)
4376 long msec;
4377{
4378#ifdef FEAT_MOUSE_GPM
4379 int gpm_process_wanted;
4380#endif
4381#ifdef FEAT_XCLIPBOARD
4382 int rest;
4383#endif
4384 int avail;
4385
4386 if (input_available()) /* something in inbuf[] */
4387 return 1;
4388
4389#if defined(FEAT_MOUSE_DEC)
4390 /* May need to query the mouse position. */
4391 if (WantQueryMouse)
4392 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004393 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004394 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4395 }
4396#endif
4397
4398 /*
4399 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4400 * events. This is a bit complicated, because they might both be defined.
4401 */
4402#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4403# ifdef FEAT_XCLIPBOARD
4404 rest = 0;
4405 if (do_xterm_trace())
4406 rest = msec;
4407# endif
4408 do
4409 {
4410# ifdef FEAT_XCLIPBOARD
4411 if (rest != 0)
4412 {
4413 msec = XT_TRACE_DELAY;
4414 if (rest >= 0 && rest < XT_TRACE_DELAY)
4415 msec = rest;
4416 if (rest >= 0)
4417 rest -= msec;
4418 }
4419# endif
4420# ifdef FEAT_MOUSE_GPM
4421 gpm_process_wanted = 0;
4422 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4423# else
4424 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4425# endif
4426 if (!avail)
4427 {
4428 if (input_available())
4429 return 1;
4430# ifdef FEAT_XCLIPBOARD
4431 if (rest == 0 || !do_xterm_trace())
4432# endif
4433 break;
4434 }
4435 }
4436 while (FALSE
4437# ifdef FEAT_MOUSE_GPM
4438 || (gpm_process_wanted && mch_gpm_process() == 0)
4439# endif
4440# ifdef FEAT_XCLIPBOARD
4441 || (!avail && rest != 0)
4442# endif
4443 );
4444
4445#else
4446 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4447#endif
4448 return avail;
4449}
4450
4451/*
4452 * Wait "msec" msec until a character is available from file descriptor "fd".
4453 * Time == -1 will block forever.
4454 * When a GUI is being used, this will not be used for input -- webb
4455 * Returns also, when a request from Sniff is waiting -- toni.
4456 * Or when a Linux GPM mouse event is waiting.
4457 */
4458/* ARGSUSED */
4459#if defined(__BEOS__)
4460 int
4461#else
4462 static int
4463#endif
4464RealWaitForChar(fd, msec, check_for_gpm)
4465 int fd;
4466 long msec;
4467 int *check_for_gpm;
4468{
4469 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004470#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004471 static int busy = FALSE;
4472
4473 /* May retry getting characters after an event was handled. */
4474# define MAY_LOOP
4475
4476# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4477 /* Remember at what time we started, so that we know how much longer we
4478 * should wait after being interrupted. */
4479# define USE_START_TV
4480 struct timeval start_tv;
4481
4482 if (msec > 0 && (
4483# ifdef FEAT_XCLIPBOARD
4484 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004485# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004486 ||
4487# endif
4488# endif
4489# ifdef USE_XSMP
4490 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004491# ifdef FEAT_MZSCHEME
4492 ||
4493# endif
4494# endif
4495# ifdef FEAT_MZSCHEME
4496 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004497# endif
4498 ))
4499 gettimeofday(&start_tv, NULL);
4500# endif
4501
4502 /* Handle being called recursively. This may happen for the session
4503 * manager stuff, it may save the file, which does a breakcheck. */
4504 if (busy)
4505 return 0;
4506#endif
4507
4508#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00004509 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004510#endif
4511 {
4512#ifdef MAY_LOOP
4513 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004514# ifdef FEAT_MZSCHEME
4515 int mzquantum_used = FALSE;
4516# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004517#endif
4518#ifndef HAVE_SELECT
4519 struct pollfd fds[5];
4520 int nfd;
4521# ifdef FEAT_XCLIPBOARD
4522 int xterm_idx = -1;
4523# endif
4524# ifdef FEAT_MOUSE_GPM
4525 int gpm_idx = -1;
4526# endif
4527# ifdef USE_XSMP
4528 int xsmp_idx = -1;
4529# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004530 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004531
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004532# ifdef FEAT_MZSCHEME
4533 mzvim_check_threads();
4534 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4535 {
4536 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4537 mzquantum_used = TRUE;
4538 }
4539# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004540 fds[0].fd = fd;
4541 fds[0].events = POLLIN;
4542 nfd = 1;
4543
4544# ifdef FEAT_SNIFF
4545# define SNIFF_IDX 1
4546 if (want_sniff_request)
4547 {
4548 fds[SNIFF_IDX].fd = fd_from_sniff;
4549 fds[SNIFF_IDX].events = POLLIN;
4550 nfd++;
4551 }
4552# endif
4553# ifdef FEAT_XCLIPBOARD
4554 if (xterm_Shell != (Widget)0)
4555 {
4556 xterm_idx = nfd;
4557 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4558 fds[nfd].events = POLLIN;
4559 nfd++;
4560 }
4561# endif
4562# ifdef FEAT_MOUSE_GPM
4563 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4564 {
4565 gpm_idx = nfd;
4566 fds[nfd].fd = gpm_fd;
4567 fds[nfd].events = POLLIN;
4568 nfd++;
4569 }
4570# endif
4571# ifdef USE_XSMP
4572 if (xsmp_icefd != -1)
4573 {
4574 xsmp_idx = nfd;
4575 fds[nfd].fd = xsmp_icefd;
4576 fds[nfd].events = POLLIN;
4577 nfd++;
4578 }
4579# endif
4580
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004581 ret = poll(fds, nfd, towait);
4582# ifdef FEAT_MZSCHEME
4583 if (ret == 0 && mzquantum_used)
4584 /* MzThreads scheduling is required and timeout occured */
4585 finished = FALSE;
4586# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004587
4588# ifdef FEAT_SNIFF
4589 if (ret < 0)
4590 sniff_disconnect(1);
4591 else if (want_sniff_request)
4592 {
4593 if (fds[SNIFF_IDX].revents & POLLHUP)
4594 sniff_disconnect(1);
4595 if (fds[SNIFF_IDX].revents & POLLIN)
4596 sniff_request_waiting = 1;
4597 }
4598# endif
4599# ifdef FEAT_XCLIPBOARD
4600 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4601 {
4602 xterm_update(); /* Maybe we should hand out clipboard */
4603 if (--ret == 0 && !input_available())
4604 /* Try again */
4605 finished = FALSE;
4606 }
4607# endif
4608# ifdef FEAT_MOUSE_GPM
4609 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4610 {
4611 *check_for_gpm = 1;
4612 }
4613# endif
4614# ifdef USE_XSMP
4615 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4616 {
4617 if (fds[xsmp_idx].revents & POLLIN)
4618 {
4619 busy = TRUE;
4620 xsmp_handle_requests();
4621 busy = FALSE;
4622 }
4623 else if (fds[xsmp_idx].revents & POLLHUP)
4624 {
4625 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004626 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 xsmp_close();
4628 }
4629 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004630 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004631 }
4632# endif
4633
4634
4635#else /* HAVE_SELECT */
4636
4637 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004638 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004639 fd_set rfds, efds;
4640 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004641 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004642
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004643# ifdef FEAT_MZSCHEME
4644 mzvim_check_threads();
4645 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4646 {
4647 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4648 mzquantum_used = TRUE;
4649 }
4650# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004651# ifdef __EMX__
4652 /* don't check for incoming chars if not in raw mode, because select()
4653 * always returns TRUE then (in some version of emx.dll) */
4654 if (curr_tmode != TMODE_RAW)
4655 return 0;
4656# endif
4657
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004658 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004659 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004660 tv.tv_sec = towait / 1000;
4661 tv.tv_usec = (towait % 1000) * (1000000/1000);
4662 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004663 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004664 else
4665 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004666
4667 /*
4668 * Select on ready for reading and exceptional condition (end of file).
4669 */
4670 FD_ZERO(&rfds); /* calls bzero() on a sun */
4671 FD_ZERO(&efds);
4672 FD_SET(fd, &rfds);
4673# if !defined(__QNX__) && !defined(__CYGWIN32__)
4674 /* For QNX select() always returns 1 if this is set. Why? */
4675 FD_SET(fd, &efds);
4676# endif
4677 maxfd = fd;
4678
4679# ifdef FEAT_SNIFF
4680 if (want_sniff_request)
4681 {
4682 FD_SET(fd_from_sniff, &rfds);
4683 FD_SET(fd_from_sniff, &efds);
4684 if (maxfd < fd_from_sniff)
4685 maxfd = fd_from_sniff;
4686 }
4687# endif
4688# ifdef FEAT_XCLIPBOARD
4689 if (xterm_Shell != (Widget)0)
4690 {
4691 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4692 if (maxfd < ConnectionNumber(xterm_dpy))
4693 maxfd = ConnectionNumber(xterm_dpy);
4694 }
4695# endif
4696# ifdef FEAT_MOUSE_GPM
4697 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4698 {
4699 FD_SET(gpm_fd, &rfds);
4700 FD_SET(gpm_fd, &efds);
4701 if (maxfd < gpm_fd)
4702 maxfd = gpm_fd;
4703 }
4704# endif
4705# ifdef USE_XSMP
4706 if (xsmp_icefd != -1)
4707 {
4708 FD_SET(xsmp_icefd, &rfds);
4709 FD_SET(xsmp_icefd, &efds);
4710 if (maxfd < xsmp_icefd)
4711 maxfd = xsmp_icefd;
4712 }
4713# endif
4714
4715# ifdef OLD_VMS
4716 /* Old VMS as v6.2 and older have broken select(). It waits more than
4717 * required. Should not be used */
4718 ret = 0;
4719# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004720 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4721# endif
4722# ifdef FEAT_MZSCHEME
4723 if (ret == 0 && mzquantum_used)
4724 /* loop if MzThreads must be scheduled and timeout occured */
4725 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004726# endif
4727
4728# ifdef FEAT_SNIFF
4729 if (ret < 0 )
4730 sniff_disconnect(1);
4731 else if (ret > 0 && want_sniff_request)
4732 {
4733 if (FD_ISSET(fd_from_sniff, &efds))
4734 sniff_disconnect(1);
4735 if (FD_ISSET(fd_from_sniff, &rfds))
4736 sniff_request_waiting = 1;
4737 }
4738# endif
4739# ifdef FEAT_XCLIPBOARD
4740 if (ret > 0 && xterm_Shell != (Widget)0
4741 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4742 {
4743 xterm_update(); /* Maybe we should hand out clipboard */
4744 /* continue looping when we only got the X event and the input
4745 * buffer is empty */
4746 if (--ret == 0 && !input_available())
4747 {
4748 /* Try again */
4749 finished = FALSE;
4750 }
4751 }
4752# endif
4753# ifdef FEAT_MOUSE_GPM
4754 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4755 {
4756 if (FD_ISSET(gpm_fd, &efds))
4757 gpm_close();
4758 else if (FD_ISSET(gpm_fd, &rfds))
4759 *check_for_gpm = 1;
4760 }
4761# endif
4762# ifdef USE_XSMP
4763 if (ret > 0 && xsmp_icefd != -1)
4764 {
4765 if (FD_ISSET(xsmp_icefd, &efds))
4766 {
4767 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004768 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004769 xsmp_close();
4770 if (--ret == 0)
4771 finished = FALSE; /* keep going if event was only one */
4772 }
4773 else if (FD_ISSET(xsmp_icefd, &rfds))
4774 {
4775 busy = TRUE;
4776 xsmp_handle_requests();
4777 busy = FALSE;
4778 if (--ret == 0)
4779 finished = FALSE; /* keep going if event was only one */
4780 }
4781 }
4782# endif
4783
4784#endif /* HAVE_SELECT */
4785
4786#ifdef MAY_LOOP
4787 if (finished || msec == 0)
4788 break;
4789
4790 /* We're going to loop around again, find out for how long */
4791 if (msec > 0)
4792 {
4793# ifdef USE_START_TV
4794 struct timeval mtv;
4795
4796 /* Compute remaining wait time. */
4797 gettimeofday(&mtv, NULL);
4798 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
4799 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
4800# else
4801 /* Guess we got interrupted halfway. */
4802 msec = msec / 2;
4803# endif
4804 if (msec <= 0)
4805 break; /* waited long enough */
4806 }
4807#endif
4808 }
4809
4810 return (ret > 0);
4811}
4812
4813#ifndef VMS
4814
4815#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004816/*
Bram Moolenaar02743632005-07-25 20:42:36 +00004817 * Expand a path into all matching files and/or directories. Handles "*",
4818 * "?", "[a-z]", "**", etc.
4819 * "path" has backslashes before chars that are not to be expanded.
4820 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004821 */
4822 int
4823mch_expandpath(gap, path, flags)
4824 garray_T *gap;
4825 char_u *path;
4826 int flags; /* EW_* flags */
4827{
Bram Moolenaar02743632005-07-25 20:42:36 +00004828 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004829}
4830#endif
4831
4832/*
4833 * mch_expand_wildcards() - this code does wild-card pattern matching using
4834 * the shell
4835 *
4836 * return OK for success, FAIL for error (you may lose some memory) and put
4837 * an error message in *file.
4838 *
4839 * num_pat is number of input patterns
4840 * pat is array of pointers to input patterns
4841 * num_file is pointer to number of matched file names
4842 * file is pointer to array of pointers to matched file names
4843 */
4844
4845#ifndef SEEK_SET
4846# define SEEK_SET 0
4847#endif
4848#ifndef SEEK_END
4849# define SEEK_END 2
4850#endif
4851
Bram Moolenaard12f5c12006-01-25 22:10:52 +00004852#define SHELL_SPECIAL (char_u *)"\t \"&';<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00004853
Bram Moolenaar071d4272004-06-13 20:20:40 +00004854/* ARGSUSED */
4855 int
4856mch_expand_wildcards(num_pat, pat, num_file, file, flags)
4857 int num_pat;
4858 char_u **pat;
4859 int *num_file;
4860 char_u ***file;
4861 int flags; /* EW_* flags */
4862{
4863 int i;
4864 size_t len;
4865 char_u *p;
4866 int dir;
4867#ifdef __EMX__
4868# define EXPL_ALLOC_INC 16
4869 char_u **expl_files;
4870 size_t files_alloced, files_free;
4871 char_u *buf;
4872 int has_wildcard;
4873
4874 *num_file = 0; /* default: no files found */
4875 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
4876 files_free = EXPL_ALLOC_INC; /* how much space is not used */
4877 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
4878 if (*file == NULL)
4879 return FAIL;
4880
4881 for (; num_pat > 0; num_pat--, pat++)
4882 {
4883 expl_files = NULL;
4884 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
4885 /* expand environment var or home dir */
4886 buf = expand_env_save(*pat);
4887 else
4888 buf = vim_strsave(*pat);
4889 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00004890 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004891 if (has_wildcard) /* yes, so expand them */
4892 expl_files = (char_u **)_fnexplode(buf);
4893
4894 /*
4895 * return value of buf if no wildcards left,
4896 * OR if no match AND EW_NOTFOUND is set.
4897 */
4898 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
4899 || (expl_files == NULL && (flags & EW_NOTFOUND)))
4900 { /* simply save the current contents of *buf */
4901 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
4902 if (expl_files != NULL)
4903 {
4904 expl_files[0] = vim_strsave(buf);
4905 expl_files[1] = NULL;
4906 }
4907 }
4908 vim_free(buf);
4909
4910 /*
4911 * Count number of names resulting from expansion,
4912 * At the same time add a backslash to the end of names that happen to
4913 * be directories, and replace slashes with backslashes.
4914 */
4915 if (expl_files)
4916 {
4917 for (i = 0; (p = expl_files[i]) != NULL; i++)
4918 {
4919 dir = mch_isdir(p);
4920 /* If we don't want dirs and this is one, skip it */
4921 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
4922 continue;
4923
Bram Moolenaara2031822006-03-07 22:29:51 +00004924 /* Skip files that are not executable if we check for that. */
4925 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
4926 continue;
4927
Bram Moolenaar071d4272004-06-13 20:20:40 +00004928 if (--files_free == 0)
4929 {
4930 /* need more room in table of pointers */
4931 files_alloced += EXPL_ALLOC_INC;
4932 *file = (char_u **)vim_realloc(*file,
4933 sizeof(char_u **) * files_alloced);
4934 if (*file == NULL)
4935 {
4936 EMSG(_(e_outofmem));
4937 *num_file = 0;
4938 return FAIL;
4939 }
4940 files_free = EXPL_ALLOC_INC;
4941 }
4942 slash_adjust(p);
4943 if (dir)
4944 {
4945 /* For a directory we add a '/', unless it's already
4946 * there. */
4947 len = STRLEN(p);
4948 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
4949 {
4950 STRCPY((*file)[*num_file], p);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004951 if (!after_pathsep((*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004952 {
4953 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004954 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004955 }
4956 }
4957 }
4958 else
4959 {
4960 (*file)[*num_file] = vim_strsave(p);
4961 }
4962
4963 /*
4964 * Error message already given by either alloc or vim_strsave.
4965 * Should return FAIL, but returning OK works also.
4966 */
4967 if ((*file)[*num_file] == NULL)
4968 break;
4969 (*num_file)++;
4970 }
4971 _fnexplodefree((char **)expl_files);
4972 }
4973 }
4974 return OK;
4975
4976#else /* __EMX__ */
4977
4978 int j;
4979 char_u *tempname;
4980 char_u *command;
4981 FILE *fd;
4982 char_u *buffer;
4983#define STYLE_ECHO 0 /* use "echo" to expand */
4984#define STYLE_GLOB 1 /* use "glob" to expand, for csh */
4985#define STYLE_PRINT 2 /* use "print -N" to expand, for zsh */
4986#define STYLE_BT 3 /* `cmd` expansion, execute the pattern directly */
4987 int shell_style = STYLE_ECHO;
4988 int check_spaces;
4989 static int did_find_nul = FALSE;
4990 int ampersent = FALSE;
4991
4992 *num_file = 0; /* default: no files found */
4993 *file = NULL;
4994
4995 /*
4996 * If there are no wildcards, just copy the names to allocated memory.
4997 * Saves a lot of time, because we don't have to start a new shell.
4998 */
4999 if (!have_wildcard(num_pat, pat))
5000 return save_patterns(num_pat, pat, num_file, file);
5001
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005002# ifdef HAVE_SANDBOX
5003 /* Don't allow any shell command in the sandbox. */
5004 if (sandbox != 0 && check_secure())
5005 return FAIL;
5006# endif
5007
Bram Moolenaar071d4272004-06-13 20:20:40 +00005008 /*
5009 * Don't allow the use of backticks in secure and restricted mode.
5010 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005011 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005012 for (i = 0; i < num_pat; ++i)
5013 if (vim_strchr(pat[i], '`') != NULL
5014 && (check_restricted() || check_secure()))
5015 return FAIL;
5016
5017 /*
5018 * get a name for the temp file
5019 */
5020 if ((tempname = vim_tempname('o')) == NULL)
5021 {
5022 EMSG(_(e_notmp));
5023 return FAIL;
5024 }
5025
5026 /*
5027 * Let the shell expand the patterns and write the result into the temp
5028 * file. if expanding `cmd` execute it directly.
5029 * If we use csh, glob will work better than echo.
5030 * If we use zsh, print -N will work better than glob.
5031 */
5032 if (num_pat == 1 && *pat[0] == '`'
5033 && (len = STRLEN(pat[0])) > 2
5034 && *(pat[0] + len - 1) == '`')
5035 shell_style = STYLE_BT;
5036 else if ((len = STRLEN(p_sh)) >= 3)
5037 {
5038 if (STRCMP(p_sh + len - 3, "csh") == 0)
5039 shell_style = STYLE_GLOB;
5040 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5041 shell_style = STYLE_PRINT;
5042 }
5043
5044 /* "unset nonomatch; print -N >" plus two is 29 */
5045 len = STRLEN(tempname) + 29;
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005046 for (i = 0; i < num_pat; ++i)
5047 {
5048 /* Count the length of the patterns in the same way as they are put in
5049 * "command" below. */
5050#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005052#else
5053 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005054 for (j = 0; pat[i][j] != NUL; ++j)
5055 {
5056 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5057 ++len; /* may add a backslash */
5058 ++len;
5059 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005060#endif
5061 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005062 command = alloc(len);
5063 if (command == NULL)
5064 {
5065 /* out of memory */
5066 vim_free(tempname);
5067 return FAIL;
5068 }
5069
5070 /*
5071 * Build the shell command:
5072 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5073 * recognizes this).
5074 * - Add the shell command to print the expanded names.
5075 * - Add the temp file name.
5076 * - Add the file name patterns.
5077 */
5078 if (shell_style == STYLE_BT)
5079 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005080 /* change `command; command& ` to (command; command ) */
5081 STRCPY(command, "(");
5082 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005083 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005084 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005085 while (p > command && vim_iswhite(*p))
5086 --p;
5087 if (*p == '&') /* remove trailing '&' */
5088 {
5089 ampersent = TRUE;
5090 *p = ' ';
5091 }
5092 STRCAT(command, ">");
5093 }
5094 else
5095 {
5096 if (flags & EW_NOTFOUND)
5097 STRCPY(command, "set nonomatch; ");
5098 else
5099 STRCPY(command, "unset nonomatch; ");
5100 if (shell_style == STYLE_GLOB)
5101 STRCAT(command, "glob >");
5102 else if (shell_style == STYLE_PRINT)
5103 STRCAT(command, "print -N >");
5104 else
5105 STRCAT(command, "echo >");
5106 }
5107 STRCAT(command, tempname);
5108 if (shell_style != STYLE_BT)
5109 for (i = 0; i < num_pat; ++i)
5110 {
5111 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005112 * is started twice. Otherwise put a backslash before special
5113 * characters, except insice ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005114#ifdef USE_SYSTEM
5115 STRCAT(command, " \"");
5116 STRCAT(command, pat[i]);
5117 STRCAT(command, "\"");
5118#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005119 int intick = FALSE;
5120
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121 p = command + STRLEN(command);
5122 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005123 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005124 {
5125 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005126 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005127 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5128 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005129 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005130 * backslash inside backticks, before a special character
5131 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005132 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005133 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5134 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005135 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005136 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005137 }
5138 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005139 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005140 /* Put a backslash before a special character, but not
5141 * when inside ``. */
5142 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005143
5144 /* Copy one character. */
5145 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005146 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005147 *p = NUL;
5148#endif
5149 }
5150 if (flags & EW_SILENT)
5151 show_shell_mess = FALSE;
5152 if (ampersent)
5153 STRCAT(command, "&"); /* put the '&' back after the
5154 redirection */
5155
5156 /*
5157 * Using zsh -G: If a pattern has no matches, it is just deleted from
5158 * the argument list, otherwise zsh gives an error message and doesn't
5159 * expand any other pattern.
5160 */
5161 if (shell_style == STYLE_PRINT)
5162 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5163
5164 /*
5165 * If we use -f then shell variables set in .cshrc won't get expanded.
5166 * vi can do it, so we will too, but it is only necessary if there is a "$"
5167 * in one of the patterns, otherwise we can still use the fast option.
5168 */
5169 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5170 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5171
5172 /*
5173 * execute the shell command
5174 */
5175 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5176
5177 /* When running in the background, give it some time to create the temp
5178 * file, but don't wait for it to finish. */
5179 if (ampersent)
5180 mch_delay(10L, TRUE);
5181
5182 extra_shell_arg = NULL; /* cleanup */
5183 show_shell_mess = TRUE;
5184 vim_free(command);
5185
5186 if (i) /* mch_call_shell() failed */
5187 {
5188 mch_remove(tempname);
5189 vim_free(tempname);
5190 /*
5191 * With interactive completion, the error message is not printed.
5192 * However with USE_SYSTEM, I don't know how to turn off error messages
5193 * from the shell, so screen may still get messed up -- webb.
5194 */
5195#ifndef USE_SYSTEM
5196 if (!(flags & EW_SILENT))
5197#endif
5198 {
5199 redraw_later_clear(); /* probably messed up screen */
5200 msg_putchar('\n'); /* clear bottom line quickly */
5201 cmdline_row = Rows - 1; /* continue on last line */
5202#ifdef USE_SYSTEM
5203 if (!(flags & EW_SILENT))
5204#endif
5205 {
5206 MSG(_(e_wildexpand));
5207 msg_start(); /* don't overwrite this message */
5208 }
5209 }
5210 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5211 * EW_NOTFOUND is given */
5212 if (shell_style == STYLE_BT)
5213 return FAIL;
5214 goto notfound;
5215 }
5216
5217 /*
5218 * read the names from the file into memory
5219 */
5220 fd = fopen((char *)tempname, READBIN);
5221 if (fd == NULL)
5222 {
5223 /* Something went wrong, perhaps a file name with a special char. */
5224 if (!(flags & EW_SILENT))
5225 {
5226 MSG(_(e_wildexpand));
5227 msg_start(); /* don't overwrite this message */
5228 }
5229 vim_free(tempname);
5230 goto notfound;
5231 }
5232 fseek(fd, 0L, SEEK_END);
5233 len = ftell(fd); /* get size of temp file */
5234 fseek(fd, 0L, SEEK_SET);
5235 buffer = alloc(len + 1);
5236 if (buffer == NULL)
5237 {
5238 /* out of memory */
5239 mch_remove(tempname);
5240 vim_free(tempname);
5241 fclose(fd);
5242 return FAIL;
5243 }
5244 i = fread((char *)buffer, 1, len, fd);
5245 fclose(fd);
5246 mch_remove(tempname);
5247 if (i != len)
5248 {
5249 /* unexpected read error */
5250 EMSG2(_(e_notread), tempname);
5251 vim_free(tempname);
5252 vim_free(buffer);
5253 return FAIL;
5254 }
5255 vim_free(tempname);
5256
5257#if defined(__CYGWIN__) || defined(__CYGWIN32__)
5258 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5259 p = buffer;
5260 for (i = 0; i < len; ++i)
5261 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5262 *p++ = buffer[i];
5263 len = p - buffer;
5264# endif
5265
5266
5267 /* file names are separated with Space */
5268 if (shell_style == STYLE_ECHO)
5269 {
5270 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5271 p = buffer;
5272 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5273 {
5274 while (*p != ' ' && *p != '\n')
5275 ++p;
5276 p = skipwhite(p); /* skip to next entry */
5277 }
5278 }
5279 /* file names are separated with NL */
5280 else if (shell_style == STYLE_BT)
5281 {
5282 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5283 p = buffer;
5284 for (i = 0; *p != NUL; ++i) /* count number of entries */
5285 {
5286 while (*p != '\n' && *p != NUL)
5287 ++p;
5288 if (*p != NUL)
5289 ++p;
5290 p = skipwhite(p); /* skip leading white space */
5291 }
5292 }
5293 /* file names are separated with NUL */
5294 else
5295 {
5296 /*
5297 * Some versions of zsh use spaces instead of NULs to separate
5298 * results. Only do this when there is no NUL before the end of the
5299 * buffer, otherwise we would never be able to use file names with
5300 * embedded spaces when zsh does use NULs.
5301 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5302 * don't check for spaces again.
5303 */
5304 check_spaces = FALSE;
5305 if (shell_style == STYLE_PRINT && !did_find_nul)
5306 {
5307 /* If there is a NUL, set did_find_nul, else set check_spaces */
5308 if (len && (int)STRLEN(buffer) < len - 1)
5309 did_find_nul = TRUE;
5310 else
5311 check_spaces = TRUE;
5312 }
5313
5314 /*
5315 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5316 * already is one, for STYLE_GLOB it needs to be added.
5317 */
5318 if (len && buffer[len - 1] == NUL)
5319 --len;
5320 else
5321 buffer[len] = NUL;
5322 i = 0;
5323 for (p = buffer; p < buffer + len; ++p)
5324 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5325 {
5326 ++i;
5327 *p = NUL;
5328 }
5329 if (len)
5330 ++i; /* count last entry */
5331 }
5332 if (i == 0)
5333 {
5334 /*
5335 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5336 * /bin/sh will happily expand it to nothing rather than returning an
5337 * error; and hey, it's good to check anyway -- webb.
5338 */
5339 vim_free(buffer);
5340 goto notfound;
5341 }
5342 *num_file = i;
5343 *file = (char_u **)alloc(sizeof(char_u *) * i);
5344 if (*file == NULL)
5345 {
5346 /* out of memory */
5347 vim_free(buffer);
5348 return FAIL;
5349 }
5350
5351 /*
5352 * Isolate the individual file names.
5353 */
5354 p = buffer;
5355 for (i = 0; i < *num_file; ++i)
5356 {
5357 (*file)[i] = p;
5358 /* Space or NL separates */
5359 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT)
5360 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00005361 while (!(shell_style == STYLE_ECHO && *p == ' ')
5362 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005363 ++p;
5364 if (p == buffer + len) /* last entry */
5365 *p = NUL;
5366 else
5367 {
5368 *p++ = NUL;
5369 p = skipwhite(p); /* skip to next entry */
5370 }
5371 }
5372 else /* NUL separates */
5373 {
5374 while (*p && p < buffer + len) /* skip entry */
5375 ++p;
5376 ++p; /* skip NUL */
5377 }
5378 }
5379
5380 /*
5381 * Move the file names to allocated memory.
5382 */
5383 for (j = 0, i = 0; i < *num_file; ++i)
5384 {
5385 /* Require the files to exist. Helps when using /bin/sh */
5386 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5387 continue;
5388
5389 /* check if this entry should be included */
5390 dir = (mch_isdir((*file)[i]));
5391 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5392 continue;
5393
Bram Moolenaara2031822006-03-07 22:29:51 +00005394 /* Skip files that are not executable if we check for that. */
5395 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
5396 continue;
5397
Bram Moolenaar071d4272004-06-13 20:20:40 +00005398 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5399 if (p)
5400 {
5401 STRCPY(p, (*file)[i]);
5402 if (dir)
5403 STRCAT(p, "/"); /* add '/' to a directory name */
5404 (*file)[j++] = p;
5405 }
5406 }
5407 vim_free(buffer);
5408 *num_file = j;
5409
5410 if (*num_file == 0) /* rejected all entries */
5411 {
5412 vim_free(*file);
5413 *file = NULL;
5414 goto notfound;
5415 }
5416
5417 return OK;
5418
5419notfound:
5420 if (flags & EW_NOTFOUND)
5421 return save_patterns(num_pat, pat, num_file, file);
5422 return FAIL;
5423
5424#endif /* __EMX__ */
5425}
5426
5427#endif /* VMS */
5428
5429#ifndef __EMX__
5430 static int
5431save_patterns(num_pat, pat, num_file, file)
5432 int num_pat;
5433 char_u **pat;
5434 int *num_file;
5435 char_u ***file;
5436{
5437 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005438 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005439
5440 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5441 if (*file == NULL)
5442 return FAIL;
5443 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005444 {
5445 s = vim_strsave(pat[i]);
5446 if (s != NULL)
5447 /* Be compatible with expand_filename(): halve the number of
5448 * backslashes. */
5449 backslash_halve(s);
5450 (*file)[i] = s;
5451 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005452 *num_file = num_pat;
5453 return OK;
5454}
5455#endif
5456
5457
5458/*
5459 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5460 * expand.
5461 */
5462 int
5463mch_has_exp_wildcard(p)
5464 char_u *p;
5465{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005466 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005467 {
5468#ifndef OS2
5469 if (*p == '\\' && p[1] != NUL)
5470 ++p;
5471 else
5472#endif
5473 if (vim_strchr((char_u *)
5474#ifdef VMS
5475 "*?%"
5476#else
5477# ifdef OS2
5478 "*?"
5479# else
5480 "*?[{'"
5481# endif
5482#endif
5483 , *p) != NULL)
5484 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005485 }
5486 return FALSE;
5487}
5488
5489/*
5490 * Return TRUE if the string "p" contains a wildcard.
5491 * Don't recognize '~' at the end as a wildcard.
5492 */
5493 int
5494mch_has_wildcard(p)
5495 char_u *p;
5496{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005497 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005498 {
5499#ifndef OS2
5500 if (*p == '\\' && p[1] != NUL)
5501 ++p;
5502 else
5503#endif
5504 if (vim_strchr((char_u *)
5505#ifdef VMS
5506 "*?%$"
5507#else
5508# ifdef OS2
5509# ifdef VIM_BACKTICK
5510 "*?$`"
5511# else
5512 "*?$"
5513# endif
5514# else
5515 "*?[{`'$"
5516# endif
5517#endif
5518 , *p) != NULL
5519 || (*p == '~' && p[1] != NUL))
5520 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005521 }
5522 return FALSE;
5523}
5524
5525#ifndef __EMX__
5526 static int
5527have_wildcard(num, file)
5528 int num;
5529 char_u **file;
5530{
5531 int i;
5532
5533 for (i = 0; i < num; i++)
5534 if (mch_has_wildcard(file[i]))
5535 return 1;
5536 return 0;
5537}
5538
5539 static int
5540have_dollars(num, file)
5541 int num;
5542 char_u **file;
5543{
5544 int i;
5545
5546 for (i = 0; i < num; i++)
5547 if (vim_strchr(file[i], '$') != NULL)
5548 return TRUE;
5549 return FALSE;
5550}
5551#endif /* ifndef __EMX__ */
5552
5553#ifndef HAVE_RENAME
5554/*
5555 * Scaled-down version of rename(), which is missing in Xenix.
5556 * This version can only move regular files and will fail if the
5557 * destination exists.
5558 */
5559 int
5560mch_rename(src, dest)
5561 const char *src, *dest;
5562{
5563 struct stat st;
5564
5565 if (stat(dest, &st) >= 0) /* fail if destination exists */
5566 return -1;
5567 if (link(src, dest) != 0) /* link file to new name */
5568 return -1;
5569 if (mch_remove(src) == 0) /* delete link to old name */
5570 return 0;
5571 return -1;
5572}
5573#endif /* !HAVE_RENAME */
5574
5575#ifdef FEAT_MOUSE_GPM
5576/*
5577 * Initializes connection with gpm (if it isn't already opened)
5578 * Return 1 if succeeded (or connection already opened), 0 if failed
5579 */
5580 static int
5581gpm_open()
5582{
5583 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5584
5585 if (!gpm_flag)
5586 {
5587 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5588 gpm_connect.defaultMask = ~GPM_HARD;
5589 /* Default handling for mouse move*/
5590 gpm_connect.minMod = 0; /* Handle any modifier keys */
5591 gpm_connect.maxMod = 0xffff;
5592 if (Gpm_Open(&gpm_connect, 0) > 0)
5593 {
5594 /* gpm library tries to handling TSTP causes
5595 * problems. Anyways, we close connection to Gpm whenever
5596 * we are going to suspend or starting an external process
5597 * so we should'nt have problem with this
5598 */
5599 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5600 return 1; /* succeed */
5601 }
5602 if (gpm_fd == -2)
5603 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5604 return 0;
5605 }
5606 return 1; /* already open */
5607}
5608
5609/*
5610 * Closes connection to gpm
5611 * returns non-zero if connection succesfully closed
5612 */
5613 static void
5614gpm_close()
5615{
5616 if (gpm_flag && gpm_fd >= 0) /* if Open */
5617 Gpm_Close();
5618}
5619
5620/* Reads gpm event and adds special keys to input buf. Returns length of
5621 * generated key sequence.
5622 * This function is made after gui_send_mouse_event
5623 */
5624 static int
5625mch_gpm_process()
5626{
5627 int button;
5628 static Gpm_Event gpm_event;
5629 char_u string[6];
5630 int_u vim_modifiers;
5631 int row,col;
5632 unsigned char buttons_mask;
5633 unsigned char gpm_modifiers;
5634 static unsigned char old_buttons = 0;
5635
5636 Gpm_GetEvent(&gpm_event);
5637
5638#ifdef FEAT_GUI
5639 /* Don't put events in the input queue now. */
5640 if (hold_gui_events)
5641 return 0;
5642#endif
5643
5644 row = gpm_event.y - 1;
5645 col = gpm_event.x - 1;
5646
5647 string[0] = ESC; /* Our termcode */
5648 string[1] = 'M';
5649 string[2] = 'G';
5650 switch (GPM_BARE_EVENTS(gpm_event.type))
5651 {
5652 case GPM_DRAG:
5653 string[3] = MOUSE_DRAG;
5654 break;
5655 case GPM_DOWN:
5656 buttons_mask = gpm_event.buttons & ~old_buttons;
5657 old_buttons = gpm_event.buttons;
5658 switch (buttons_mask)
5659 {
5660 case GPM_B_LEFT:
5661 button = MOUSE_LEFT;
5662 break;
5663 case GPM_B_MIDDLE:
5664 button = MOUSE_MIDDLE;
5665 break;
5666 case GPM_B_RIGHT:
5667 button = MOUSE_RIGHT;
5668 break;
5669 default:
5670 return 0;
5671 /*Don't know what to do. Can more than one button be
5672 * reported in one event? */
5673 }
5674 string[3] = (char_u)(button | 0x20);
5675 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5676 break;
5677 case GPM_UP:
5678 string[3] = MOUSE_RELEASE;
5679 old_buttons &= ~gpm_event.buttons;
5680 break;
5681 default:
5682 return 0;
5683 }
5684 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5685 gpm_modifiers = gpm_event.modifiers;
5686 vim_modifiers = 0x0;
5687 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5688 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5689 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5690 */
5691 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5692 vim_modifiers |= MOUSE_SHIFT;
5693
5694 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5695 vim_modifiers |= MOUSE_CTRL;
5696 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5697 vim_modifiers |= MOUSE_ALT;
5698 string[3] |= vim_modifiers;
5699 string[4] = (char_u)(col + ' ' + 1);
5700 string[5] = (char_u)(row + ' ' + 1);
5701 add_to_input_buf(string, 6);
5702 return 6;
5703}
5704#endif /* FEAT_MOUSE_GPM */
5705
5706#if defined(FEAT_LIBCALL) || defined(PROTO)
5707typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
5708typedef char_u * (*INTPROCSTR)__ARGS((int));
5709typedef int (*STRPROCINT)__ARGS((char_u *));
5710typedef int (*INTPROCINT)__ARGS((int));
5711
5712/*
5713 * Call a DLL routine which takes either a string or int param
5714 * and returns an allocated string.
5715 */
5716 int
5717mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
5718 char_u *libname;
5719 char_u *funcname;
5720 char_u *argstring; /* NULL when using a argint */
5721 int argint;
5722 char_u **string_result;/* NULL when using number_result */
5723 int *number_result;
5724{
5725# if defined(USE_DLOPEN)
5726 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005727 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005728# else
5729 shl_t hinstLib;
5730# endif
5731 STRPROCSTR ProcAdd;
5732 INTPROCSTR ProcAddI;
5733 char_u *retval_str = NULL;
5734 int retval_int = 0;
5735 int success = FALSE;
5736
5737 /* Get a handle to the DLL module. */
5738# if defined(USE_DLOPEN)
5739 hinstLib = dlopen((char *)libname, RTLD_LAZY
5740# ifdef RTLD_LOCAL
5741 | RTLD_LOCAL
5742# endif
5743 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005744 if (hinstLib == NULL)
5745 {
5746 /* "dlerr" must be used before dlclose() */
5747 dlerr = (char *)dlerror();
5748 if (dlerr != NULL)
5749 EMSG2(_("dlerror = \"%s\""), dlerr);
5750 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005751# else
5752 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
5753# endif
5754
5755 /* If the handle is valid, try to get the function address. */
5756 if (hinstLib != NULL)
5757 {
5758# ifdef HAVE_SETJMP_H
5759 /*
5760 * Catch a crash when calling the library function. For example when
5761 * using a number where a string pointer is expected.
5762 */
5763 mch_startjmp();
5764 if (SETJMP(lc_jump_env) != 0)
5765 {
5766 success = FALSE;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005767 dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005768 mch_didjmp();
5769 }
5770 else
5771# endif
5772 {
5773 retval_str = NULL;
5774 retval_int = 0;
5775
5776 if (argstring != NULL)
5777 {
5778# if defined(USE_DLOPEN)
5779 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005780 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005781# else
5782 if (shl_findsym(&hinstLib, (const char *)funcname,
5783 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
5784 ProcAdd = NULL;
5785# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005786 if ((success = (ProcAdd != NULL
5787# if defined(USE_DLOPEN)
5788 && dlerr == NULL
5789# endif
5790 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005791 {
5792 if (string_result == NULL)
5793 retval_int = ((STRPROCINT)ProcAdd)(argstring);
5794 else
5795 retval_str = (ProcAdd)(argstring);
5796 }
5797 }
5798 else
5799 {
5800# if defined(USE_DLOPEN)
5801 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005802 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005803# else
5804 if (shl_findsym(&hinstLib, (const char *)funcname,
5805 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
5806 ProcAddI = NULL;
5807# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005808 if ((success = (ProcAddI != NULL
5809# if defined(USE_DLOPEN)
5810 && dlerr == NULL
5811# endif
5812 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005813 {
5814 if (string_result == NULL)
5815 retval_int = ((INTPROCINT)ProcAddI)(argint);
5816 else
5817 retval_str = (ProcAddI)(argint);
5818 }
5819 }
5820
5821 /* Save the string before we free the library. */
5822 /* Assume that a "1" or "-1" result is an illegal pointer. */
5823 if (string_result == NULL)
5824 *number_result = retval_int;
5825 else if (retval_str != NULL
5826 && retval_str != (char_u *)1
5827 && retval_str != (char_u *)-1)
5828 *string_result = vim_strsave(retval_str);
5829 }
5830
5831# ifdef HAVE_SETJMP_H
5832 mch_endjmp();
5833# ifdef SIGHASARG
5834 if (lc_signal != 0)
5835 {
5836 int i;
5837
5838 /* try to find the name of this signal */
5839 for (i = 0; signal_info[i].sig != -1; i++)
5840 if (lc_signal == signal_info[i].sig)
5841 break;
5842 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
5843 }
5844# endif
5845# endif
5846
Bram Moolenaar071d4272004-06-13 20:20:40 +00005847# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005848 /* "dlerr" must be used before dlclose() */
5849 if (dlerr != NULL)
5850 EMSG2(_("dlerror = \"%s\""), dlerr);
5851
5852 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005853 (void)dlclose(hinstLib);
5854# else
5855 (void)shl_unload(hinstLib);
5856# endif
5857 }
5858
5859 if (!success)
5860 {
5861 EMSG2(_(e_libcall), funcname);
5862 return FAIL;
5863 }
5864
5865 return OK;
5866}
5867#endif
5868
5869#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
5870static int xterm_trace = -1; /* default: disabled */
5871static int xterm_button;
5872
5873/*
5874 * Setup a dummy window for X selections in a terminal.
5875 */
5876 void
5877setup_term_clip()
5878{
5879 int z = 0;
5880 char *strp = "";
5881 Widget AppShell;
5882
5883 if (!x_connect_to_server())
5884 return;
5885
5886 open_app_context();
5887 if (app_context != NULL && xterm_Shell == (Widget)0)
5888 {
5889 int (*oldhandler)();
5890#if defined(HAVE_SETJMP_H)
5891 int (*oldIOhandler)();
5892#endif
5893# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5894 struct timeval start_tv;
5895
5896 if (p_verbose > 0)
5897 gettimeofday(&start_tv, NULL);
5898# endif
5899
5900 /* Ignore X errors while opening the display */
5901 oldhandler = XSetErrorHandler(x_error_check);
5902
5903#if defined(HAVE_SETJMP_H)
5904 /* Ignore X IO errors while opening the display */
5905 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
5906 mch_startjmp();
5907 if (SETJMP(lc_jump_env) != 0)
5908 {
5909 mch_didjmp();
5910 xterm_dpy = NULL;
5911 }
5912 else
5913#endif
5914 {
5915 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
5916 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
5917#if defined(HAVE_SETJMP_H)
5918 mch_endjmp();
5919#endif
5920 }
5921
5922#if defined(HAVE_SETJMP_H)
5923 /* Now handle X IO errors normally. */
5924 (void)XSetIOErrorHandler(oldIOhandler);
5925#endif
5926 /* Now handle X errors normally. */
5927 (void)XSetErrorHandler(oldhandler);
5928
5929 if (xterm_dpy == NULL)
5930 {
5931 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005932 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005933 return;
5934 }
5935
5936 /* Catch terminating error of the X server connection. */
5937 (void)XSetIOErrorHandler(x_IOerror_handler);
5938
5939# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5940 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005941 {
5942 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005943 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005944 verbose_leave();
5945 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005946# endif
5947
5948 /* Create a Shell to make converters work. */
5949 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
5950 applicationShellWidgetClass, xterm_dpy,
5951 NULL);
5952 if (AppShell == (Widget)0)
5953 return;
5954 xterm_Shell = XtVaCreatePopupShell("VIM",
5955 topLevelShellWidgetClass, AppShell,
5956 XtNmappedWhenManaged, 0,
5957 XtNwidth, 1,
5958 XtNheight, 1,
5959 NULL);
5960 if (xterm_Shell == (Widget)0)
5961 return;
5962
5963 x11_setup_atoms(xterm_dpy);
5964 if (x11_display == NULL)
5965 x11_display = xterm_dpy;
5966
5967 XtRealizeWidget(xterm_Shell);
5968 XSync(xterm_dpy, False);
5969 xterm_update();
5970 }
5971 if (xterm_Shell != (Widget)0)
5972 {
5973 clip_init(TRUE);
5974 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
5975 x11_window = (Window)atol(strp);
5976 /* Check if $WINDOWID is valid. */
5977 if (test_x11_window(xterm_dpy) == FAIL)
5978 x11_window = 0;
5979 if (x11_window != 0)
5980 xterm_trace = 0;
5981 }
5982}
5983
5984 void
5985start_xterm_trace(button)
5986 int button;
5987{
5988 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
5989 return;
5990 xterm_trace = 1;
5991 xterm_button = button;
5992 do_xterm_trace();
5993}
5994
5995
5996 void
5997stop_xterm_trace()
5998{
5999 if (xterm_trace < 0)
6000 return;
6001 xterm_trace = 0;
6002}
6003
6004/*
6005 * Query the xterm pointer and generate mouse termcodes if necessary
6006 * return TRUE if dragging is active, else FALSE
6007 */
6008 static int
6009do_xterm_trace()
6010{
6011 Window root, child;
6012 int root_x, root_y;
6013 int win_x, win_y;
6014 int row, col;
6015 int_u mask_return;
6016 char_u buf[50];
6017 char_u *strp;
6018 long got_hints;
6019 static char_u *mouse_code;
6020 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6021 static int prev_row = 0, prev_col = 0;
6022 static XSizeHints xterm_hints;
6023
6024 if (xterm_trace <= 0)
6025 return FALSE;
6026
6027 if (xterm_trace == 1)
6028 {
6029 /* Get the hints just before tracking starts. The font size might
6030 * have changed recently */
6031 XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints);
6032 if (!(got_hints & PResizeInc)
6033 || xterm_hints.width_inc <= 1
6034 || xterm_hints.height_inc <= 1)
6035 {
6036 xterm_trace = -1; /* Not enough data -- disable tracing */
6037 return FALSE;
6038 }
6039
6040 /* Rely on the same mouse code for the duration of this */
6041 mouse_code = find_termcode(mouse_name);
6042 prev_row = mouse_row;
6043 prev_row = mouse_col;
6044 xterm_trace = 2;
6045
6046 /* Find the offset of the chars, there might be a scrollbar on the
6047 * left of the window and/or a menu on the top (eterm etc.) */
6048 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6049 &win_x, &win_y, &mask_return);
6050 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6051 - (xterm_hints.height_inc / 2);
6052 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6053 xterm_hints.y = 2;
6054 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6055 - (xterm_hints.width_inc / 2);
6056 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6057 xterm_hints.x = 2;
6058 return TRUE;
6059 }
6060 if (mouse_code == NULL)
6061 {
6062 xterm_trace = 0;
6063 return FALSE;
6064 }
6065
6066 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6067 &win_x, &win_y, &mask_return);
6068
6069 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6070 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6071 if (row == prev_row && col == prev_col)
6072 return TRUE;
6073
6074 STRCPY(buf, mouse_code);
6075 strp = buf + STRLEN(buf);
6076 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6077 *strp++ = (char_u)(col + ' ' + 1);
6078 *strp++ = (char_u)(row + ' ' + 1);
6079 *strp = 0;
6080 add_to_input_buf(buf, STRLEN(buf));
6081
6082 prev_row = row;
6083 prev_col = col;
6084 return TRUE;
6085}
6086
6087# if defined(FEAT_GUI) || defined(PROTO)
6088/*
6089 * Destroy the display, window and app_context. Required for GTK.
6090 */
6091 void
6092clear_xterm_clip()
6093{
6094 if (xterm_Shell != (Widget)0)
6095 {
6096 XtDestroyWidget(xterm_Shell);
6097 xterm_Shell = (Widget)0;
6098 }
6099 if (xterm_dpy != NULL)
6100 {
6101#if 0
6102 /* Lesstif and Solaris crash here, lose some memory */
6103 XtCloseDisplay(xterm_dpy);
6104#endif
6105 if (x11_display == xterm_dpy)
6106 x11_display = NULL;
6107 xterm_dpy = NULL;
6108 }
6109#if 0
6110 if (app_context != (XtAppContext)NULL)
6111 {
6112 /* Lesstif and Solaris crash here, lose some memory */
6113 XtDestroyApplicationContext(app_context);
6114 app_context = (XtAppContext)NULL;
6115 }
6116#endif
6117}
6118# endif
6119
6120/*
6121 * Catch up with any queued X events. This may put keyboard input into the
6122 * input buffer, call resize call-backs, trigger timers etc. If there is
6123 * nothing in the X event queue (& no timers pending), then we return
6124 * immediately.
6125 */
6126 static void
6127xterm_update()
6128{
6129 XEvent event;
6130
6131 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6132 {
6133 XtAppNextEvent(app_context, &event);
6134#ifdef FEAT_CLIENTSERVER
6135 {
6136 XPropertyEvent *e = (XPropertyEvent *)&event;
6137
6138 if (e->type == PropertyNotify && e->window == commWindow
6139 && e->atom == commProperty && e->state == PropertyNewValue)
6140 serverEventProc(xterm_dpy, &event);
6141 }
6142#endif
6143 XtDispatchEvent(&event);
6144 }
6145}
6146
6147 int
6148clip_xterm_own_selection(cbd)
6149 VimClipboard *cbd;
6150{
6151 if (xterm_Shell != (Widget)0)
6152 return clip_x11_own_selection(xterm_Shell, cbd);
6153 return FAIL;
6154}
6155
6156 void
6157clip_xterm_lose_selection(cbd)
6158 VimClipboard *cbd;
6159{
6160 if (xterm_Shell != (Widget)0)
6161 clip_x11_lose_selection(xterm_Shell, cbd);
6162}
6163
6164 void
6165clip_xterm_request_selection(cbd)
6166 VimClipboard *cbd;
6167{
6168 if (xterm_Shell != (Widget)0)
6169 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6170}
6171
6172 void
6173clip_xterm_set_selection(cbd)
6174 VimClipboard *cbd;
6175{
6176 clip_x11_set_selection(cbd);
6177}
6178#endif
6179
6180
6181#if defined(USE_XSMP) || defined(PROTO)
6182/*
6183 * Code for X Session Management Protocol.
6184 */
6185static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6186static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6187static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6188static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6189static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6190
6191
6192# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6193static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6194
6195/*
6196 * This is our chance to ask the user if they want to save,
6197 * or abort the logout
6198 */
6199/*ARGSUSED*/
6200 static void
6201xsmp_handle_interaction(smc_conn, client_data)
6202 SmcConn smc_conn;
6203 SmPointer client_data;
6204{
6205 cmdmod_T save_cmdmod;
6206 int cancel_shutdown = False;
6207
6208 save_cmdmod = cmdmod;
6209 cmdmod.confirm = TRUE;
6210 if (check_changed_any(FALSE))
6211 /* Mustn't logout */
6212 cancel_shutdown = True;
6213 cmdmod = save_cmdmod;
6214 setcursor(); /* position cursor */
6215 out_flush();
6216
6217 /* Done interaction */
6218 SmcInteractDone(smc_conn, cancel_shutdown);
6219
6220 /* Finish off
6221 * Only end save-yourself here if we're not cancelling shutdown;
6222 * we'll get a cancelled callback later in which we'll end it.
6223 * Hopefully get around glitchy SMs (like GNOME-1)
6224 */
6225 if (!cancel_shutdown)
6226 {
6227 xsmp.save_yourself = False;
6228 SmcSaveYourselfDone(smc_conn, True);
6229 }
6230}
6231# endif
6232
6233/*
6234 * Callback that starts save-yourself.
6235 */
6236/*ARGSUSED*/
6237 static void
6238xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6239 shutdown, interact_style, fast)
6240 SmcConn smc_conn;
6241 SmPointer client_data;
6242 int save_type;
6243 Bool shutdown;
6244 int interact_style;
6245 Bool fast;
6246{
6247 /* Handle already being in saveyourself */
6248 if (xsmp.save_yourself)
6249 SmcSaveYourselfDone(smc_conn, True);
6250 xsmp.save_yourself = True;
6251 xsmp.shutdown = shutdown;
6252
6253 /* First up, preserve all files */
6254 out_flush();
6255 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6256
6257 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006258 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006259
6260# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6261 /* Now see if we can ask about unsaved files */
6262 if (shutdown && !fast && gui.in_use)
6263 /* Need to interact with user, but need SM's permission */
6264 SmcInteractRequest(smc_conn, SmDialogError,
6265 xsmp_handle_interaction, client_data);
6266 else
6267# endif
6268 {
6269 /* Can stop the cycle here */
6270 SmcSaveYourselfDone(smc_conn, True);
6271 xsmp.save_yourself = False;
6272 }
6273}
6274
6275
6276/*
6277 * Callback to warn us of imminent death.
6278 */
6279/*ARGSUSED*/
6280 static void
6281xsmp_die(smc_conn, client_data)
6282 SmcConn smc_conn;
6283 SmPointer client_data;
6284{
6285 xsmp_close();
6286
6287 /* quit quickly leaving swapfiles for modified buffers behind */
6288 getout_preserve_modified(0);
6289}
6290
6291
6292/*
6293 * Callback to tell us that save-yourself has completed.
6294 */
6295/*ARGSUSED*/
6296 static void
6297xsmp_save_complete(smc_conn, client_data)
6298 SmcConn smc_conn;
6299 SmPointer client_data;
6300{
6301 xsmp.save_yourself = False;
6302}
6303
6304
6305/*
6306 * Callback to tell us that an instigated shutdown was cancelled
6307 * (maybe even by us)
6308 */
6309/*ARGSUSED*/
6310 static void
6311xsmp_shutdown_cancelled(smc_conn, client_data)
6312 SmcConn smc_conn;
6313 SmPointer client_data;
6314{
6315 if (xsmp.save_yourself)
6316 SmcSaveYourselfDone(smc_conn, True);
6317 xsmp.save_yourself = False;
6318 xsmp.shutdown = False;
6319}
6320
6321
6322/*
6323 * Callback to tell us that a new ICE connection has been established.
6324 */
6325/*ARGSUSED*/
6326 static void
6327xsmp_ice_connection(iceConn, clientData, opening, watchData)
6328 IceConn iceConn;
6329 IcePointer clientData;
6330 Bool opening;
6331 IcePointer *watchData;
6332{
6333 /* Intercept creation of ICE connection fd */
6334 if (opening)
6335 {
6336 xsmp_icefd = IceConnectionNumber(iceConn);
6337 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6338 }
6339}
6340
6341
6342/* Handle any ICE processing that's required; return FAIL if SM lost */
6343 int
6344xsmp_handle_requests()
6345{
6346 Bool rep;
6347
6348 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6349 == IceProcessMessagesIOError)
6350 {
6351 /* Lost ICE */
6352 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006353 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006354 xsmp_close();
6355 return FAIL;
6356 }
6357 else
6358 return OK;
6359}
6360
6361static int dummy;
6362
6363/* Set up X Session Management Protocol */
6364 void
6365xsmp_init(void)
6366{
6367 char errorstring[80];
6368 char *clientid;
6369 SmcCallbacks smcallbacks;
6370#if 0
6371 SmPropValue smname;
6372 SmProp smnameprop;
6373 SmProp *smprops[1];
6374#endif
6375
6376 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006377 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006378
6379 xsmp.save_yourself = xsmp.shutdown = False;
6380
6381 /* Set up SM callbacks - must have all, even if they're not used */
6382 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6383 smcallbacks.save_yourself.client_data = NULL;
6384 smcallbacks.die.callback = xsmp_die;
6385 smcallbacks.die.client_data = NULL;
6386 smcallbacks.save_complete.callback = xsmp_save_complete;
6387 smcallbacks.save_complete.client_data = NULL;
6388 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6389 smcallbacks.shutdown_cancelled.client_data = NULL;
6390
6391 /* Set up a watch on ICE connection creations. The "dummy" argument is
6392 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6393 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6394 {
6395 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006396 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006397 return;
6398 }
6399
6400 /* Create an SM connection */
6401 xsmp.smcconn = SmcOpenConnection(
6402 NULL,
6403 NULL,
6404 SmProtoMajor,
6405 SmProtoMinor,
6406 SmcSaveYourselfProcMask | SmcDieProcMask
6407 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6408 &smcallbacks,
6409 NULL,
6410 &clientid,
6411 sizeof(errorstring),
6412 errorstring);
6413 if (xsmp.smcconn == NULL)
6414 {
6415 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00006416
Bram Moolenaar071d4272004-06-13 20:20:40 +00006417 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006418 {
6419 vim_snprintf(errorreport, sizeof(errorreport),
6420 _("XSMP SmcOpenConnection failed: %s"), errorstring);
6421 verb_msg((char_u *)errorreport);
6422 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006423 return;
6424 }
6425 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6426
6427#if 0
6428 /* ID ourselves */
6429 smname.value = "vim";
6430 smname.length = 3;
6431 smnameprop.name = "SmProgram";
6432 smnameprop.type = "SmARRAY8";
6433 smnameprop.num_vals = 1;
6434 smnameprop.vals = &smname;
6435
6436 smprops[0] = &smnameprop;
6437 SmcSetProperties(xsmp.smcconn, 1, smprops);
6438#endif
6439}
6440
6441
6442/* Shut down XSMP comms. */
6443 void
6444xsmp_close()
6445{
6446 if (xsmp_icefd != -1)
6447 {
6448 SmcCloseConnection(xsmp.smcconn, 0, NULL);
6449 xsmp_icefd = -1;
6450 }
6451}
6452#endif /* USE_XSMP */
6453
6454
6455#ifdef EBCDIC
6456/* Translate character to its CTRL- value */
6457char CtrlTable[] =
6458{
6459/* 00 - 5E */
6460 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6461 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6462 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6463 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6464 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6465 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6466/* ^ */ 0x1E,
6467/* - */ 0x1F,
6468/* 61 - 6C */
6469 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6470/* _ */ 0x1F,
6471/* 6E - 80 */
6472 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6473/* a */ 0x01,
6474/* b */ 0x02,
6475/* c */ 0x03,
6476/* d */ 0x37,
6477/* e */ 0x2D,
6478/* f */ 0x2E,
6479/* g */ 0x2F,
6480/* h */ 0x16,
6481/* i */ 0x05,
6482/* 8A - 90 */
6483 0, 0, 0, 0, 0, 0, 0,
6484/* j */ 0x15,
6485/* k */ 0x0B,
6486/* l */ 0x0C,
6487/* m */ 0x0D,
6488/* n */ 0x0E,
6489/* o */ 0x0F,
6490/* p */ 0x10,
6491/* q */ 0x11,
6492/* r */ 0x12,
6493/* 9A - A1 */
6494 0, 0, 0, 0, 0, 0, 0, 0,
6495/* s */ 0x13,
6496/* t */ 0x3C,
6497/* u */ 0x3D,
6498/* v */ 0x32,
6499/* w */ 0x26,
6500/* x */ 0x18,
6501/* y */ 0x19,
6502/* z */ 0x3F,
6503/* AA - AC */
6504 0, 0, 0,
6505/* [ */ 0x27,
6506/* AE - BC */
6507 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6508/* ] */ 0x1D,
6509/* BE - C0 */ 0, 0, 0,
6510/* A */ 0x01,
6511/* B */ 0x02,
6512/* C */ 0x03,
6513/* D */ 0x37,
6514/* E */ 0x2D,
6515/* F */ 0x2E,
6516/* G */ 0x2F,
6517/* H */ 0x16,
6518/* I */ 0x05,
6519/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6520/* J */ 0x15,
6521/* K */ 0x0B,
6522/* L */ 0x0C,
6523/* M */ 0x0D,
6524/* N */ 0x0E,
6525/* O */ 0x0F,
6526/* P */ 0x10,
6527/* Q */ 0x11,
6528/* R */ 0x12,
6529/* DA - DF */ 0, 0, 0, 0, 0, 0,
6530/* \ */ 0x1C,
6531/* E1 */ 0,
6532/* S */ 0x13,
6533/* T */ 0x3C,
6534/* U */ 0x3D,
6535/* V */ 0x32,
6536/* W */ 0x26,
6537/* X */ 0x18,
6538/* Y */ 0x19,
6539/* Z */ 0x3F,
6540/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6541 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6542};
6543
6544char MetaCharTable[]=
6545{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6546 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6547 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6548 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6549 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6550};
6551
6552
6553/* TODO: Use characters NOT numbers!!! */
6554char CtrlCharTable[]=
6555{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6556 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6557 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6558 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6559 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6560};
6561
6562
6563#endif