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