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