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