blob: 7d2d0cc9e902ddd94c3679c8b30a1cc7d00e9289 [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
2357/*
2358 * Get file permissions for 'name'.
2359 * Returns -1 when it doesn't exist.
2360 */
2361 long
2362mch_getperm(name)
2363 char_u *name;
2364{
2365 struct stat statb;
2366
2367 /* Keep the #ifdef outside of stat(), it may be a macro. */
2368#ifdef VMS
2369 if (stat((char *)vms_fixfilename(name), &statb))
2370#else
2371 if (stat((char *)name, &statb))
2372#endif
2373 return -1;
2374 return statb.st_mode;
2375}
2376
2377/*
2378 * set file permission for 'name' to 'perm'
2379 *
2380 * return FAIL for failure, OK otherwise
2381 */
2382 int
2383mch_setperm(name, perm)
2384 char_u *name;
2385 long perm;
2386{
2387 return (chmod((char *)
2388#ifdef VMS
2389 vms_fixfilename(name),
2390#else
2391 name,
2392#endif
2393 (mode_t)perm) == 0 ? OK : FAIL);
2394}
2395
2396#if defined(HAVE_ACL) || defined(PROTO)
2397# ifdef HAVE_SYS_ACL_H
2398# include <sys/acl.h>
2399# endif
2400# ifdef HAVE_SYS_ACCESS_H
2401# include <sys/access.h>
2402# endif
2403
2404# ifdef HAVE_SOLARIS_ACL
2405typedef struct vim_acl_solaris_T {
2406 int acl_cnt;
2407 aclent_t *acl_entry;
2408} vim_acl_solaris_T;
2409# endif
2410
2411/*
2412 * Return a pointer to the ACL of file "fname" in allocated memory.
2413 * Return NULL if the ACL is not available for whatever reason.
2414 */
2415 vim_acl_T
2416mch_get_acl(fname)
2417 char_u *fname;
2418{
2419 vim_acl_T ret = NULL;
2420#ifdef HAVE_POSIX_ACL
2421 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2422#else
2423#ifdef HAVE_SOLARIS_ACL
2424 vim_acl_solaris_T *aclent;
2425
2426 aclent = malloc(sizeof(vim_acl_solaris_T));
2427 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2428 {
2429 free(aclent);
2430 return NULL;
2431 }
2432 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2433 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2434 {
2435 free(aclent->acl_entry);
2436 free(aclent);
2437 return NULL;
2438 }
2439 ret = (vim_acl_T)aclent;
2440#else
2441#if defined(HAVE_AIX_ACL)
2442 int aclsize;
2443 struct acl *aclent;
2444
2445 aclsize = sizeof(struct acl);
2446 aclent = malloc(aclsize);
2447 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2448 {
2449 if (errno == ENOSPC)
2450 {
2451 aclsize = aclent->acl_len;
2452 aclent = realloc(aclent, aclsize);
2453 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2454 {
2455 free(aclent);
2456 return NULL;
2457 }
2458 }
2459 else
2460 {
2461 free(aclent);
2462 return NULL;
2463 }
2464 }
2465 ret = (vim_acl_T)aclent;
2466#endif /* HAVE_AIX_ACL */
2467#endif /* HAVE_SOLARIS_ACL */
2468#endif /* HAVE_POSIX_ACL */
2469 return ret;
2470}
2471
2472/*
2473 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2474 */
2475 void
2476mch_set_acl(fname, aclent)
2477 char_u *fname;
2478 vim_acl_T aclent;
2479{
2480 if (aclent == NULL)
2481 return;
2482#ifdef HAVE_POSIX_ACL
2483 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2484#else
2485#ifdef HAVE_SOLARIS_ACL
2486 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2487 ((vim_acl_solaris_T *)aclent)->acl_entry);
2488#else
2489#ifdef HAVE_AIX_ACL
2490 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2491#endif /* HAVE_AIX_ACL */
2492#endif /* HAVE_SOLARIS_ACL */
2493#endif /* HAVE_POSIX_ACL */
2494}
2495
2496 void
2497mch_free_acl(aclent)
2498 vim_acl_T aclent;
2499{
2500 if (aclent == NULL)
2501 return;
2502#ifdef HAVE_POSIX_ACL
2503 acl_free((acl_t)aclent);
2504#else
2505#ifdef HAVE_SOLARIS_ACL
2506 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2507 free(aclent);
2508#else
2509#ifdef HAVE_AIX_ACL
2510 free(aclent);
2511#endif /* HAVE_AIX_ACL */
2512#endif /* HAVE_SOLARIS_ACL */
2513#endif /* HAVE_POSIX_ACL */
2514}
2515#endif
2516
2517/*
2518 * Set hidden flag for "name".
2519 */
2520/* ARGSUSED */
2521 void
2522mch_hide(name)
2523 char_u *name;
2524{
2525 /* can't hide a file */
2526}
2527
2528/*
2529 * return TRUE if "name" is a directory
2530 * return FALSE if "name" is not a directory
2531 * return FALSE for error
2532 */
2533 int
2534mch_isdir(name)
2535 char_u *name;
2536{
2537 struct stat statb;
2538
2539 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2540 return FALSE;
2541 if (stat((char *)name, &statb))
2542 return FALSE;
2543#ifdef _POSIX_SOURCE
2544 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2545#else
2546 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2547#endif
2548}
2549
2550#if defined(FEAT_EVAL) || defined(PROTO)
2551
2552static int executable_file __ARGS((char_u *name));
2553
2554/*
2555 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2556 */
2557 static int
2558executable_file(name)
2559 char_u *name;
2560{
2561 struct stat st;
2562
2563 if (stat((char *)name, &st))
2564 return 0;
2565 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2566}
2567
2568/*
2569 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2570 * Return -1 if unknown.
2571 */
2572 int
2573mch_can_exe(name)
2574 char_u *name;
2575{
2576 char_u *buf;
2577 char_u *p, *e;
2578 int retval;
2579
2580 /* If it's an absolute or relative path don't need to use $PATH. */
2581 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2582 || (name[1] == '.' && name[2] == '/'))))
2583 return executable_file(name);
2584
2585 p = (char_u *)getenv("PATH");
2586 if (p == NULL || *p == NUL)
2587 return -1;
2588 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2589 if (buf == NULL)
2590 return -1;
2591
2592 /*
2593 * Walk through all entries in $PATH to check if "name" exists there and
2594 * is an executable file.
2595 */
2596 for (;;)
2597 {
2598 e = (char_u *)strchr((char *)p, ':');
2599 if (e == NULL)
2600 e = p + STRLEN(p);
2601 if (e - p <= 1) /* empty entry means current dir */
2602 STRCPY(buf, "./");
2603 else
2604 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002605 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002606 add_pathsep(buf);
2607 }
2608 STRCAT(buf, name);
2609 retval = executable_file(buf);
2610 if (retval == 1)
2611 break;
2612
2613 if (*e != ':')
2614 break;
2615 p = e + 1;
2616 }
2617
2618 vim_free(buf);
2619 return retval;
2620}
2621#endif
2622
2623/*
2624 * Check what "name" is:
2625 * NODE_NORMAL: file or directory (or doesn't exist)
2626 * NODE_WRITABLE: writable device, socket, fifo, etc.
2627 * NODE_OTHER: non-writable things
2628 */
2629 int
2630mch_nodetype(name)
2631 char_u *name;
2632{
2633 struct stat st;
2634
2635 if (stat((char *)name, &st))
2636 return NODE_NORMAL;
2637 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2638 return NODE_NORMAL;
2639#ifndef OS2
2640 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2641 return NODE_OTHER;
2642#endif
2643 /* Everything else is writable? */
2644 return NODE_WRITABLE;
2645}
2646
2647 void
2648mch_early_init()
2649{
2650#ifdef HAVE_CHECK_STACK_GROWTH
2651 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002652
Bram Moolenaar071d4272004-06-13 20:20:40 +00002653 check_stack_growth((char *)&i);
2654
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002655# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002656 get_stack_limit();
2657# endif
2658
2659#endif
2660
2661 /*
2662 * Setup an alternative stack for signals. Helps to catch signals when
2663 * running out of stack space.
2664 * Use of sigaltstack() is preferred, it's more portable.
2665 * Ignore any errors.
2666 */
2667#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2668 signal_stack = malloc(SIGSTKSZ);
2669 init_signal_stack();
2670#endif
2671}
2672
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002673#if defined(EXITFREE) || defined(PROTO)
2674 void
2675mch_free_mem()
2676{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002677# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2678 if (clip_star.owned)
2679 clip_lose_selection(&clip_star);
2680 if (clip_plus.owned)
2681 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002682# endif
2683# if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
2684 if (xterm_Shell != (Widget)0)
2685 XtDestroyWidget(xterm_Shell);
2686 if (xterm_dpy != NULL)
2687 XtCloseDisplay(xterm_dpy);
2688 if (app_context != (XtAppContext)NULL)
2689 XtDestroyApplicationContext(app_context);
2690# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002691# ifdef FEAT_X11
2692 if (x11_display != NULL && x11_display != xterm_dpy)
2693 XCloseDisplay(x11_display);
2694# endif
2695# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2696 vim_free(signal_stack);
2697 signal_stack = NULL;
2698# endif
2699# ifdef FEAT_TITLE
2700 vim_free(oldtitle);
2701 vim_free(oldicon);
2702# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002703}
2704#endif
2705
Bram Moolenaar071d4272004-06-13 20:20:40 +00002706static void exit_scroll __ARGS((void));
2707
2708/*
2709 * Output a newline when exiting.
2710 * Make sure the newline goes to the same stream as the text.
2711 */
2712 static void
2713exit_scroll()
2714{
Bram Moolenaardf177f62005-02-22 08:39:57 +00002715 if (silent_mode)
2716 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002717 if (newline_on_exit || msg_didout)
2718 {
2719 if (msg_use_printf())
2720 {
2721 if (info_message)
2722 mch_msg("\n");
2723 else
2724 mch_errmsg("\r\n");
2725 }
2726 else
2727 out_char('\n');
2728 }
2729 else
2730 {
2731 restore_cterm_colors(); /* get original colors back */
2732 msg_clr_eos_force(); /* clear the rest of the display */
2733 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
2734 }
2735}
2736
2737 void
2738mch_exit(r)
2739 int r;
2740{
2741 exiting = TRUE;
2742
2743#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
2744 x11_export_final_selection();
2745#endif
2746
2747#ifdef FEAT_GUI
2748 if (!gui.in_use)
2749#endif
2750 {
2751 settmode(TMODE_COOK);
2752#ifdef FEAT_TITLE
2753 mch_restore_title(3); /* restore xterm title and icon name */
2754#endif
2755 /*
2756 * When t_ti is not empty but it doesn't cause swapping terminal
2757 * pages, need to output a newline when msg_didout is set. But when
2758 * t_ti does swap pages it should not go to the shell page. Do this
2759 * before stoptermcap().
2760 */
2761 if (swapping_screen() && !newline_on_exit)
2762 exit_scroll();
2763
2764 /* Stop termcap: May need to check for T_CRV response, which
2765 * requires RAW mode. */
2766 stoptermcap();
2767
2768 /*
2769 * A newline is only required after a message in the alternate screen.
2770 * This is set to TRUE by wait_return().
2771 */
2772 if (!swapping_screen() || newline_on_exit)
2773 exit_scroll();
2774
2775 /* Cursor may have been switched off without calling starttermcap()
2776 * when doing "vim -u vimrc" and vimrc contains ":q". */
2777 if (full_screen)
2778 cursor_on();
2779 }
2780 out_flush();
2781 ml_close_all(TRUE); /* remove all memfiles */
2782 may_core_dump();
2783#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002784 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002785 gui_exit(r);
2786#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00002787
2788#if defined(MACOS_X) && defined(FEAT_MBYTE)
2789 mac_conv_cleanup();
2790#endif
2791
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792#ifdef __QNX__
2793 /* A core dump won't be created if the signal handler
2794 * doesn't return, so we can't call exit() */
2795 if (deadly_signal != 0)
2796 return;
2797#endif
2798
Bram Moolenaar009b2592004-10-24 19:18:58 +00002799#ifdef FEAT_NETBEANS_INTG
2800 if (usingNetbeans)
2801 netbeans_send_disconnect();
2802#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002803
2804#ifdef EXITFREE
2805 free_all_mem();
2806#endif
2807
Bram Moolenaar071d4272004-06-13 20:20:40 +00002808 exit(r);
2809}
2810
2811 static void
2812may_core_dump()
2813{
2814 if (deadly_signal != 0)
2815 {
2816 signal(deadly_signal, SIG_DFL);
2817 kill(getpid(), deadly_signal); /* Die using the signal we caught */
2818 }
2819}
2820
2821#ifndef VMS
2822
2823 void
2824mch_settmode(tmode)
2825 int tmode;
2826{
2827 static int first = TRUE;
2828
2829 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2830#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2831 /*
2832 * for "new" tty systems
2833 */
2834# ifdef HAVE_TERMIOS_H
2835 static struct termios told;
2836 struct termios tnew;
2837# else
2838 static struct termio told;
2839 struct termio tnew;
2840# endif
2841
2842 if (first)
2843 {
2844 first = FALSE;
2845# if defined(HAVE_TERMIOS_H)
2846 tcgetattr(read_cmd_fd, &told);
2847# else
2848 ioctl(read_cmd_fd, TCGETA, &told);
2849# endif
2850 }
2851
2852 tnew = told;
2853 if (tmode == TMODE_RAW)
2854 {
2855 /*
2856 * ~ICRNL enables typing ^V^M
2857 */
2858 tnew.c_iflag &= ~ICRNL;
2859 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
2860# if defined(IEXTEN) && !defined(__MINT__)
2861 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
2862 /* but it breaks function keys on MINT */
2863# endif
2864 );
2865# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
2866 tnew.c_oflag &= ~ONLCR;
2867# endif
2868 tnew.c_cc[VMIN] = 1; /* return after 1 char */
2869 tnew.c_cc[VTIME] = 0; /* don't wait */
2870 }
2871 else if (tmode == TMODE_SLEEP)
2872 tnew.c_lflag &= ~(ECHO);
2873
2874# if defined(HAVE_TERMIOS_H)
2875 {
2876 int n = 10;
2877
2878 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
2879 * few times. */
2880 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
2881 && errno == EINTR && n > 0)
2882 --n;
2883 }
2884# else
2885 ioctl(read_cmd_fd, TCSETA, &tnew);
2886# endif
2887
2888#else
2889
2890 /*
2891 * for "old" tty systems
2892 */
2893# ifndef TIOCSETN
2894# define TIOCSETN TIOCSETP /* for hpux 9.0 */
2895# endif
2896 static struct sgttyb ttybold;
2897 struct sgttyb ttybnew;
2898
2899 if (first)
2900 {
2901 first = FALSE;
2902 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
2903 }
2904
2905 ttybnew = ttybold;
2906 if (tmode == TMODE_RAW)
2907 {
2908 ttybnew.sg_flags &= ~(CRMOD | ECHO);
2909 ttybnew.sg_flags |= RAW;
2910 }
2911 else if (tmode == TMODE_SLEEP)
2912 ttybnew.sg_flags &= ~(ECHO);
2913 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
2914#endif
2915 curr_tmode = tmode;
2916}
2917
2918/*
2919 * Try to get the code for "t_kb" from the stty setting
2920 *
2921 * Even if termcap claims a backspace key, the user's setting *should*
2922 * prevail. stty knows more about reality than termcap does, and if
2923 * somebody's usual erase key is DEL (which, for most BSD users, it will
2924 * be), they're going to get really annoyed if their erase key starts
2925 * doing forward deletes for no reason. (Eric Fischer)
2926 */
2927 void
2928get_stty()
2929{
2930 char_u buf[2];
2931 char_u *p;
2932
2933 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2934#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2935 /* for "new" tty systems */
2936# ifdef HAVE_TERMIOS_H
2937 struct termios keys;
2938# else
2939 struct termio keys;
2940# endif
2941
2942# if defined(HAVE_TERMIOS_H)
2943 if (tcgetattr(read_cmd_fd, &keys) != -1)
2944# else
2945 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
2946# endif
2947 {
2948 buf[0] = keys.c_cc[VERASE];
2949 intr_char = keys.c_cc[VINTR];
2950#else
2951 /* for "old" tty systems */
2952 struct sgttyb keys;
2953
2954 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
2955 {
2956 buf[0] = keys.sg_erase;
2957 intr_char = keys.sg_kill;
2958#endif
2959 buf[1] = NUL;
2960 add_termcode((char_u *)"kb", buf, FALSE);
2961
2962 /*
2963 * If <BS> and <DEL> are now the same, redefine <DEL>.
2964 */
2965 p = find_termcode((char_u *)"kD");
2966 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
2967 do_fixdel(NULL);
2968 }
2969#if 0
2970 } /* to keep cindent happy */
2971#endif
2972}
2973
2974#endif /* VMS */
2975
2976#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2977/*
2978 * Set mouse clicks on or off.
2979 */
2980 void
2981mch_setmouse(on)
2982 int on;
2983{
2984 static int ison = FALSE;
2985 int xterm_mouse_vers;
2986
2987 if (on == ison) /* return quickly if nothing to do */
2988 return;
2989
2990 xterm_mouse_vers = use_xterm_mouse();
2991 if (xterm_mouse_vers > 0)
2992 {
2993 if (on) /* enable mouse events, use mouse tracking if available */
2994 out_str_nf((char_u *)
2995 (xterm_mouse_vers > 1
2996 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
2997 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
2998 else /* disable mouse events, could probably always send the same */
2999 out_str_nf((char_u *)
3000 (xterm_mouse_vers > 1
3001 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3002 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3003 ison = on;
3004 }
3005
3006# ifdef FEAT_MOUSE_DEC
3007 else if (ttym_flags == TTYM_DEC)
3008 {
3009 if (on) /* enable mouse events */
3010 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3011 else /* disable mouse events */
3012 out_str_nf((char_u *)"\033['z");
3013 ison = on;
3014 }
3015# endif
3016
3017# ifdef FEAT_MOUSE_GPM
3018 else
3019 {
3020 if (on)
3021 {
3022 if (gpm_open())
3023 ison = TRUE;
3024 }
3025 else
3026 {
3027 gpm_close();
3028 ison = FALSE;
3029 }
3030 }
3031# endif
3032
3033# ifdef FEAT_MOUSE_JSB
3034 else
3035 {
3036 if (on)
3037 {
3038 /* D - Enable Mouse up/down messages
3039 * L - Enable Left Button Reporting
3040 * M - Enable Middle Button Reporting
3041 * R - Enable Right Button Reporting
3042 * K - Enable SHIFT and CTRL key Reporting
3043 * + - Enable Advanced messaging of mouse moves and up/down messages
3044 * Q - Quiet No Ack
3045 * # - Numeric value of mouse pointer required
3046 * 0 = Multiview 2000 cursor, used as standard
3047 * 1 = Windows Arrow
3048 * 2 = Windows I Beam
3049 * 3 = Windows Hour Glass
3050 * 4 = Windows Cross Hair
3051 * 5 = Windows UP Arrow
3052 */
3053#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3054 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3055 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3056#else
3057 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3058 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3059#endif
3060 ison = TRUE;
3061 }
3062 else
3063 {
3064 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3065 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3066 ison = FALSE;
3067 }
3068 }
3069# endif
3070# ifdef FEAT_MOUSE_PTERM
3071 else
3072 {
3073 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3074 if (on)
3075 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3076 else
3077 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3078 ison = on;
3079 }
3080# endif
3081}
3082
3083/*
3084 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3085 */
3086 void
3087check_mouse_termcode()
3088{
3089# ifdef FEAT_MOUSE_XTERM
3090 if (use_xterm_mouse()
3091# ifdef FEAT_GUI
3092 && !gui.in_use
3093# endif
3094 )
3095 {
3096 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003097 ? IF_EB("\233M", CSI_STR "M")
3098 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003099 if (*p_mouse != NUL)
3100 {
3101 /* force mouse off and maybe on to send possibly new mouse
3102 * activation sequence to the xterm, with(out) drag tracing. */
3103 mch_setmouse(FALSE);
3104 setmouse();
3105 }
3106 }
3107 else
3108 del_mouse_termcode(KS_MOUSE);
3109# endif
3110
3111# ifdef FEAT_MOUSE_GPM
3112 if (!use_xterm_mouse()
3113# ifdef FEAT_GUI
3114 && !gui.in_use
3115# endif
3116 )
3117 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3118# endif
3119
3120# ifdef FEAT_MOUSE_JSB
3121 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3122 if (!use_xterm_mouse()
3123# ifdef FEAT_GUI
3124 && !gui.in_use
3125# endif
3126 )
3127 set_mouse_termcode(KS_JSBTERM_MOUSE,
3128 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3129 else
3130 del_mouse_termcode(KS_JSBTERM_MOUSE);
3131# endif
3132
3133# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003134 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003135 * define it in the GUI or when using an xterm. */
3136 if (!use_xterm_mouse()
3137# ifdef FEAT_GUI
3138 && !gui.in_use
3139# endif
3140 )
3141 set_mouse_termcode(KS_NETTERM_MOUSE,
3142 (char_u *)IF_EB("\033}", ESC_STR "}"));
3143 else
3144 del_mouse_termcode(KS_NETTERM_MOUSE);
3145# endif
3146
3147# ifdef FEAT_MOUSE_DEC
3148 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3149 if (!use_xterm_mouse()
3150# ifdef FEAT_GUI
3151 && !gui.in_use
3152# endif
3153 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003154 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3155 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003156 else
3157 del_mouse_termcode(KS_DEC_MOUSE);
3158# endif
3159# ifdef FEAT_MOUSE_PTERM
3160 /* same as the dec mouse */
3161 if (!use_xterm_mouse()
3162# ifdef FEAT_GUI
3163 && !gui.in_use
3164# endif
3165 )
3166 set_mouse_termcode(KS_PTERM_MOUSE,
3167 (char_u *) IF_EB("\033[", ESC_STR "["));
3168 else
3169 del_mouse_termcode(KS_PTERM_MOUSE);
3170# endif
3171}
3172#endif
3173
3174/*
3175 * set screen mode, always fails.
3176 */
3177/* ARGSUSED */
3178 int
3179mch_screenmode(arg)
3180 char_u *arg;
3181{
3182 EMSG(_(e_screenmode));
3183 return FAIL;
3184}
3185
3186#ifndef VMS
3187
3188/*
3189 * Try to get the current window size:
3190 * 1. with an ioctl(), most accurate method
3191 * 2. from the environment variables LINES and COLUMNS
3192 * 3. from the termcap
3193 * 4. keep using the old values
3194 * Return OK when size could be determined, FAIL otherwise.
3195 */
3196 int
3197mch_get_shellsize()
3198{
3199 long rows = 0;
3200 long columns = 0;
3201 char_u *p;
3202
3203 /*
3204 * For OS/2 use _scrsize().
3205 */
3206# ifdef __EMX__
3207 {
3208 int s[2];
3209
3210 _scrsize(s);
3211 columns = s[0];
3212 rows = s[1];
3213 }
3214# endif
3215
3216 /*
3217 * 1. try using an ioctl. It is the most accurate method.
3218 *
3219 * Try using TIOCGWINSZ first, some systems that have it also define
3220 * TIOCGSIZE but don't have a struct ttysize.
3221 */
3222# ifdef TIOCGWINSZ
3223 {
3224 struct winsize ws;
3225 int fd = 1;
3226
3227 /* When stdout is not a tty, use stdin for the ioctl(). */
3228 if (!isatty(fd) && isatty(read_cmd_fd))
3229 fd = read_cmd_fd;
3230 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3231 {
3232 columns = ws.ws_col;
3233 rows = ws.ws_row;
3234 }
3235 }
3236# else /* TIOCGWINSZ */
3237# ifdef TIOCGSIZE
3238 {
3239 struct ttysize ts;
3240 int fd = 1;
3241
3242 /* When stdout is not a tty, use stdin for the ioctl(). */
3243 if (!isatty(fd) && isatty(read_cmd_fd))
3244 fd = read_cmd_fd;
3245 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3246 {
3247 columns = ts.ts_cols;
3248 rows = ts.ts_lines;
3249 }
3250 }
3251# endif /* TIOCGSIZE */
3252# endif /* TIOCGWINSZ */
3253
3254 /*
3255 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003256 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3257 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003258 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003259 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260 {
3261 if ((p = (char_u *)getenv("LINES")))
3262 rows = atoi((char *)p);
3263 if ((p = (char_u *)getenv("COLUMNS")))
3264 columns = atoi((char *)p);
3265 }
3266
3267#ifdef HAVE_TGETENT
3268 /*
3269 * 3. try reading "co" and "li" entries from termcap
3270 */
3271 if (columns == 0 || rows == 0)
3272 getlinecol(&columns, &rows);
3273#endif
3274
3275 /*
3276 * 4. If everything fails, use the old values
3277 */
3278 if (columns <= 0 || rows <= 0)
3279 return FAIL;
3280
3281 Rows = rows;
3282 Columns = columns;
3283 return OK;
3284}
3285
3286/*
3287 * Try to set the window size to Rows and Columns.
3288 */
3289 void
3290mch_set_shellsize()
3291{
3292 if (*T_CWS)
3293 {
3294 /*
3295 * NOTE: if you get an error here that term_set_winsize() is
3296 * undefined, check the output of configure. It could probably not
3297 * find a ncurses, termcap or termlib library.
3298 */
3299 term_set_winsize((int)Rows, (int)Columns);
3300 out_flush();
3301 screen_start(); /* don't know where cursor is now */
3302 }
3303}
3304
3305#endif /* VMS */
3306
3307/*
3308 * Rows and/or Columns has changed.
3309 */
3310 void
3311mch_new_shellsize()
3312{
3313 /* Nothing to do. */
3314}
3315
Bram Moolenaardf177f62005-02-22 08:39:57 +00003316#ifndef USE_SYSTEM
3317static void append_ga_line __ARGS((garray_T *gap));
3318
3319/*
3320 * Append the text in "gap" below the cursor line and clear "gap".
3321 */
3322 static void
3323append_ga_line(gap)
3324 garray_T *gap;
3325{
3326 /* Remove trailing CR. */
3327 if (gap->ga_len > 0
3328 && !curbuf->b_p_bin
3329 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3330 --gap->ga_len;
3331 ga_append(gap, NUL);
3332 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3333 gap->ga_len = 0;
3334}
3335#endif
3336
Bram Moolenaar071d4272004-06-13 20:20:40 +00003337 int
3338mch_call_shell(cmd, options)
3339 char_u *cmd;
3340 int options; /* SHELL_*, see vim.h */
3341{
3342#ifdef VMS
3343 char *ifn = NULL;
3344 char *ofn = NULL;
3345#endif
3346 int tmode = cur_tmode;
3347#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3348 int x;
3349# ifndef __EMX__
3350 char_u *newcmd; /* only needed for unix */
3351# else
3352 /*
3353 * Set the preferred shell in the EMXSHELL environment variable (but
3354 * only if it is different from what is already in the environment).
3355 * Emx then takes care of whether to use "/c" or "-c" in an
3356 * intelligent way. Simply pass the whole thing to emx's system() call.
3357 * Emx also starts an interactive shell if system() is passed an empty
3358 * string.
3359 */
3360 char_u *p, *old;
3361
3362 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3363 {
3364 /* should check HAVE_SETENV, but I know we don't have it. */
3365 p = alloc(10 + strlen(p_sh));
3366 if (p)
3367 {
3368 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3369 putenv((char *)p); /* don't free the pointer! */
3370 }
3371 }
3372# endif
3373
3374 out_flush();
3375
3376 if (options & SHELL_COOKED)
3377 settmode(TMODE_COOK); /* set to normal mode */
3378
3379# ifdef __EMX__
3380 if (cmd == NULL)
3381 x = system(""); /* this starts an interactive shell in emx */
3382 else
3383 x = system((char *)cmd);
3384 /* system() returns -1 when error occurs in starting shell */
3385 if (x == -1 && !emsg_silent)
3386 {
3387 MSG_PUTS(_("\nCannot execute shell "));
3388 msg_outtrans(p_sh);
3389 msg_putchar('\n');
3390 }
3391# else /* not __EMX__ */
3392 if (cmd == NULL)
3393 x = system((char *)p_sh);
3394 else
3395 {
3396# ifdef VMS
3397 if (ofn = strchr((char *)cmd, '>'))
3398 *ofn++ = '\0';
3399 if (ifn = strchr((char *)cmd, '<'))
3400 {
3401 char *p;
3402
3403 *ifn++ = '\0';
3404 p = strchr(ifn,' '); /* chop off any trailing spaces */
3405 if (p)
3406 *p = '\0';
3407 }
3408 if (ofn)
3409 x = vms_sys((char *)cmd, ofn, ifn);
3410 else
3411 x = system((char *)cmd);
3412# else
3413 newcmd = lalloc(STRLEN(p_sh)
3414 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3415 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3416 if (newcmd == NULL)
3417 x = 0;
3418 else
3419 {
3420 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3421 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3422 (char *)p_shcf,
3423 (char *)cmd);
3424 x = system((char *)newcmd);
3425 vim_free(newcmd);
3426 }
3427# endif
3428 }
3429# ifdef VMS
3430 x = vms_sys_status(x);
3431# endif
3432 if (emsg_silent)
3433 ;
3434 else if (x == 127)
3435 MSG_PUTS(_("\nCannot execute shell sh\n"));
3436# endif /* __EMX__ */
3437 else if (x && !(options & SHELL_SILENT))
3438 {
3439 MSG_PUTS(_("\nshell returned "));
3440 msg_outnum((long)x);
3441 msg_putchar('\n');
3442 }
3443
3444 if (tmode == TMODE_RAW)
3445 settmode(TMODE_RAW); /* set to raw mode */
3446# ifdef FEAT_TITLE
3447 resettitle();
3448# endif
3449 return x;
3450
3451#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3452
Bram Moolenaardf177f62005-02-22 08:39:57 +00003453# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3454 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003455
3456 char_u *newcmd = NULL;
3457 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003458 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003459 pid_t wait_pid = 0;
3460# ifdef HAVE_UNION_WAIT
3461 union wait status;
3462# else
3463 int status = -1;
3464# endif
3465 int retval = -1;
3466 char **argv = NULL;
3467 int argc;
3468 int i;
3469 char_u *p;
3470 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003471 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003472# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003473 int pty_slave_fd = -1;
3474 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003475# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003476 int fd_toshell[2]; /* for pipes */
3477 int fd_fromshell[2];
3478 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003479# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003480 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003481# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482 static char envbuf_Rows[20];
3483 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484# endif
3485 int did_settmode = FALSE; /* TRUE when settmode(TMODE_RAW) called */
3486
3487 out_flush();
3488 if (options & SHELL_COOKED)
3489 settmode(TMODE_COOK); /* set to normal mode */
3490
3491 /*
3492 * 1: find number of arguments
3493 * 2: separate them and built argv[]
3494 */
3495 newcmd = vim_strsave(p_sh);
3496 if (newcmd == NULL) /* out of memory */
3497 goto error;
3498 for (i = 0; i < 2; ++i)
3499 {
3500 p = newcmd;
3501 inquote = FALSE;
3502 argc = 0;
3503 for (;;)
3504 {
3505 if (i == 1)
3506 argv[argc] = (char *)p;
3507 ++argc;
3508 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3509 {
3510 if (*p == '"')
3511 inquote = !inquote;
3512 ++p;
3513 }
3514 if (*p == NUL)
3515 break;
3516 if (i == 1)
3517 *p++ = NUL;
3518 p = skipwhite(p);
3519 }
3520 if (i == 0)
3521 {
3522 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3523 if (argv == NULL) /* out of memory */
3524 goto error;
3525 }
3526 }
3527 if (cmd != NULL)
3528 {
3529 if (extra_shell_arg != NULL)
3530 argv[argc++] = (char *)extra_shell_arg;
3531 argv[argc++] = (char *)p_shcf;
3532 argv[argc++] = (char *)cmd;
3533 }
3534 argv[argc] = NULL;
3535
Bram Moolenaar071d4272004-06-13 20:20:40 +00003536 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003537 * For the GUI, when writing the output into the buffer and when reading
3538 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3539 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003541 if ((options & (SHELL_READ|SHELL_WRITE))
3542# ifdef FEAT_GUI
3543 || (gui.in_use && show_shell_mess)
3544# endif
3545 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003546 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003547# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548 /*
3549 * Try to open a master pty.
3550 * If this works, open the slave pty.
3551 * If the slave can't be opened, close the master pty.
3552 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003553 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554 {
3555 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3556 if (pty_master_fd >= 0 && ((pty_slave_fd =
3557 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3558 {
3559 close(pty_master_fd);
3560 pty_master_fd = -1;
3561 }
3562 }
3563 /*
3564 * If not opening a pty or it didn't work, try using pipes.
3565 */
3566 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003567# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003568 {
3569 pipe_error = (pipe(fd_toshell) < 0);
3570 if (!pipe_error) /* pipe create OK */
3571 {
3572 pipe_error = (pipe(fd_fromshell) < 0);
3573 if (pipe_error) /* pipe create failed */
3574 {
3575 close(fd_toshell[0]);
3576 close(fd_toshell[1]);
3577 }
3578 }
3579 if (pipe_error)
3580 {
3581 MSG_PUTS(_("\nCannot create pipes\n"));
3582 out_flush();
3583 }
3584 }
3585 }
3586
3587 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003588 {
3589# ifdef __BEOS__
3590 beos_cleanup_read_thread();
3591# endif
3592 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3593 {
3594 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003595 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003596# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003597 || (gui.in_use && show_shell_mess)
3598# endif
3599 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003600 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003601# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602 if (pty_master_fd >= 0) /* close the pseudo tty */
3603 {
3604 close(pty_master_fd);
3605 close(pty_slave_fd);
3606 }
3607 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003608# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003609 {
3610 close(fd_toshell[0]);
3611 close(fd_toshell[1]);
3612 close(fd_fromshell[0]);
3613 close(fd_fromshell[1]);
3614 }
3615 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003616 }
3617 else if (pid == 0) /* child */
3618 {
3619 reset_signals(); /* handle signals normally */
3620
3621 if (!show_shell_mess || (options & SHELL_EXPAND))
3622 {
3623 int fd;
3624
3625 /*
3626 * Don't want to show any message from the shell. Can't just
3627 * close stdout and stderr though, because some systems will
3628 * break if you try to write to them after that, so we must
3629 * use dup() to replace them with something else -- webb
3630 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3631 * waiting for input.
3632 */
3633 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3634 fclose(stdin);
3635 fclose(stdout);
3636 fclose(stderr);
3637
3638 /*
3639 * If any of these open()'s and dup()'s fail, we just continue
3640 * anyway. It's not fatal, and on most systems it will make
3641 * no difference at all. On a few it will cause the execvp()
3642 * to exit with a non-zero status even when the completion
3643 * could be done, which is nothing too serious. If the open()
3644 * or dup() failed we'd just do the same thing ourselves
3645 * anyway -- webb
3646 */
3647 if (fd >= 0)
3648 {
3649 dup(fd); /* To replace stdin (file descriptor 0) */
3650 dup(fd); /* To replace stdout (file descriptor 1) */
3651 dup(fd); /* To replace stderr (file descriptor 2) */
3652
3653 /* Don't need this now that we've duplicated it */
3654 close(fd);
3655 }
3656 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003657 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003658# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003659 || gui.in_use
3660# endif
3661 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003662 {
3663
Bram Moolenaardf177f62005-02-22 08:39:57 +00003664# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665 (void)setsid();
Bram Moolenaardf177f62005-02-22 08:39:57 +00003666# endif
3667# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003668 /* push stream discipline modules */
3669 if (options & SHELL_COOKED)
3670 SetupSlavePTY(pty_slave_fd);
3671# ifdef TIOCSCTTY
3672 /* try to become controlling tty (probably doesn't work,
3673 * unless run by root) */
3674 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
3675# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003676# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003677 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003678# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003679 setenv("TERM", "dumb", 1);
3680 sprintf((char *)envbuf, "%ld", Rows);
3681 setenv("ROWS", (char *)envbuf, 1);
3682 sprintf((char *)envbuf, "%ld", Rows);
3683 setenv("LINES", (char *)envbuf, 1);
3684 sprintf((char *)envbuf, "%ld", Columns);
3685 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003686# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003687 /*
3688 * Putenv does not copy the string, it has to remain valid.
3689 * Use a static array to avoid loosing allocated memory.
3690 */
3691 putenv("TERM=dumb");
3692 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
3693 putenv(envbuf_Rows);
3694 sprintf(envbuf_Rows, "LINES=%ld", Rows);
3695 putenv(envbuf_Rows);
3696 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
3697 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003698# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003699
Bram Moolenaara5792f52005-11-23 21:25:05 +00003700 /*
3701 * stderr is only redirected when using the GUI, so that a
3702 * program like gpg can still access the terminal to get a
3703 * passphrase using stderr.
3704 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003705# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003706 if (pty_master_fd >= 0)
3707 {
3708 close(pty_master_fd); /* close master side of pty */
3709
3710 /* set up stdin/stdout/stderr for the child */
3711 close(0);
3712 dup(pty_slave_fd);
3713 close(1);
3714 dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003715 if (gui.in_use)
3716 {
3717 close(2);
3718 dup(pty_slave_fd);
3719 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003720
3721 close(pty_slave_fd); /* has been dupped, close it now */
3722 }
3723 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003724# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003725 {
3726 /* set up stdin for the child */
3727 close(fd_toshell[1]);
3728 close(0);
3729 dup(fd_toshell[0]);
3730 close(fd_toshell[0]);
3731
3732 /* set up stdout for the child */
3733 close(fd_fromshell[0]);
3734 close(1);
3735 dup(fd_fromshell[1]);
3736 close(fd_fromshell[1]);
3737
Bram Moolenaara5792f52005-11-23 21:25:05 +00003738# ifdef FEAT_GUI
3739 if (gui.in_use)
3740 {
3741 /* set up stderr for the child */
3742 close(2);
3743 dup(1);
3744 }
3745# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746 }
3747 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003748
Bram Moolenaar071d4272004-06-13 20:20:40 +00003749 /*
3750 * There is no type cast for the argv, because the type may be
3751 * different on different machines. This may cause a warning
3752 * message with strict compilers, don't worry about it.
3753 * Call _exit() instead of exit() to avoid closing the connection
3754 * to the X server (esp. with GTK, which uses atexit()).
3755 */
3756 execvp(argv[0], argv);
3757 _exit(EXEC_FAILED); /* exec failed, return failure code */
3758 }
3759 else /* parent */
3760 {
3761 /*
3762 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003763 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003764 */
3765 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003766 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003767
3768 /*
3769 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003770 * This is also used to pipe stdin/stdout to/from the external
3771 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003772 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003773 if ((options & (SHELL_READ|SHELL_WRITE))
3774# ifdef FEAT_GUI
3775 || (gui.in_use && show_shell_mess)
3776# endif
3777 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003778 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003779# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003780 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003781# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003782 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003783# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003784 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
3785 int ta_len = 0; /* valid bytes in ta_buf[] */
3786 int len;
3787 int p_more_save;
3788 int old_State;
3789 int c;
3790 int toshell_fd;
3791 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003792 garray_T ga;
3793 int noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794
Bram Moolenaardf177f62005-02-22 08:39:57 +00003795# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003796 if (pty_master_fd >= 0)
3797 {
3798 close(pty_slave_fd); /* close slave side of pty */
3799 fromshell_fd = pty_master_fd;
3800 toshell_fd = dup(pty_master_fd);
3801 }
3802 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003803# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003804 {
3805 close(fd_toshell[0]);
3806 close(fd_fromshell[1]);
3807 toshell_fd = fd_toshell[1];
3808 fromshell_fd = fd_fromshell[0];
3809 }
3810
3811 /*
3812 * Write to the child if there are typed characters.
3813 * Read from the child if there are characters available.
3814 * Repeat the reading a few times if more characters are
3815 * available. Need to check for typed keys now and then, but
3816 * not too often (delays when no chars are available).
3817 * This loop is quit if no characters can be read from the pty
3818 * (WaitForChar detected special condition), or there are no
3819 * characters available and the child has exited.
3820 * Only check if the child has exited when there is no more
3821 * output. The child may exit before all the output has
3822 * been printed.
3823 *
3824 * Currently this busy loops!
3825 * This can probably dead-lock when the write blocks!
3826 */
3827 p_more_save = p_more;
3828 p_more = FALSE;
3829 old_State = State;
3830 State = EXTERNCMD; /* don't redraw at window resize */
3831
Bram Moolenaardf177f62005-02-22 08:39:57 +00003832 if (options & SHELL_WRITE && toshell_fd >= 0)
3833 {
3834 /* Fork a process that will write the lines to the
3835 * external program. */
3836 if ((wpid = fork()) == -1)
3837 {
3838 MSG_PUTS(_("\nCannot fork\n"));
3839 }
3840 else if (wpid == 0)
3841 {
3842 linenr_T lnum = curbuf->b_op_start.lnum;
3843 int written = 0;
3844 char_u *p = ml_get(lnum);
3845 char_u *s;
3846 size_t l;
3847
3848 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00003849 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003850 for (;;)
3851 {
3852 l = STRLEN(p + written);
3853 if (l == 0)
3854 len = 0;
3855 else if (p[written] == NL)
3856 /* NL -> NUL translation */
3857 len = write(toshell_fd, "", (size_t)1);
3858 else
3859 {
3860 s = vim_strchr(p + written, NL);
3861 len = write(toshell_fd, (char *)p + written,
3862 s == NULL ? l : s - (p + written));
3863 }
3864 if (len == l)
3865 {
3866 /* Finished a line, add a NL, unless this line
3867 * should not have one. */
3868 if (lnum != curbuf->b_op_end.lnum
3869 || !curbuf->b_p_bin
3870 || (lnum != write_no_eol_lnum
3871 && (lnum !=
3872 curbuf->b_ml.ml_line_count
3873 || curbuf->b_p_eol)))
3874 write(toshell_fd, "\n", (size_t)1);
3875 ++lnum;
3876 if (lnum > curbuf->b_op_end.lnum)
3877 {
3878 /* finished all the lines, close pipe */
3879 close(toshell_fd);
3880 toshell_fd = -1;
3881 break;
3882 }
3883 p = ml_get(lnum);
3884 written = 0;
3885 }
3886 else if (len > 0)
3887 written += len;
3888 }
3889 _exit(0);
3890 }
3891 else
3892 {
3893 close(toshell_fd);
3894 toshell_fd = -1;
3895 }
3896 }
3897
3898 if (options & SHELL_READ)
3899 ga_init2(&ga, 1, BUFLEN);
3900
3901 noread_cnt = 0;
3902
Bram Moolenaar071d4272004-06-13 20:20:40 +00003903 for (;;)
3904 {
3905 /*
3906 * Check if keys have been typed, write them to the child
3907 * if there are any. Don't do this if we are expanding
3908 * wild cards (would eat typeahead). Don't get extra
3909 * characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003910 * Don't read characters unless we didn't get output for a
3911 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003912 */
3913 len = 0;
3914 if (!(options & SHELL_EXPAND)
3915 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00003916 || (noread_cnt > 4
3917 && (len = ui_inchar(ta_buf,
3918 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003919 {
3920 /*
3921 * For pipes:
3922 * Check for CTRL-C: send interrupt signal to child.
3923 * Check for CTRL-D: EOF, close pipe to child.
3924 */
3925 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
3926 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003927# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003928 /*
3929 * Send SIGINT to the child's group or all
3930 * processes in our group.
3931 */
3932 if (ta_buf[ta_len] == Ctrl_C
3933 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003934 {
3935# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00003936 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003937# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003938 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003939# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003940 if (wpid > 0)
3941 kill(wpid, SIGINT);
3942 }
3943# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003944 if (pty_master_fd < 0 && toshell_fd >= 0
3945 && ta_buf[ta_len] == Ctrl_D)
3946 {
3947 close(toshell_fd);
3948 toshell_fd = -1;
3949 }
3950 }
3951
3952 /* replace K_BS by <BS> and K_DEL by <DEL> */
3953 for (i = ta_len; i < ta_len + len; ++i)
3954 {
3955 if (ta_buf[i] == CSI && len - i > 2)
3956 {
3957 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
3958 if (c == K_DEL || c == K_KDEL || c == K_BS)
3959 {
3960 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
3961 (size_t)(len - i - 2));
3962 if (c == K_DEL || c == K_KDEL)
3963 ta_buf[i] = DEL;
3964 else
3965 ta_buf[i] = Ctrl_H;
3966 len -= 2;
3967 }
3968 }
3969 else if (ta_buf[i] == '\r')
3970 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00003971# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003972 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003973 i += (*mb_ptr2len)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003974# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003975 }
3976
3977 /*
3978 * For pipes: echo the typed characters.
3979 * For a pty this does not seem to work.
3980 */
3981 if (pty_master_fd < 0)
3982 {
3983 for (i = ta_len; i < ta_len + len; ++i)
3984 {
3985 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
3986 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003987# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003988 else if (has_mbyte)
3989 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003990 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003991
3992 msg_outtrans_len(ta_buf + i, l);
3993 i += l - 1;
3994 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003995# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003996 else
3997 msg_outtrans_len(ta_buf + i, 1);
3998 }
3999 windgoto(msg_row, msg_col);
4000 out_flush();
4001 }
4002
4003 ta_len += len;
4004
4005 /*
4006 * Write the characters to the child, unless EOF has
4007 * been typed for pipes. Write one character at a
4008 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004009 * When writing buffer lines, drop the typed
4010 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004011 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004012 if (options & SHELL_WRITE)
4013 ta_len = 0;
4014 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004015 {
4016 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4017 if (len > 0)
4018 {
4019 ta_len -= len;
4020 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004021 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004022 }
4023 }
4024 }
4025
Bram Moolenaardf177f62005-02-22 08:39:57 +00004026 if (got_int)
4027 {
4028 /* CTRL-C sends a signal to the child, we ignore it
4029 * ourselves */
4030# ifdef HAVE_SETSID
4031 kill(-pid, SIGINT);
4032# else
4033 kill(0, SIGINT);
4034# endif
4035 if (wpid > 0)
4036 kill(wpid, SIGINT);
4037 got_int = FALSE;
4038 }
4039
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040 /*
4041 * Check if the child has any characters to be printed.
4042 * Read them and write them to our window. Repeat this as
4043 * long as there is something to do, avoid the 10ms wait
4044 * for mch_inchar(), or sending typeahead characters to
4045 * the external process.
4046 * TODO: This should handle escape sequences, compatible
4047 * to some terminal (vt52?).
4048 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004049 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004050 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4051 {
4052 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004053# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004055# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004056 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004057# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004058 );
4059 if (len <= 0) /* end of file or error */
4060 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004061
4062 noread_cnt = 0;
4063 if (options & SHELL_READ)
4064 {
4065 /* Do NUL -> NL translation, append NL separated
4066 * lines to the current buffer. */
4067 for (i = 0; i < len; ++i)
4068 {
4069 if (buffer[i] == NL)
4070 append_ga_line(&ga);
4071 else if (buffer[i] == NUL)
4072 ga_append(&ga, NL);
4073 else
4074 ga_append(&ga, buffer[i]);
4075 }
4076 }
4077# ifdef FEAT_MBYTE
4078 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004079 {
4080 int l;
4081
Bram Moolenaardf177f62005-02-22 08:39:57 +00004082 len += buffer_off;
4083 buffer[len] = NUL;
4084
Bram Moolenaar071d4272004-06-13 20:20:40 +00004085 /* Check if the last character in buffer[] is
4086 * incomplete, keep these bytes for the next
4087 * round. */
4088 for (p = buffer; p < buffer + len; p += l)
4089 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004090 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004091 if (l == 0)
4092 l = 1; /* NUL byte? */
4093 else if (MB_BYTE2LEN(*p) != l)
4094 break;
4095 }
4096 if (p == buffer) /* no complete character */
4097 {
4098 /* avoid getting stuck at an illegal byte */
4099 if (len >= 12)
4100 ++p;
4101 else
4102 {
4103 buffer_off = len;
4104 continue;
4105 }
4106 }
4107 c = *p;
4108 *p = NUL;
4109 msg_puts(buffer);
4110 if (p < buffer + len)
4111 {
4112 *p = c;
4113 buffer_off = (buffer + len) - p;
4114 mch_memmove(buffer, p, buffer_off);
4115 continue;
4116 }
4117 buffer_off = 0;
4118 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004119# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004120 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004121 {
4122 buffer[len] = NUL;
4123 msg_puts(buffer);
4124 }
4125
4126 windgoto(msg_row, msg_col);
4127 cursor_on();
4128 out_flush();
4129 if (got_int)
4130 break;
4131 }
4132
4133 /*
4134 * Check if the child still exists, before checking for
4135 * typed characters (otherwise we would loose typeahead).
4136 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004137# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004138 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004139# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004141# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004142 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4143 || (wait_pid == pid && WIFEXITED(status)))
4144 {
4145 wait_pid = pid;
4146 break;
4147 }
4148 wait_pid = 0;
4149 }
4150finished:
4151 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004152 if (options & SHELL_READ)
4153 {
4154 if (ga.ga_len > 0)
4155 {
4156 append_ga_line(&ga);
4157 /* remember that the NL was missing */
4158 write_no_eol_lnum = curwin->w_cursor.lnum;
4159 }
4160 else
4161 write_no_eol_lnum = 0;
4162 ga_clear(&ga);
4163 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004164
Bram Moolenaar071d4272004-06-13 20:20:40 +00004165 /*
4166 * Give all typeahead that wasn't used back to ui_inchar().
4167 */
4168 if (ta_len)
4169 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004170 State = old_State;
4171 if (toshell_fd >= 0)
4172 close(toshell_fd);
4173 close(fromshell_fd);
4174 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175
4176 /*
4177 * Wait until our child has exited.
4178 * Ignore wait() returning pids of other children and returning
4179 * because of some signal like SIGWINCH.
4180 * Don't wait if wait_pid was already set above, indicating the
4181 * child already exited.
4182 */
4183 while (wait_pid != pid)
4184 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004185# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004186 /* Ugly hack: when compiled with Python threads are probably
4187 * used, in which case wait() sometimes hangs for no obvious
4188 * reason. Use waitpid() instead and loop (like the GUI). */
4189# ifdef __NeXT__
4190 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4191# else
4192 wait_pid = waitpid(pid, &status, WNOHANG);
4193# endif
4194 if (wait_pid == 0)
4195 {
4196 /* Wait for 1/100 sec before trying again. */
4197 mch_delay(10L, TRUE);
4198 continue;
4199 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004200# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004201 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004202# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004203 if (wait_pid <= 0
4204# ifdef ECHILD
4205 && errno == ECHILD
4206# endif
4207 )
4208 break;
4209 }
4210
Bram Moolenaardf177f62005-02-22 08:39:57 +00004211 /* Make sure the child that writes to the external program is
4212 * dead. */
4213 if (wpid > 0)
4214 kill(wpid, SIGKILL);
4215
Bram Moolenaar071d4272004-06-13 20:20:40 +00004216 /*
4217 * Set to raw mode right now, otherwise a CTRL-C after
4218 * catch_signals() will kill Vim.
4219 */
4220 if (tmode == TMODE_RAW)
4221 settmode(TMODE_RAW);
4222 did_settmode = TRUE;
4223 set_signals();
4224
4225 if (WIFEXITED(status))
4226 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004227 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004228 retval = WEXITSTATUS(status);
4229 if (retval && !emsg_silent)
4230 {
4231 if (retval == EXEC_FAILED)
4232 {
4233 MSG_PUTS(_("\nCannot execute shell "));
4234 msg_outtrans(p_sh);
4235 msg_putchar('\n');
4236 }
4237 else if (!(options & SHELL_SILENT))
4238 {
4239 MSG_PUTS(_("\nshell returned "));
4240 msg_outnum((long)retval);
4241 msg_putchar('\n');
4242 }
4243 }
4244 }
4245 else
4246 MSG_PUTS(_("\nCommand terminated\n"));
4247 }
4248 }
4249 vim_free(argv);
4250
4251error:
4252 if (!did_settmode)
4253 if (tmode == TMODE_RAW)
4254 settmode(TMODE_RAW); /* set to raw mode */
4255# ifdef FEAT_TITLE
4256 resettitle();
4257# endif
4258 vim_free(newcmd);
4259
4260 return retval;
4261
4262#endif /* USE_SYSTEM */
4263}
4264
4265/*
4266 * Check for CTRL-C typed by reading all available characters.
4267 * In cooked mode we should get SIGINT, no need to check.
4268 */
4269 void
4270mch_breakcheck()
4271{
4272 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4273 fill_input_buf(FALSE);
4274}
4275
4276/*
4277 * Wait "msec" msec until a character is available from the keyboard or from
4278 * inbuf[]. msec == -1 will block forever.
4279 * When a GUI is being used, this will never get called -- webb
4280 */
4281 static int
4282WaitForChar(msec)
4283 long msec;
4284{
4285#ifdef FEAT_MOUSE_GPM
4286 int gpm_process_wanted;
4287#endif
4288#ifdef FEAT_XCLIPBOARD
4289 int rest;
4290#endif
4291 int avail;
4292
4293 if (input_available()) /* something in inbuf[] */
4294 return 1;
4295
4296#if defined(FEAT_MOUSE_DEC)
4297 /* May need to query the mouse position. */
4298 if (WantQueryMouse)
4299 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004300 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004301 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4302 }
4303#endif
4304
4305 /*
4306 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4307 * events. This is a bit complicated, because they might both be defined.
4308 */
4309#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4310# ifdef FEAT_XCLIPBOARD
4311 rest = 0;
4312 if (do_xterm_trace())
4313 rest = msec;
4314# endif
4315 do
4316 {
4317# ifdef FEAT_XCLIPBOARD
4318 if (rest != 0)
4319 {
4320 msec = XT_TRACE_DELAY;
4321 if (rest >= 0 && rest < XT_TRACE_DELAY)
4322 msec = rest;
4323 if (rest >= 0)
4324 rest -= msec;
4325 }
4326# endif
4327# ifdef FEAT_MOUSE_GPM
4328 gpm_process_wanted = 0;
4329 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4330# else
4331 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4332# endif
4333 if (!avail)
4334 {
4335 if (input_available())
4336 return 1;
4337# ifdef FEAT_XCLIPBOARD
4338 if (rest == 0 || !do_xterm_trace())
4339# endif
4340 break;
4341 }
4342 }
4343 while (FALSE
4344# ifdef FEAT_MOUSE_GPM
4345 || (gpm_process_wanted && mch_gpm_process() == 0)
4346# endif
4347# ifdef FEAT_XCLIPBOARD
4348 || (!avail && rest != 0)
4349# endif
4350 );
4351
4352#else
4353 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4354#endif
4355 return avail;
4356}
4357
4358/*
4359 * Wait "msec" msec until a character is available from file descriptor "fd".
4360 * Time == -1 will block forever.
4361 * When a GUI is being used, this will not be used for input -- webb
4362 * Returns also, when a request from Sniff is waiting -- toni.
4363 * Or when a Linux GPM mouse event is waiting.
4364 */
4365/* ARGSUSED */
4366#if defined(__BEOS__)
4367 int
4368#else
4369 static int
4370#endif
4371RealWaitForChar(fd, msec, check_for_gpm)
4372 int fd;
4373 long msec;
4374 int *check_for_gpm;
4375{
4376 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004377#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004378 static int busy = FALSE;
4379
4380 /* May retry getting characters after an event was handled. */
4381# define MAY_LOOP
4382
4383# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4384 /* Remember at what time we started, so that we know how much longer we
4385 * should wait after being interrupted. */
4386# define USE_START_TV
4387 struct timeval start_tv;
4388
4389 if (msec > 0 && (
4390# ifdef FEAT_XCLIPBOARD
4391 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004392# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004393 ||
4394# endif
4395# endif
4396# ifdef USE_XSMP
4397 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004398# ifdef FEAT_MZSCHEME
4399 ||
4400# endif
4401# endif
4402# ifdef FEAT_MZSCHEME
4403 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004404# endif
4405 ))
4406 gettimeofday(&start_tv, NULL);
4407# endif
4408
4409 /* Handle being called recursively. This may happen for the session
4410 * manager stuff, it may save the file, which does a breakcheck. */
4411 if (busy)
4412 return 0;
4413#endif
4414
4415#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00004416 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004417#endif
4418 {
4419#ifdef MAY_LOOP
4420 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004421# ifdef FEAT_MZSCHEME
4422 int mzquantum_used = FALSE;
4423# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424#endif
4425#ifndef HAVE_SELECT
4426 struct pollfd fds[5];
4427 int nfd;
4428# ifdef FEAT_XCLIPBOARD
4429 int xterm_idx = -1;
4430# endif
4431# ifdef FEAT_MOUSE_GPM
4432 int gpm_idx = -1;
4433# endif
4434# ifdef USE_XSMP
4435 int xsmp_idx = -1;
4436# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004437 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004438
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004439# ifdef FEAT_MZSCHEME
4440 mzvim_check_threads();
4441 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4442 {
4443 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4444 mzquantum_used = TRUE;
4445 }
4446# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004447 fds[0].fd = fd;
4448 fds[0].events = POLLIN;
4449 nfd = 1;
4450
4451# ifdef FEAT_SNIFF
4452# define SNIFF_IDX 1
4453 if (want_sniff_request)
4454 {
4455 fds[SNIFF_IDX].fd = fd_from_sniff;
4456 fds[SNIFF_IDX].events = POLLIN;
4457 nfd++;
4458 }
4459# endif
4460# ifdef FEAT_XCLIPBOARD
4461 if (xterm_Shell != (Widget)0)
4462 {
4463 xterm_idx = nfd;
4464 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4465 fds[nfd].events = POLLIN;
4466 nfd++;
4467 }
4468# endif
4469# ifdef FEAT_MOUSE_GPM
4470 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4471 {
4472 gpm_idx = nfd;
4473 fds[nfd].fd = gpm_fd;
4474 fds[nfd].events = POLLIN;
4475 nfd++;
4476 }
4477# endif
4478# ifdef USE_XSMP
4479 if (xsmp_icefd != -1)
4480 {
4481 xsmp_idx = nfd;
4482 fds[nfd].fd = xsmp_icefd;
4483 fds[nfd].events = POLLIN;
4484 nfd++;
4485 }
4486# endif
4487
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004488 ret = poll(fds, nfd, towait);
4489# ifdef FEAT_MZSCHEME
4490 if (ret == 0 && mzquantum_used)
4491 /* MzThreads scheduling is required and timeout occured */
4492 finished = FALSE;
4493# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004494
4495# ifdef FEAT_SNIFF
4496 if (ret < 0)
4497 sniff_disconnect(1);
4498 else if (want_sniff_request)
4499 {
4500 if (fds[SNIFF_IDX].revents & POLLHUP)
4501 sniff_disconnect(1);
4502 if (fds[SNIFF_IDX].revents & POLLIN)
4503 sniff_request_waiting = 1;
4504 }
4505# endif
4506# ifdef FEAT_XCLIPBOARD
4507 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4508 {
4509 xterm_update(); /* Maybe we should hand out clipboard */
4510 if (--ret == 0 && !input_available())
4511 /* Try again */
4512 finished = FALSE;
4513 }
4514# endif
4515# ifdef FEAT_MOUSE_GPM
4516 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4517 {
4518 *check_for_gpm = 1;
4519 }
4520# endif
4521# ifdef USE_XSMP
4522 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4523 {
4524 if (fds[xsmp_idx].revents & POLLIN)
4525 {
4526 busy = TRUE;
4527 xsmp_handle_requests();
4528 busy = FALSE;
4529 }
4530 else if (fds[xsmp_idx].revents & POLLHUP)
4531 {
4532 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004533 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 xsmp_close();
4535 }
4536 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004537 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004538 }
4539# endif
4540
4541
4542#else /* HAVE_SELECT */
4543
4544 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004545 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004546 fd_set rfds, efds;
4547 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004548 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004550# ifdef FEAT_MZSCHEME
4551 mzvim_check_threads();
4552 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4553 {
4554 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4555 mzquantum_used = TRUE;
4556 }
4557# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558# ifdef __EMX__
4559 /* don't check for incoming chars if not in raw mode, because select()
4560 * always returns TRUE then (in some version of emx.dll) */
4561 if (curr_tmode != TMODE_RAW)
4562 return 0;
4563# endif
4564
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004565 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004566 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004567 tv.tv_sec = towait / 1000;
4568 tv.tv_usec = (towait % 1000) * (1000000/1000);
4569 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004570 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004571 else
4572 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004573
4574 /*
4575 * Select on ready for reading and exceptional condition (end of file).
4576 */
4577 FD_ZERO(&rfds); /* calls bzero() on a sun */
4578 FD_ZERO(&efds);
4579 FD_SET(fd, &rfds);
4580# if !defined(__QNX__) && !defined(__CYGWIN32__)
4581 /* For QNX select() always returns 1 if this is set. Why? */
4582 FD_SET(fd, &efds);
4583# endif
4584 maxfd = fd;
4585
4586# ifdef FEAT_SNIFF
4587 if (want_sniff_request)
4588 {
4589 FD_SET(fd_from_sniff, &rfds);
4590 FD_SET(fd_from_sniff, &efds);
4591 if (maxfd < fd_from_sniff)
4592 maxfd = fd_from_sniff;
4593 }
4594# endif
4595# ifdef FEAT_XCLIPBOARD
4596 if (xterm_Shell != (Widget)0)
4597 {
4598 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4599 if (maxfd < ConnectionNumber(xterm_dpy))
4600 maxfd = ConnectionNumber(xterm_dpy);
4601 }
4602# endif
4603# ifdef FEAT_MOUSE_GPM
4604 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4605 {
4606 FD_SET(gpm_fd, &rfds);
4607 FD_SET(gpm_fd, &efds);
4608 if (maxfd < gpm_fd)
4609 maxfd = gpm_fd;
4610 }
4611# endif
4612# ifdef USE_XSMP
4613 if (xsmp_icefd != -1)
4614 {
4615 FD_SET(xsmp_icefd, &rfds);
4616 FD_SET(xsmp_icefd, &efds);
4617 if (maxfd < xsmp_icefd)
4618 maxfd = xsmp_icefd;
4619 }
4620# endif
4621
4622# ifdef OLD_VMS
4623 /* Old VMS as v6.2 and older have broken select(). It waits more than
4624 * required. Should not be used */
4625 ret = 0;
4626# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004627 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4628# endif
4629# ifdef FEAT_MZSCHEME
4630 if (ret == 0 && mzquantum_used)
4631 /* loop if MzThreads must be scheduled and timeout occured */
4632 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004633# endif
4634
4635# ifdef FEAT_SNIFF
4636 if (ret < 0 )
4637 sniff_disconnect(1);
4638 else if (ret > 0 && want_sniff_request)
4639 {
4640 if (FD_ISSET(fd_from_sniff, &efds))
4641 sniff_disconnect(1);
4642 if (FD_ISSET(fd_from_sniff, &rfds))
4643 sniff_request_waiting = 1;
4644 }
4645# endif
4646# ifdef FEAT_XCLIPBOARD
4647 if (ret > 0 && xterm_Shell != (Widget)0
4648 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4649 {
4650 xterm_update(); /* Maybe we should hand out clipboard */
4651 /* continue looping when we only got the X event and the input
4652 * buffer is empty */
4653 if (--ret == 0 && !input_available())
4654 {
4655 /* Try again */
4656 finished = FALSE;
4657 }
4658 }
4659# endif
4660# ifdef FEAT_MOUSE_GPM
4661 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4662 {
4663 if (FD_ISSET(gpm_fd, &efds))
4664 gpm_close();
4665 else if (FD_ISSET(gpm_fd, &rfds))
4666 *check_for_gpm = 1;
4667 }
4668# endif
4669# ifdef USE_XSMP
4670 if (ret > 0 && xsmp_icefd != -1)
4671 {
4672 if (FD_ISSET(xsmp_icefd, &efds))
4673 {
4674 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004675 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004676 xsmp_close();
4677 if (--ret == 0)
4678 finished = FALSE; /* keep going if event was only one */
4679 }
4680 else if (FD_ISSET(xsmp_icefd, &rfds))
4681 {
4682 busy = TRUE;
4683 xsmp_handle_requests();
4684 busy = FALSE;
4685 if (--ret == 0)
4686 finished = FALSE; /* keep going if event was only one */
4687 }
4688 }
4689# endif
4690
4691#endif /* HAVE_SELECT */
4692
4693#ifdef MAY_LOOP
4694 if (finished || msec == 0)
4695 break;
4696
4697 /* We're going to loop around again, find out for how long */
4698 if (msec > 0)
4699 {
4700# ifdef USE_START_TV
4701 struct timeval mtv;
4702
4703 /* Compute remaining wait time. */
4704 gettimeofday(&mtv, NULL);
4705 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
4706 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
4707# else
4708 /* Guess we got interrupted halfway. */
4709 msec = msec / 2;
4710# endif
4711 if (msec <= 0)
4712 break; /* waited long enough */
4713 }
4714#endif
4715 }
4716
4717 return (ret > 0);
4718}
4719
4720#ifndef VMS
4721
4722#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004723/*
Bram Moolenaar02743632005-07-25 20:42:36 +00004724 * Expand a path into all matching files and/or directories. Handles "*",
4725 * "?", "[a-z]", "**", etc.
4726 * "path" has backslashes before chars that are not to be expanded.
4727 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004728 */
4729 int
4730mch_expandpath(gap, path, flags)
4731 garray_T *gap;
4732 char_u *path;
4733 int flags; /* EW_* flags */
4734{
Bram Moolenaar02743632005-07-25 20:42:36 +00004735 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004736}
4737#endif
4738
4739/*
4740 * mch_expand_wildcards() - this code does wild-card pattern matching using
4741 * the shell
4742 *
4743 * return OK for success, FAIL for error (you may lose some memory) and put
4744 * an error message in *file.
4745 *
4746 * num_pat is number of input patterns
4747 * pat is array of pointers to input patterns
4748 * num_file is pointer to number of matched file names
4749 * file is pointer to array of pointers to matched file names
4750 */
4751
4752#ifndef SEEK_SET
4753# define SEEK_SET 0
4754#endif
4755#ifndef SEEK_END
4756# define SEEK_END 2
4757#endif
4758
4759/* ARGSUSED */
4760 int
4761mch_expand_wildcards(num_pat, pat, num_file, file, flags)
4762 int num_pat;
4763 char_u **pat;
4764 int *num_file;
4765 char_u ***file;
4766 int flags; /* EW_* flags */
4767{
4768 int i;
4769 size_t len;
4770 char_u *p;
4771 int dir;
4772#ifdef __EMX__
4773# define EXPL_ALLOC_INC 16
4774 char_u **expl_files;
4775 size_t files_alloced, files_free;
4776 char_u *buf;
4777 int has_wildcard;
4778
4779 *num_file = 0; /* default: no files found */
4780 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
4781 files_free = EXPL_ALLOC_INC; /* how much space is not used */
4782 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
4783 if (*file == NULL)
4784 return FAIL;
4785
4786 for (; num_pat > 0; num_pat--, pat++)
4787 {
4788 expl_files = NULL;
4789 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
4790 /* expand environment var or home dir */
4791 buf = expand_env_save(*pat);
4792 else
4793 buf = vim_strsave(*pat);
4794 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00004795 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004796 if (has_wildcard) /* yes, so expand them */
4797 expl_files = (char_u **)_fnexplode(buf);
4798
4799 /*
4800 * return value of buf if no wildcards left,
4801 * OR if no match AND EW_NOTFOUND is set.
4802 */
4803 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
4804 || (expl_files == NULL && (flags & EW_NOTFOUND)))
4805 { /* simply save the current contents of *buf */
4806 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
4807 if (expl_files != NULL)
4808 {
4809 expl_files[0] = vim_strsave(buf);
4810 expl_files[1] = NULL;
4811 }
4812 }
4813 vim_free(buf);
4814
4815 /*
4816 * Count number of names resulting from expansion,
4817 * At the same time add a backslash to the end of names that happen to
4818 * be directories, and replace slashes with backslashes.
4819 */
4820 if (expl_files)
4821 {
4822 for (i = 0; (p = expl_files[i]) != NULL; i++)
4823 {
4824 dir = mch_isdir(p);
4825 /* If we don't want dirs and this is one, skip it */
4826 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
4827 continue;
4828
4829 if (--files_free == 0)
4830 {
4831 /* need more room in table of pointers */
4832 files_alloced += EXPL_ALLOC_INC;
4833 *file = (char_u **)vim_realloc(*file,
4834 sizeof(char_u **) * files_alloced);
4835 if (*file == NULL)
4836 {
4837 EMSG(_(e_outofmem));
4838 *num_file = 0;
4839 return FAIL;
4840 }
4841 files_free = EXPL_ALLOC_INC;
4842 }
4843 slash_adjust(p);
4844 if (dir)
4845 {
4846 /* For a directory we add a '/', unless it's already
4847 * there. */
4848 len = STRLEN(p);
4849 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
4850 {
4851 STRCPY((*file)[*num_file], p);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004852 if (!after_pathsep((*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004853 {
4854 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004855 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004856 }
4857 }
4858 }
4859 else
4860 {
4861 (*file)[*num_file] = vim_strsave(p);
4862 }
4863
4864 /*
4865 * Error message already given by either alloc or vim_strsave.
4866 * Should return FAIL, but returning OK works also.
4867 */
4868 if ((*file)[*num_file] == NULL)
4869 break;
4870 (*num_file)++;
4871 }
4872 _fnexplodefree((char **)expl_files);
4873 }
4874 }
4875 return OK;
4876
4877#else /* __EMX__ */
4878
4879 int j;
4880 char_u *tempname;
4881 char_u *command;
4882 FILE *fd;
4883 char_u *buffer;
4884#define STYLE_ECHO 0 /* use "echo" to expand */
4885#define STYLE_GLOB 1 /* use "glob" to expand, for csh */
4886#define STYLE_PRINT 2 /* use "print -N" to expand, for zsh */
4887#define STYLE_BT 3 /* `cmd` expansion, execute the pattern directly */
4888 int shell_style = STYLE_ECHO;
4889 int check_spaces;
4890 static int did_find_nul = FALSE;
4891 int ampersent = FALSE;
4892
4893 *num_file = 0; /* default: no files found */
4894 *file = NULL;
4895
4896 /*
4897 * If there are no wildcards, just copy the names to allocated memory.
4898 * Saves a lot of time, because we don't have to start a new shell.
4899 */
4900 if (!have_wildcard(num_pat, pat))
4901 return save_patterns(num_pat, pat, num_file, file);
4902
Bram Moolenaar0e634da2005-07-20 21:57:28 +00004903# ifdef HAVE_SANDBOX
4904 /* Don't allow any shell command in the sandbox. */
4905 if (sandbox != 0 && check_secure())
4906 return FAIL;
4907# endif
4908
Bram Moolenaar071d4272004-06-13 20:20:40 +00004909 /*
4910 * Don't allow the use of backticks in secure and restricted mode.
4911 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00004912 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004913 for (i = 0; i < num_pat; ++i)
4914 if (vim_strchr(pat[i], '`') != NULL
4915 && (check_restricted() || check_secure()))
4916 return FAIL;
4917
4918 /*
4919 * get a name for the temp file
4920 */
4921 if ((tempname = vim_tempname('o')) == NULL)
4922 {
4923 EMSG(_(e_notmp));
4924 return FAIL;
4925 }
4926
4927 /*
4928 * Let the shell expand the patterns and write the result into the temp
4929 * file. if expanding `cmd` execute it directly.
4930 * If we use csh, glob will work better than echo.
4931 * If we use zsh, print -N will work better than glob.
4932 */
4933 if (num_pat == 1 && *pat[0] == '`'
4934 && (len = STRLEN(pat[0])) > 2
4935 && *(pat[0] + len - 1) == '`')
4936 shell_style = STYLE_BT;
4937 else if ((len = STRLEN(p_sh)) >= 3)
4938 {
4939 if (STRCMP(p_sh + len - 3, "csh") == 0)
4940 shell_style = STYLE_GLOB;
4941 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
4942 shell_style = STYLE_PRINT;
4943 }
4944
4945 /* "unset nonomatch; print -N >" plus two is 29 */
4946 len = STRLEN(tempname) + 29;
Bram Moolenaarb23c3382005-01-31 19:09:12 +00004947 for (i = 0; i < num_pat; ++i)
4948 {
4949 /* Count the length of the patterns in the same way as they are put in
4950 * "command" below. */
4951#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00004952 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00004953#else
4954 ++len; /* add space */
4955 for (j = 0; pat[i][j] != NUL; )
Bram Moolenaarb815dac2005-12-07 20:59:24 +00004956 if (vim_strchr((char_u *)" ';&<>", pat[i][j]) != NULL)
Bram Moolenaarb23c3382005-01-31 19:09:12 +00004957 {
4958 len += 2; /* add two quotes */
4959 while (pat[i][j] != NUL
Bram Moolenaarb815dac2005-12-07 20:59:24 +00004960 && vim_strchr((char_u *)" ';&<>", pat[i][j]) != NULL)
Bram Moolenaarb23c3382005-01-31 19:09:12 +00004961 {
4962 ++len;
4963 ++j;
4964 }
4965 }
4966 else
4967 {
4968 ++len;
4969 ++j;
4970 }
4971#endif
4972 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004973 command = alloc(len);
4974 if (command == NULL)
4975 {
4976 /* out of memory */
4977 vim_free(tempname);
4978 return FAIL;
4979 }
4980
4981 /*
4982 * Build the shell command:
4983 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
4984 * recognizes this).
4985 * - Add the shell command to print the expanded names.
4986 * - Add the temp file name.
4987 * - Add the file name patterns.
4988 */
4989 if (shell_style == STYLE_BT)
4990 {
4991 STRCPY(command, pat[0] + 1); /* exclude first backtick */
4992 p = command + STRLEN(command) - 1;
4993 *p = ' '; /* remove last backtick */
4994 while (p > command && vim_iswhite(*p))
4995 --p;
4996 if (*p == '&') /* remove trailing '&' */
4997 {
4998 ampersent = TRUE;
4999 *p = ' ';
5000 }
5001 STRCAT(command, ">");
5002 }
5003 else
5004 {
5005 if (flags & EW_NOTFOUND)
5006 STRCPY(command, "set nonomatch; ");
5007 else
5008 STRCPY(command, "unset nonomatch; ");
5009 if (shell_style == STYLE_GLOB)
5010 STRCAT(command, "glob >");
5011 else if (shell_style == STYLE_PRINT)
5012 STRCAT(command, "print -N >");
5013 else
5014 STRCAT(command, "echo >");
5015 }
5016 STRCAT(command, tempname);
5017 if (shell_style != STYLE_BT)
5018 for (i = 0; i < num_pat; ++i)
5019 {
5020 /* When using system() always add extra quotes, because the shell
5021 * is started twice. Otherwise only put quotes around spaces and
5022 * single quotes. */
5023#ifdef USE_SYSTEM
5024 STRCAT(command, " \"");
5025 STRCAT(command, pat[i]);
5026 STRCAT(command, "\"");
5027#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005028 int intick = FALSE;
5029
Bram Moolenaar071d4272004-06-13 20:20:40 +00005030 p = command + STRLEN(command);
5031 *p++ = ' ';
5032 for (j = 0; pat[i][j] != NUL; )
Bram Moolenaar582fd852005-03-28 20:58:01 +00005033 {
5034 if (pat[i][j] == '`')
5035 {
5036 intick = !intick;
5037 *p++ = pat[i][j++];
5038 }
Bram Moolenaarb815dac2005-12-07 20:59:24 +00005039 else if (!intick && vim_strchr((char_u *)" ';&<>",
Bram Moolenaar582fd852005-03-28 20:58:01 +00005040 pat[i][j]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005041 {
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00005042 /* Put quotes around special characters, but not when
5043 * inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005044 *p++ = '"';
Bram Moolenaarb815dac2005-12-07 20:59:24 +00005045 while (pat[i][j] != NUL && vim_strchr((char_u *)" ';&<>",
5046 pat[i][j]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005047 *p++ = pat[i][j++];
5048 *p++ = '"';
5049 }
5050 else
Bram Moolenaar0cf6f542005-01-16 21:59:36 +00005051 {
5052 /* For a backslash also copy the next character, don't
5053 * want to put quotes around it. */
5054 if ((*p++ = pat[i][j++]) == '\\' && pat[i][j] != NUL)
5055 *p++ = pat[i][j++];
5056 }
Bram Moolenaar582fd852005-03-28 20:58:01 +00005057 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005058 *p = NUL;
5059#endif
5060 }
5061 if (flags & EW_SILENT)
5062 show_shell_mess = FALSE;
5063 if (ampersent)
5064 STRCAT(command, "&"); /* put the '&' back after the
5065 redirection */
5066
5067 /*
5068 * Using zsh -G: If a pattern has no matches, it is just deleted from
5069 * the argument list, otherwise zsh gives an error message and doesn't
5070 * expand any other pattern.
5071 */
5072 if (shell_style == STYLE_PRINT)
5073 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5074
5075 /*
5076 * If we use -f then shell variables set in .cshrc won't get expanded.
5077 * vi can do it, so we will too, but it is only necessary if there is a "$"
5078 * in one of the patterns, otherwise we can still use the fast option.
5079 */
5080 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5081 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5082
5083 /*
5084 * execute the shell command
5085 */
5086 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5087
5088 /* When running in the background, give it some time to create the temp
5089 * file, but don't wait for it to finish. */
5090 if (ampersent)
5091 mch_delay(10L, TRUE);
5092
5093 extra_shell_arg = NULL; /* cleanup */
5094 show_shell_mess = TRUE;
5095 vim_free(command);
5096
5097 if (i) /* mch_call_shell() failed */
5098 {
5099 mch_remove(tempname);
5100 vim_free(tempname);
5101 /*
5102 * With interactive completion, the error message is not printed.
5103 * However with USE_SYSTEM, I don't know how to turn off error messages
5104 * from the shell, so screen may still get messed up -- webb.
5105 */
5106#ifndef USE_SYSTEM
5107 if (!(flags & EW_SILENT))
5108#endif
5109 {
5110 redraw_later_clear(); /* probably messed up screen */
5111 msg_putchar('\n'); /* clear bottom line quickly */
5112 cmdline_row = Rows - 1; /* continue on last line */
5113#ifdef USE_SYSTEM
5114 if (!(flags & EW_SILENT))
5115#endif
5116 {
5117 MSG(_(e_wildexpand));
5118 msg_start(); /* don't overwrite this message */
5119 }
5120 }
5121 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5122 * EW_NOTFOUND is given */
5123 if (shell_style == STYLE_BT)
5124 return FAIL;
5125 goto notfound;
5126 }
5127
5128 /*
5129 * read the names from the file into memory
5130 */
5131 fd = fopen((char *)tempname, READBIN);
5132 if (fd == NULL)
5133 {
5134 /* Something went wrong, perhaps a file name with a special char. */
5135 if (!(flags & EW_SILENT))
5136 {
5137 MSG(_(e_wildexpand));
5138 msg_start(); /* don't overwrite this message */
5139 }
5140 vim_free(tempname);
5141 goto notfound;
5142 }
5143 fseek(fd, 0L, SEEK_END);
5144 len = ftell(fd); /* get size of temp file */
5145 fseek(fd, 0L, SEEK_SET);
5146 buffer = alloc(len + 1);
5147 if (buffer == NULL)
5148 {
5149 /* out of memory */
5150 mch_remove(tempname);
5151 vim_free(tempname);
5152 fclose(fd);
5153 return FAIL;
5154 }
5155 i = fread((char *)buffer, 1, len, fd);
5156 fclose(fd);
5157 mch_remove(tempname);
5158 if (i != len)
5159 {
5160 /* unexpected read error */
5161 EMSG2(_(e_notread), tempname);
5162 vim_free(tempname);
5163 vim_free(buffer);
5164 return FAIL;
5165 }
5166 vim_free(tempname);
5167
5168#if defined(__CYGWIN__) || defined(__CYGWIN32__)
5169 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5170 p = buffer;
5171 for (i = 0; i < len; ++i)
5172 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5173 *p++ = buffer[i];
5174 len = p - buffer;
5175# endif
5176
5177
5178 /* file names are separated with Space */
5179 if (shell_style == STYLE_ECHO)
5180 {
5181 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5182 p = buffer;
5183 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5184 {
5185 while (*p != ' ' && *p != '\n')
5186 ++p;
5187 p = skipwhite(p); /* skip to next entry */
5188 }
5189 }
5190 /* file names are separated with NL */
5191 else if (shell_style == STYLE_BT)
5192 {
5193 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5194 p = buffer;
5195 for (i = 0; *p != NUL; ++i) /* count number of entries */
5196 {
5197 while (*p != '\n' && *p != NUL)
5198 ++p;
5199 if (*p != NUL)
5200 ++p;
5201 p = skipwhite(p); /* skip leading white space */
5202 }
5203 }
5204 /* file names are separated with NUL */
5205 else
5206 {
5207 /*
5208 * Some versions of zsh use spaces instead of NULs to separate
5209 * results. Only do this when there is no NUL before the end of the
5210 * buffer, otherwise we would never be able to use file names with
5211 * embedded spaces when zsh does use NULs.
5212 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5213 * don't check for spaces again.
5214 */
5215 check_spaces = FALSE;
5216 if (shell_style == STYLE_PRINT && !did_find_nul)
5217 {
5218 /* If there is a NUL, set did_find_nul, else set check_spaces */
5219 if (len && (int)STRLEN(buffer) < len - 1)
5220 did_find_nul = TRUE;
5221 else
5222 check_spaces = TRUE;
5223 }
5224
5225 /*
5226 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5227 * already is one, for STYLE_GLOB it needs to be added.
5228 */
5229 if (len && buffer[len - 1] == NUL)
5230 --len;
5231 else
5232 buffer[len] = NUL;
5233 i = 0;
5234 for (p = buffer; p < buffer + len; ++p)
5235 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5236 {
5237 ++i;
5238 *p = NUL;
5239 }
5240 if (len)
5241 ++i; /* count last entry */
5242 }
5243 if (i == 0)
5244 {
5245 /*
5246 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5247 * /bin/sh will happily expand it to nothing rather than returning an
5248 * error; and hey, it's good to check anyway -- webb.
5249 */
5250 vim_free(buffer);
5251 goto notfound;
5252 }
5253 *num_file = i;
5254 *file = (char_u **)alloc(sizeof(char_u *) * i);
5255 if (*file == NULL)
5256 {
5257 /* out of memory */
5258 vim_free(buffer);
5259 return FAIL;
5260 }
5261
5262 /*
5263 * Isolate the individual file names.
5264 */
5265 p = buffer;
5266 for (i = 0; i < *num_file; ++i)
5267 {
5268 (*file)[i] = p;
5269 /* Space or NL separates */
5270 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT)
5271 {
5272 while (!(shell_style == STYLE_ECHO && *p == ' ') && *p != '\n')
5273 ++p;
5274 if (p == buffer + len) /* last entry */
5275 *p = NUL;
5276 else
5277 {
5278 *p++ = NUL;
5279 p = skipwhite(p); /* skip to next entry */
5280 }
5281 }
5282 else /* NUL separates */
5283 {
5284 while (*p && p < buffer + len) /* skip entry */
5285 ++p;
5286 ++p; /* skip NUL */
5287 }
5288 }
5289
5290 /*
5291 * Move the file names to allocated memory.
5292 */
5293 for (j = 0, i = 0; i < *num_file; ++i)
5294 {
5295 /* Require the files to exist. Helps when using /bin/sh */
5296 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5297 continue;
5298
5299 /* check if this entry should be included */
5300 dir = (mch_isdir((*file)[i]));
5301 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5302 continue;
5303
5304 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5305 if (p)
5306 {
5307 STRCPY(p, (*file)[i]);
5308 if (dir)
5309 STRCAT(p, "/"); /* add '/' to a directory name */
5310 (*file)[j++] = p;
5311 }
5312 }
5313 vim_free(buffer);
5314 *num_file = j;
5315
5316 if (*num_file == 0) /* rejected all entries */
5317 {
5318 vim_free(*file);
5319 *file = NULL;
5320 goto notfound;
5321 }
5322
5323 return OK;
5324
5325notfound:
5326 if (flags & EW_NOTFOUND)
5327 return save_patterns(num_pat, pat, num_file, file);
5328 return FAIL;
5329
5330#endif /* __EMX__ */
5331}
5332
5333#endif /* VMS */
5334
5335#ifndef __EMX__
5336 static int
5337save_patterns(num_pat, pat, num_file, file)
5338 int num_pat;
5339 char_u **pat;
5340 int *num_file;
5341 char_u ***file;
5342{
5343 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005344 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005345
5346 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5347 if (*file == NULL)
5348 return FAIL;
5349 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005350 {
5351 s = vim_strsave(pat[i]);
5352 if (s != NULL)
5353 /* Be compatible with expand_filename(): halve the number of
5354 * backslashes. */
5355 backslash_halve(s);
5356 (*file)[i] = s;
5357 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005358 *num_file = num_pat;
5359 return OK;
5360}
5361#endif
5362
5363
5364/*
5365 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5366 * expand.
5367 */
5368 int
5369mch_has_exp_wildcard(p)
5370 char_u *p;
5371{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005372 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005373 {
5374#ifndef OS2
5375 if (*p == '\\' && p[1] != NUL)
5376 ++p;
5377 else
5378#endif
5379 if (vim_strchr((char_u *)
5380#ifdef VMS
5381 "*?%"
5382#else
5383# ifdef OS2
5384 "*?"
5385# else
5386 "*?[{'"
5387# endif
5388#endif
5389 , *p) != NULL)
5390 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005391 }
5392 return FALSE;
5393}
5394
5395/*
5396 * Return TRUE if the string "p" contains a wildcard.
5397 * Don't recognize '~' at the end as a wildcard.
5398 */
5399 int
5400mch_has_wildcard(p)
5401 char_u *p;
5402{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005403 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005404 {
5405#ifndef OS2
5406 if (*p == '\\' && p[1] != NUL)
5407 ++p;
5408 else
5409#endif
5410 if (vim_strchr((char_u *)
5411#ifdef VMS
5412 "*?%$"
5413#else
5414# ifdef OS2
5415# ifdef VIM_BACKTICK
5416 "*?$`"
5417# else
5418 "*?$"
5419# endif
5420# else
5421 "*?[{`'$"
5422# endif
5423#endif
5424 , *p) != NULL
5425 || (*p == '~' && p[1] != NUL))
5426 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005427 }
5428 return FALSE;
5429}
5430
5431#ifndef __EMX__
5432 static int
5433have_wildcard(num, file)
5434 int num;
5435 char_u **file;
5436{
5437 int i;
5438
5439 for (i = 0; i < num; i++)
5440 if (mch_has_wildcard(file[i]))
5441 return 1;
5442 return 0;
5443}
5444
5445 static int
5446have_dollars(num, file)
5447 int num;
5448 char_u **file;
5449{
5450 int i;
5451
5452 for (i = 0; i < num; i++)
5453 if (vim_strchr(file[i], '$') != NULL)
5454 return TRUE;
5455 return FALSE;
5456}
5457#endif /* ifndef __EMX__ */
5458
5459#ifndef HAVE_RENAME
5460/*
5461 * Scaled-down version of rename(), which is missing in Xenix.
5462 * This version can only move regular files and will fail if the
5463 * destination exists.
5464 */
5465 int
5466mch_rename(src, dest)
5467 const char *src, *dest;
5468{
5469 struct stat st;
5470
5471 if (stat(dest, &st) >= 0) /* fail if destination exists */
5472 return -1;
5473 if (link(src, dest) != 0) /* link file to new name */
5474 return -1;
5475 if (mch_remove(src) == 0) /* delete link to old name */
5476 return 0;
5477 return -1;
5478}
5479#endif /* !HAVE_RENAME */
5480
5481#ifdef FEAT_MOUSE_GPM
5482/*
5483 * Initializes connection with gpm (if it isn't already opened)
5484 * Return 1 if succeeded (or connection already opened), 0 if failed
5485 */
5486 static int
5487gpm_open()
5488{
5489 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5490
5491 if (!gpm_flag)
5492 {
5493 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5494 gpm_connect.defaultMask = ~GPM_HARD;
5495 /* Default handling for mouse move*/
5496 gpm_connect.minMod = 0; /* Handle any modifier keys */
5497 gpm_connect.maxMod = 0xffff;
5498 if (Gpm_Open(&gpm_connect, 0) > 0)
5499 {
5500 /* gpm library tries to handling TSTP causes
5501 * problems. Anyways, we close connection to Gpm whenever
5502 * we are going to suspend or starting an external process
5503 * so we should'nt have problem with this
5504 */
5505 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5506 return 1; /* succeed */
5507 }
5508 if (gpm_fd == -2)
5509 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5510 return 0;
5511 }
5512 return 1; /* already open */
5513}
5514
5515/*
5516 * Closes connection to gpm
5517 * returns non-zero if connection succesfully closed
5518 */
5519 static void
5520gpm_close()
5521{
5522 if (gpm_flag && gpm_fd >= 0) /* if Open */
5523 Gpm_Close();
5524}
5525
5526/* Reads gpm event and adds special keys to input buf. Returns length of
5527 * generated key sequence.
5528 * This function is made after gui_send_mouse_event
5529 */
5530 static int
5531mch_gpm_process()
5532{
5533 int button;
5534 static Gpm_Event gpm_event;
5535 char_u string[6];
5536 int_u vim_modifiers;
5537 int row,col;
5538 unsigned char buttons_mask;
5539 unsigned char gpm_modifiers;
5540 static unsigned char old_buttons = 0;
5541
5542 Gpm_GetEvent(&gpm_event);
5543
5544#ifdef FEAT_GUI
5545 /* Don't put events in the input queue now. */
5546 if (hold_gui_events)
5547 return 0;
5548#endif
5549
5550 row = gpm_event.y - 1;
5551 col = gpm_event.x - 1;
5552
5553 string[0] = ESC; /* Our termcode */
5554 string[1] = 'M';
5555 string[2] = 'G';
5556 switch (GPM_BARE_EVENTS(gpm_event.type))
5557 {
5558 case GPM_DRAG:
5559 string[3] = MOUSE_DRAG;
5560 break;
5561 case GPM_DOWN:
5562 buttons_mask = gpm_event.buttons & ~old_buttons;
5563 old_buttons = gpm_event.buttons;
5564 switch (buttons_mask)
5565 {
5566 case GPM_B_LEFT:
5567 button = MOUSE_LEFT;
5568 break;
5569 case GPM_B_MIDDLE:
5570 button = MOUSE_MIDDLE;
5571 break;
5572 case GPM_B_RIGHT:
5573 button = MOUSE_RIGHT;
5574 break;
5575 default:
5576 return 0;
5577 /*Don't know what to do. Can more than one button be
5578 * reported in one event? */
5579 }
5580 string[3] = (char_u)(button | 0x20);
5581 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5582 break;
5583 case GPM_UP:
5584 string[3] = MOUSE_RELEASE;
5585 old_buttons &= ~gpm_event.buttons;
5586 break;
5587 default:
5588 return 0;
5589 }
5590 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5591 gpm_modifiers = gpm_event.modifiers;
5592 vim_modifiers = 0x0;
5593 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5594 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5595 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5596 */
5597 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5598 vim_modifiers |= MOUSE_SHIFT;
5599
5600 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5601 vim_modifiers |= MOUSE_CTRL;
5602 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5603 vim_modifiers |= MOUSE_ALT;
5604 string[3] |= vim_modifiers;
5605 string[4] = (char_u)(col + ' ' + 1);
5606 string[5] = (char_u)(row + ' ' + 1);
5607 add_to_input_buf(string, 6);
5608 return 6;
5609}
5610#endif /* FEAT_MOUSE_GPM */
5611
5612#if defined(FEAT_LIBCALL) || defined(PROTO)
5613typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
5614typedef char_u * (*INTPROCSTR)__ARGS((int));
5615typedef int (*STRPROCINT)__ARGS((char_u *));
5616typedef int (*INTPROCINT)__ARGS((int));
5617
5618/*
5619 * Call a DLL routine which takes either a string or int param
5620 * and returns an allocated string.
5621 */
5622 int
5623mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
5624 char_u *libname;
5625 char_u *funcname;
5626 char_u *argstring; /* NULL when using a argint */
5627 int argint;
5628 char_u **string_result;/* NULL when using number_result */
5629 int *number_result;
5630{
5631# if defined(USE_DLOPEN)
5632 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005633 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005634# else
5635 shl_t hinstLib;
5636# endif
5637 STRPROCSTR ProcAdd;
5638 INTPROCSTR ProcAddI;
5639 char_u *retval_str = NULL;
5640 int retval_int = 0;
5641 int success = FALSE;
5642
5643 /* Get a handle to the DLL module. */
5644# if defined(USE_DLOPEN)
5645 hinstLib = dlopen((char *)libname, RTLD_LAZY
5646# ifdef RTLD_LOCAL
5647 | RTLD_LOCAL
5648# endif
5649 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005650 if (hinstLib == NULL)
5651 {
5652 /* "dlerr" must be used before dlclose() */
5653 dlerr = (char *)dlerror();
5654 if (dlerr != NULL)
5655 EMSG2(_("dlerror = \"%s\""), dlerr);
5656 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005657# else
5658 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
5659# endif
5660
5661 /* If the handle is valid, try to get the function address. */
5662 if (hinstLib != NULL)
5663 {
5664# ifdef HAVE_SETJMP_H
5665 /*
5666 * Catch a crash when calling the library function. For example when
5667 * using a number where a string pointer is expected.
5668 */
5669 mch_startjmp();
5670 if (SETJMP(lc_jump_env) != 0)
5671 {
5672 success = FALSE;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005673 dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005674 mch_didjmp();
5675 }
5676 else
5677# endif
5678 {
5679 retval_str = NULL;
5680 retval_int = 0;
5681
5682 if (argstring != NULL)
5683 {
5684# if defined(USE_DLOPEN)
5685 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005686 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005687# else
5688 if (shl_findsym(&hinstLib, (const char *)funcname,
5689 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
5690 ProcAdd = NULL;
5691# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005692 if ((success = (ProcAdd != NULL
5693# if defined(USE_DLOPEN)
5694 && dlerr == NULL
5695# endif
5696 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005697 {
5698 if (string_result == NULL)
5699 retval_int = ((STRPROCINT)ProcAdd)(argstring);
5700 else
5701 retval_str = (ProcAdd)(argstring);
5702 }
5703 }
5704 else
5705 {
5706# if defined(USE_DLOPEN)
5707 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005708 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005709# else
5710 if (shl_findsym(&hinstLib, (const char *)funcname,
5711 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
5712 ProcAddI = NULL;
5713# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005714 if ((success = (ProcAddI != NULL
5715# if defined(USE_DLOPEN)
5716 && dlerr == NULL
5717# endif
5718 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005719 {
5720 if (string_result == NULL)
5721 retval_int = ((INTPROCINT)ProcAddI)(argint);
5722 else
5723 retval_str = (ProcAddI)(argint);
5724 }
5725 }
5726
5727 /* Save the string before we free the library. */
5728 /* Assume that a "1" or "-1" result is an illegal pointer. */
5729 if (string_result == NULL)
5730 *number_result = retval_int;
5731 else if (retval_str != NULL
5732 && retval_str != (char_u *)1
5733 && retval_str != (char_u *)-1)
5734 *string_result = vim_strsave(retval_str);
5735 }
5736
5737# ifdef HAVE_SETJMP_H
5738 mch_endjmp();
5739# ifdef SIGHASARG
5740 if (lc_signal != 0)
5741 {
5742 int i;
5743
5744 /* try to find the name of this signal */
5745 for (i = 0; signal_info[i].sig != -1; i++)
5746 if (lc_signal == signal_info[i].sig)
5747 break;
5748 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
5749 }
5750# endif
5751# endif
5752
Bram Moolenaar071d4272004-06-13 20:20:40 +00005753# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005754 /* "dlerr" must be used before dlclose() */
5755 if (dlerr != NULL)
5756 EMSG2(_("dlerror = \"%s\""), dlerr);
5757
5758 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005759 (void)dlclose(hinstLib);
5760# else
5761 (void)shl_unload(hinstLib);
5762# endif
5763 }
5764
5765 if (!success)
5766 {
5767 EMSG2(_(e_libcall), funcname);
5768 return FAIL;
5769 }
5770
5771 return OK;
5772}
5773#endif
5774
5775#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
5776static int xterm_trace = -1; /* default: disabled */
5777static int xterm_button;
5778
5779/*
5780 * Setup a dummy window for X selections in a terminal.
5781 */
5782 void
5783setup_term_clip()
5784{
5785 int z = 0;
5786 char *strp = "";
5787 Widget AppShell;
5788
5789 if (!x_connect_to_server())
5790 return;
5791
5792 open_app_context();
5793 if (app_context != NULL && xterm_Shell == (Widget)0)
5794 {
5795 int (*oldhandler)();
5796#if defined(HAVE_SETJMP_H)
5797 int (*oldIOhandler)();
5798#endif
5799# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5800 struct timeval start_tv;
5801
5802 if (p_verbose > 0)
5803 gettimeofday(&start_tv, NULL);
5804# endif
5805
5806 /* Ignore X errors while opening the display */
5807 oldhandler = XSetErrorHandler(x_error_check);
5808
5809#if defined(HAVE_SETJMP_H)
5810 /* Ignore X IO errors while opening the display */
5811 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
5812 mch_startjmp();
5813 if (SETJMP(lc_jump_env) != 0)
5814 {
5815 mch_didjmp();
5816 xterm_dpy = NULL;
5817 }
5818 else
5819#endif
5820 {
5821 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
5822 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
5823#if defined(HAVE_SETJMP_H)
5824 mch_endjmp();
5825#endif
5826 }
5827
5828#if defined(HAVE_SETJMP_H)
5829 /* Now handle X IO errors normally. */
5830 (void)XSetIOErrorHandler(oldIOhandler);
5831#endif
5832 /* Now handle X errors normally. */
5833 (void)XSetErrorHandler(oldhandler);
5834
5835 if (xterm_dpy == NULL)
5836 {
5837 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005838 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839 return;
5840 }
5841
5842 /* Catch terminating error of the X server connection. */
5843 (void)XSetIOErrorHandler(x_IOerror_handler);
5844
5845# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5846 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005847 {
5848 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005849 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005850 verbose_leave();
5851 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005852# endif
5853
5854 /* Create a Shell to make converters work. */
5855 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
5856 applicationShellWidgetClass, xterm_dpy,
5857 NULL);
5858 if (AppShell == (Widget)0)
5859 return;
5860 xterm_Shell = XtVaCreatePopupShell("VIM",
5861 topLevelShellWidgetClass, AppShell,
5862 XtNmappedWhenManaged, 0,
5863 XtNwidth, 1,
5864 XtNheight, 1,
5865 NULL);
5866 if (xterm_Shell == (Widget)0)
5867 return;
5868
5869 x11_setup_atoms(xterm_dpy);
5870 if (x11_display == NULL)
5871 x11_display = xterm_dpy;
5872
5873 XtRealizeWidget(xterm_Shell);
5874 XSync(xterm_dpy, False);
5875 xterm_update();
5876 }
5877 if (xterm_Shell != (Widget)0)
5878 {
5879 clip_init(TRUE);
5880 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
5881 x11_window = (Window)atol(strp);
5882 /* Check if $WINDOWID is valid. */
5883 if (test_x11_window(xterm_dpy) == FAIL)
5884 x11_window = 0;
5885 if (x11_window != 0)
5886 xterm_trace = 0;
5887 }
5888}
5889
5890 void
5891start_xterm_trace(button)
5892 int button;
5893{
5894 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
5895 return;
5896 xterm_trace = 1;
5897 xterm_button = button;
5898 do_xterm_trace();
5899}
5900
5901
5902 void
5903stop_xterm_trace()
5904{
5905 if (xterm_trace < 0)
5906 return;
5907 xterm_trace = 0;
5908}
5909
5910/*
5911 * Query the xterm pointer and generate mouse termcodes if necessary
5912 * return TRUE if dragging is active, else FALSE
5913 */
5914 static int
5915do_xterm_trace()
5916{
5917 Window root, child;
5918 int root_x, root_y;
5919 int win_x, win_y;
5920 int row, col;
5921 int_u mask_return;
5922 char_u buf[50];
5923 char_u *strp;
5924 long got_hints;
5925 static char_u *mouse_code;
5926 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
5927 static int prev_row = 0, prev_col = 0;
5928 static XSizeHints xterm_hints;
5929
5930 if (xterm_trace <= 0)
5931 return FALSE;
5932
5933 if (xterm_trace == 1)
5934 {
5935 /* Get the hints just before tracking starts. The font size might
5936 * have changed recently */
5937 XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints);
5938 if (!(got_hints & PResizeInc)
5939 || xterm_hints.width_inc <= 1
5940 || xterm_hints.height_inc <= 1)
5941 {
5942 xterm_trace = -1; /* Not enough data -- disable tracing */
5943 return FALSE;
5944 }
5945
5946 /* Rely on the same mouse code for the duration of this */
5947 mouse_code = find_termcode(mouse_name);
5948 prev_row = mouse_row;
5949 prev_row = mouse_col;
5950 xterm_trace = 2;
5951
5952 /* Find the offset of the chars, there might be a scrollbar on the
5953 * left of the window and/or a menu on the top (eterm etc.) */
5954 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
5955 &win_x, &win_y, &mask_return);
5956 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
5957 - (xterm_hints.height_inc / 2);
5958 if (xterm_hints.y <= xterm_hints.height_inc / 2)
5959 xterm_hints.y = 2;
5960 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
5961 - (xterm_hints.width_inc / 2);
5962 if (xterm_hints.x <= xterm_hints.width_inc / 2)
5963 xterm_hints.x = 2;
5964 return TRUE;
5965 }
5966 if (mouse_code == NULL)
5967 {
5968 xterm_trace = 0;
5969 return FALSE;
5970 }
5971
5972 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
5973 &win_x, &win_y, &mask_return);
5974
5975 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
5976 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
5977 if (row == prev_row && col == prev_col)
5978 return TRUE;
5979
5980 STRCPY(buf, mouse_code);
5981 strp = buf + STRLEN(buf);
5982 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
5983 *strp++ = (char_u)(col + ' ' + 1);
5984 *strp++ = (char_u)(row + ' ' + 1);
5985 *strp = 0;
5986 add_to_input_buf(buf, STRLEN(buf));
5987
5988 prev_row = row;
5989 prev_col = col;
5990 return TRUE;
5991}
5992
5993# if defined(FEAT_GUI) || defined(PROTO)
5994/*
5995 * Destroy the display, window and app_context. Required for GTK.
5996 */
5997 void
5998clear_xterm_clip()
5999{
6000 if (xterm_Shell != (Widget)0)
6001 {
6002 XtDestroyWidget(xterm_Shell);
6003 xterm_Shell = (Widget)0;
6004 }
6005 if (xterm_dpy != NULL)
6006 {
6007#if 0
6008 /* Lesstif and Solaris crash here, lose some memory */
6009 XtCloseDisplay(xterm_dpy);
6010#endif
6011 if (x11_display == xterm_dpy)
6012 x11_display = NULL;
6013 xterm_dpy = NULL;
6014 }
6015#if 0
6016 if (app_context != (XtAppContext)NULL)
6017 {
6018 /* Lesstif and Solaris crash here, lose some memory */
6019 XtDestroyApplicationContext(app_context);
6020 app_context = (XtAppContext)NULL;
6021 }
6022#endif
6023}
6024# endif
6025
6026/*
6027 * Catch up with any queued X events. This may put keyboard input into the
6028 * input buffer, call resize call-backs, trigger timers etc. If there is
6029 * nothing in the X event queue (& no timers pending), then we return
6030 * immediately.
6031 */
6032 static void
6033xterm_update()
6034{
6035 XEvent event;
6036
6037 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6038 {
6039 XtAppNextEvent(app_context, &event);
6040#ifdef FEAT_CLIENTSERVER
6041 {
6042 XPropertyEvent *e = (XPropertyEvent *)&event;
6043
6044 if (e->type == PropertyNotify && e->window == commWindow
6045 && e->atom == commProperty && e->state == PropertyNewValue)
6046 serverEventProc(xterm_dpy, &event);
6047 }
6048#endif
6049 XtDispatchEvent(&event);
6050 }
6051}
6052
6053 int
6054clip_xterm_own_selection(cbd)
6055 VimClipboard *cbd;
6056{
6057 if (xterm_Shell != (Widget)0)
6058 return clip_x11_own_selection(xterm_Shell, cbd);
6059 return FAIL;
6060}
6061
6062 void
6063clip_xterm_lose_selection(cbd)
6064 VimClipboard *cbd;
6065{
6066 if (xterm_Shell != (Widget)0)
6067 clip_x11_lose_selection(xterm_Shell, cbd);
6068}
6069
6070 void
6071clip_xterm_request_selection(cbd)
6072 VimClipboard *cbd;
6073{
6074 if (xterm_Shell != (Widget)0)
6075 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6076}
6077
6078 void
6079clip_xterm_set_selection(cbd)
6080 VimClipboard *cbd;
6081{
6082 clip_x11_set_selection(cbd);
6083}
6084#endif
6085
6086
6087#if defined(USE_XSMP) || defined(PROTO)
6088/*
6089 * Code for X Session Management Protocol.
6090 */
6091static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6092static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6093static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6094static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6095static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6096
6097
6098# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6099static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6100
6101/*
6102 * This is our chance to ask the user if they want to save,
6103 * or abort the logout
6104 */
6105/*ARGSUSED*/
6106 static void
6107xsmp_handle_interaction(smc_conn, client_data)
6108 SmcConn smc_conn;
6109 SmPointer client_data;
6110{
6111 cmdmod_T save_cmdmod;
6112 int cancel_shutdown = False;
6113
6114 save_cmdmod = cmdmod;
6115 cmdmod.confirm = TRUE;
6116 if (check_changed_any(FALSE))
6117 /* Mustn't logout */
6118 cancel_shutdown = True;
6119 cmdmod = save_cmdmod;
6120 setcursor(); /* position cursor */
6121 out_flush();
6122
6123 /* Done interaction */
6124 SmcInteractDone(smc_conn, cancel_shutdown);
6125
6126 /* Finish off
6127 * Only end save-yourself here if we're not cancelling shutdown;
6128 * we'll get a cancelled callback later in which we'll end it.
6129 * Hopefully get around glitchy SMs (like GNOME-1)
6130 */
6131 if (!cancel_shutdown)
6132 {
6133 xsmp.save_yourself = False;
6134 SmcSaveYourselfDone(smc_conn, True);
6135 }
6136}
6137# endif
6138
6139/*
6140 * Callback that starts save-yourself.
6141 */
6142/*ARGSUSED*/
6143 static void
6144xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6145 shutdown, interact_style, fast)
6146 SmcConn smc_conn;
6147 SmPointer client_data;
6148 int save_type;
6149 Bool shutdown;
6150 int interact_style;
6151 Bool fast;
6152{
6153 /* Handle already being in saveyourself */
6154 if (xsmp.save_yourself)
6155 SmcSaveYourselfDone(smc_conn, True);
6156 xsmp.save_yourself = True;
6157 xsmp.shutdown = shutdown;
6158
6159 /* First up, preserve all files */
6160 out_flush();
6161 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6162
6163 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006164 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006165
6166# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6167 /* Now see if we can ask about unsaved files */
6168 if (shutdown && !fast && gui.in_use)
6169 /* Need to interact with user, but need SM's permission */
6170 SmcInteractRequest(smc_conn, SmDialogError,
6171 xsmp_handle_interaction, client_data);
6172 else
6173# endif
6174 {
6175 /* Can stop the cycle here */
6176 SmcSaveYourselfDone(smc_conn, True);
6177 xsmp.save_yourself = False;
6178 }
6179}
6180
6181
6182/*
6183 * Callback to warn us of imminent death.
6184 */
6185/*ARGSUSED*/
6186 static void
6187xsmp_die(smc_conn, client_data)
6188 SmcConn smc_conn;
6189 SmPointer client_data;
6190{
6191 xsmp_close();
6192
6193 /* quit quickly leaving swapfiles for modified buffers behind */
6194 getout_preserve_modified(0);
6195}
6196
6197
6198/*
6199 * Callback to tell us that save-yourself has completed.
6200 */
6201/*ARGSUSED*/
6202 static void
6203xsmp_save_complete(smc_conn, client_data)
6204 SmcConn smc_conn;
6205 SmPointer client_data;
6206{
6207 xsmp.save_yourself = False;
6208}
6209
6210
6211/*
6212 * Callback to tell us that an instigated shutdown was cancelled
6213 * (maybe even by us)
6214 */
6215/*ARGSUSED*/
6216 static void
6217xsmp_shutdown_cancelled(smc_conn, client_data)
6218 SmcConn smc_conn;
6219 SmPointer client_data;
6220{
6221 if (xsmp.save_yourself)
6222 SmcSaveYourselfDone(smc_conn, True);
6223 xsmp.save_yourself = False;
6224 xsmp.shutdown = False;
6225}
6226
6227
6228/*
6229 * Callback to tell us that a new ICE connection has been established.
6230 */
6231/*ARGSUSED*/
6232 static void
6233xsmp_ice_connection(iceConn, clientData, opening, watchData)
6234 IceConn iceConn;
6235 IcePointer clientData;
6236 Bool opening;
6237 IcePointer *watchData;
6238{
6239 /* Intercept creation of ICE connection fd */
6240 if (opening)
6241 {
6242 xsmp_icefd = IceConnectionNumber(iceConn);
6243 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6244 }
6245}
6246
6247
6248/* Handle any ICE processing that's required; return FAIL if SM lost */
6249 int
6250xsmp_handle_requests()
6251{
6252 Bool rep;
6253
6254 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6255 == IceProcessMessagesIOError)
6256 {
6257 /* Lost ICE */
6258 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006259 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006260 xsmp_close();
6261 return FAIL;
6262 }
6263 else
6264 return OK;
6265}
6266
6267static int dummy;
6268
6269/* Set up X Session Management Protocol */
6270 void
6271xsmp_init(void)
6272{
6273 char errorstring[80];
6274 char *clientid;
6275 SmcCallbacks smcallbacks;
6276#if 0
6277 SmPropValue smname;
6278 SmProp smnameprop;
6279 SmProp *smprops[1];
6280#endif
6281
6282 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006283 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006284
6285 xsmp.save_yourself = xsmp.shutdown = False;
6286
6287 /* Set up SM callbacks - must have all, even if they're not used */
6288 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6289 smcallbacks.save_yourself.client_data = NULL;
6290 smcallbacks.die.callback = xsmp_die;
6291 smcallbacks.die.client_data = NULL;
6292 smcallbacks.save_complete.callback = xsmp_save_complete;
6293 smcallbacks.save_complete.client_data = NULL;
6294 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6295 smcallbacks.shutdown_cancelled.client_data = NULL;
6296
6297 /* Set up a watch on ICE connection creations. The "dummy" argument is
6298 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6299 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6300 {
6301 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006302 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006303 return;
6304 }
6305
6306 /* Create an SM connection */
6307 xsmp.smcconn = SmcOpenConnection(
6308 NULL,
6309 NULL,
6310 SmProtoMajor,
6311 SmProtoMinor,
6312 SmcSaveYourselfProcMask | SmcDieProcMask
6313 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6314 &smcallbacks,
6315 NULL,
6316 &clientid,
6317 sizeof(errorstring),
6318 errorstring);
6319 if (xsmp.smcconn == NULL)
6320 {
6321 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00006322
Bram Moolenaar071d4272004-06-13 20:20:40 +00006323 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006324 {
6325 vim_snprintf(errorreport, sizeof(errorreport),
6326 _("XSMP SmcOpenConnection failed: %s"), errorstring);
6327 verb_msg((char_u *)errorreport);
6328 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006329 return;
6330 }
6331 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6332
6333#if 0
6334 /* ID ourselves */
6335 smname.value = "vim";
6336 smname.length = 3;
6337 smnameprop.name = "SmProgram";
6338 smnameprop.type = "SmARRAY8";
6339 smnameprop.num_vals = 1;
6340 smnameprop.vals = &smname;
6341
6342 smprops[0] = &smnameprop;
6343 SmcSetProperties(xsmp.smcconn, 1, smprops);
6344#endif
6345}
6346
6347
6348/* Shut down XSMP comms. */
6349 void
6350xsmp_close()
6351{
6352 if (xsmp_icefd != -1)
6353 {
6354 SmcCloseConnection(xsmp.smcconn, 0, NULL);
6355 xsmp_icefd = -1;
6356 }
6357}
6358#endif /* USE_XSMP */
6359
6360
6361#ifdef EBCDIC
6362/* Translate character to its CTRL- value */
6363char CtrlTable[] =
6364{
6365/* 00 - 5E */
6366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6367 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6372/* ^ */ 0x1E,
6373/* - */ 0x1F,
6374/* 61 - 6C */
6375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6376/* _ */ 0x1F,
6377/* 6E - 80 */
6378 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6379/* a */ 0x01,
6380/* b */ 0x02,
6381/* c */ 0x03,
6382/* d */ 0x37,
6383/* e */ 0x2D,
6384/* f */ 0x2E,
6385/* g */ 0x2F,
6386/* h */ 0x16,
6387/* i */ 0x05,
6388/* 8A - 90 */
6389 0, 0, 0, 0, 0, 0, 0,
6390/* j */ 0x15,
6391/* k */ 0x0B,
6392/* l */ 0x0C,
6393/* m */ 0x0D,
6394/* n */ 0x0E,
6395/* o */ 0x0F,
6396/* p */ 0x10,
6397/* q */ 0x11,
6398/* r */ 0x12,
6399/* 9A - A1 */
6400 0, 0, 0, 0, 0, 0, 0, 0,
6401/* s */ 0x13,
6402/* t */ 0x3C,
6403/* u */ 0x3D,
6404/* v */ 0x32,
6405/* w */ 0x26,
6406/* x */ 0x18,
6407/* y */ 0x19,
6408/* z */ 0x3F,
6409/* AA - AC */
6410 0, 0, 0,
6411/* [ */ 0x27,
6412/* AE - BC */
6413 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6414/* ] */ 0x1D,
6415/* BE - C0 */ 0, 0, 0,
6416/* A */ 0x01,
6417/* B */ 0x02,
6418/* C */ 0x03,
6419/* D */ 0x37,
6420/* E */ 0x2D,
6421/* F */ 0x2E,
6422/* G */ 0x2F,
6423/* H */ 0x16,
6424/* I */ 0x05,
6425/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6426/* J */ 0x15,
6427/* K */ 0x0B,
6428/* L */ 0x0C,
6429/* M */ 0x0D,
6430/* N */ 0x0E,
6431/* O */ 0x0F,
6432/* P */ 0x10,
6433/* Q */ 0x11,
6434/* R */ 0x12,
6435/* DA - DF */ 0, 0, 0, 0, 0, 0,
6436/* \ */ 0x1C,
6437/* E1 */ 0,
6438/* S */ 0x13,
6439/* T */ 0x3C,
6440/* U */ 0x3D,
6441/* V */ 0x32,
6442/* W */ 0x26,
6443/* X */ 0x18,
6444/* Y */ 0x19,
6445/* Z */ 0x3F,
6446/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6447 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6448};
6449
6450char MetaCharTable[]=
6451{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6452 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6453 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6454 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6455 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6456};
6457
6458
6459/* TODO: Use characters NOT numbers!!! */
6460char CtrlCharTable[]=
6461{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6462 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6463 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6464 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6465 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6466};
6467
6468
6469#endif