blob: 07645dc49f3f8d40f61500a991ff6afbdedf3026 [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 Moolenaar4317d9b2005-03-18 20:25:31 +0000370 updatescript(0);
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 )
932 && !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 Moolenaard8b0cf12004-12-12 11:33:30 +00001226handle_signal(sig)
1227 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
2075 STRNCPY((char *)s, cuserid(NULL), len);
2076 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 {
2098 STRNCPY(s, pw->pw_name, len);
Bram Moolenaar051b7822005-05-19 21:00:46 +00002099 s[len - 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002100 return OK;
2101 }
2102#endif
2103 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2104 return FAIL; /* a number is not a name */
2105}
2106
2107/*
2108 * Insert host name is s[len].
2109 */
2110
2111#ifdef HAVE_SYS_UTSNAME_H
2112 void
2113mch_get_host_name(s, len)
2114 char_u *s;
2115 int len;
2116{
2117 struct utsname vutsname;
2118
2119 if (uname(&vutsname) < 0)
2120 *s = NUL;
2121 else
2122 STRNCPY(s, vutsname.nodename, len);
2123 s[len - 1] = NUL; /* make sure it's terminated */
2124}
2125#else /* HAVE_SYS_UTSNAME_H */
2126
2127# ifdef HAVE_SYS_SYSTEMINFO_H
2128# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2129# endif
2130
2131 void
2132mch_get_host_name(s, len)
2133 char_u *s;
2134 int len;
2135{
2136# ifdef VAXC
2137 vaxc$gethostname((char *)s, len);
2138# else
2139 gethostname((char *)s, len);
2140# endif
2141 s[len - 1] = NUL; /* make sure it's terminated */
2142}
2143#endif /* HAVE_SYS_UTSNAME_H */
2144
2145/*
2146 * return process ID
2147 */
2148 long
2149mch_get_pid()
2150{
2151 return (long)getpid();
2152}
2153
2154#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2155static char *strerror __ARGS((int));
2156
2157 static char *
2158strerror(err)
2159 int err;
2160{
2161 extern int sys_nerr;
2162 extern char *sys_errlist[];
2163 static char er[20];
2164
2165 if (err > 0 && err < sys_nerr)
2166 return (sys_errlist[err]);
2167 sprintf(er, "Error %d", err);
2168 return er;
2169}
2170#endif
2171
2172/*
2173 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2174 * Return OK for success, FAIL for failure.
2175 */
2176 int
2177mch_dirname(buf, len)
2178 char_u *buf;
2179 int len;
2180{
2181#if defined(USE_GETCWD)
2182 if (getcwd((char *)buf, len) == NULL)
2183 {
2184 STRCPY(buf, strerror(errno));
2185 return FAIL;
2186 }
2187 return OK;
2188#else
2189 return (getwd((char *)buf) != NULL ? OK : FAIL);
2190#endif
2191}
2192
2193#if defined(OS2) || defined(PROTO)
2194/*
2195 * Replace all slashes by backslashes.
2196 * When 'shellslash' set do it the other way around.
2197 */
2198 void
2199slash_adjust(p)
2200 char_u *p;
2201{
2202 while (*p)
2203 {
2204 if (*p == psepcN)
2205 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002206 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002207 }
2208}
2209#endif
2210
2211/*
2212 * Get absolute file name into buffer 'buf' of length 'len' bytes.
2213 *
2214 * return FAIL for failure, OK for success
2215 */
2216 int
2217mch_FullName(fname, buf, len, force)
2218 char_u *fname, *buf;
2219 int len;
2220 int force; /* also expand when already absolute path */
2221{
2222 int l;
2223#ifdef OS2
2224 int only_drive; /* file name is only a drive letter */
2225#endif
2226#ifdef HAVE_FCHDIR
2227 int fd = -1;
2228 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
2229#endif
2230 char_u olddir[MAXPATHL];
2231 char_u *p;
2232 int retval = OK;
2233
2234#ifdef VMS
2235 fname = vms_fixfilename(fname);
2236#endif
2237
2238 /* expand it if forced or not an absolute path */
2239 if (force || !mch_isFullName(fname))
2240 {
2241 /*
2242 * If the file name has a path, change to that directory for a moment,
2243 * and then do the getwd() (and get back to where we were).
2244 * This will get the correct path name with "../" things.
2245 */
2246#ifdef OS2
2247 only_drive = 0;
2248 if (((p = vim_strrchr(fname, '/')) != NULL)
2249 || ((p = vim_strrchr(fname, '\\')) != NULL)
2250 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
2251#else
2252 if ((p = vim_strrchr(fname, '/')) != NULL)
2253#endif
2254 {
2255#ifdef HAVE_FCHDIR
2256 /*
2257 * Use fchdir() if possible, it's said to be faster and more
2258 * reliable. But on SunOS 4 it might not work. Check this by
2259 * doing a fchdir() right now.
2260 */
2261 if (!dont_fchdir)
2262 {
2263 fd = open(".", O_RDONLY | O_EXTRA, 0);
2264 if (fd >= 0 && fchdir(fd) < 0)
2265 {
2266 close(fd);
2267 fd = -1;
2268 dont_fchdir = TRUE; /* don't try again */
2269 }
2270 }
2271#endif
2272
2273 /* Only change directory when we are sure we can return to where
2274 * we are now. After doing "su" chdir(".") might not work. */
2275 if (
2276#ifdef HAVE_FCHDIR
2277 fd < 0 &&
2278#endif
2279 (mch_dirname(olddir, MAXPATHL) == FAIL
2280 || mch_chdir((char *)olddir) != 0))
2281 {
2282 p = NULL; /* can't get current dir: don't chdir */
2283 retval = FAIL;
2284 }
2285 else
2286 {
2287#ifdef OS2
2288 /*
2289 * compensate for case where ':' from "D:" was the only
2290 * path separator detected in the file name; the _next_
2291 * character has to be removed, and then restored later.
2292 */
2293 if (only_drive)
2294 p++;
2295#endif
2296 /* The directory is copied into buf[], to be able to remove
2297 * the file name without changing it (could be a string in
2298 * read-only memory) */
2299 if (p - fname >= len)
2300 retval = FAIL;
2301 else
2302 {
2303 STRNCPY(buf, fname, p - fname);
2304 buf[p - fname] = NUL;
2305 if (mch_chdir((char *)buf))
2306 retval = FAIL;
2307 else
2308 fname = p + 1;
2309 *buf = NUL;
2310 }
2311#ifdef OS2
2312 if (only_drive)
2313 {
2314 p--;
2315 if (retval != FAIL)
2316 fname--;
2317 }
2318#endif
2319 }
2320 }
2321 if (mch_dirname(buf, len) == FAIL)
2322 {
2323 retval = FAIL;
2324 *buf = NUL;
2325 }
2326 if (p != NULL)
2327 {
2328#ifdef HAVE_FCHDIR
2329 if (fd >= 0)
2330 {
2331 l = fchdir(fd);
2332 close(fd);
2333 }
2334 else
2335#endif
2336 l = mch_chdir((char *)olddir);
2337 if (l != 0)
2338 EMSG(_(e_prev_dir));
2339 }
2340
2341 l = STRLEN(buf);
2342 if (l >= len)
2343 retval = FAIL;
2344#ifndef VMS
2345 else
2346 {
2347 if (l > 0 && buf[l - 1] != '/' && *fname != NUL
2348 && STRCMP(fname, ".") != 0)
2349 STRCAT(buf, "/");
2350 }
2351#endif
2352 }
2353 /* Catch file names which are too long. */
2354 if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len)
2355 return FAIL;
2356
2357 /* Do not append ".", "/dir/." is equal to "/dir". */
2358 if (STRCMP(fname, ".") != 0)
2359 STRCAT(buf, fname);
2360
2361 return OK;
2362}
2363
2364/*
2365 * Return TRUE if "fname" does not depend on the current directory.
2366 */
2367 int
2368mch_isFullName(fname)
2369 char_u *fname;
2370{
2371#ifdef __EMX__
2372 return _fnisabs(fname);
2373#else
2374# ifdef VMS
2375 return ( fname[0] == '/' || fname[0] == '.' ||
2376 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2377 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2378 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2379# else
2380 return (*fname == '/' || *fname == '~');
2381# endif
2382#endif
2383}
2384
2385/*
2386 * Get file permissions for 'name'.
2387 * Returns -1 when it doesn't exist.
2388 */
2389 long
2390mch_getperm(name)
2391 char_u *name;
2392{
2393 struct stat statb;
2394
2395 /* Keep the #ifdef outside of stat(), it may be a macro. */
2396#ifdef VMS
2397 if (stat((char *)vms_fixfilename(name), &statb))
2398#else
2399 if (stat((char *)name, &statb))
2400#endif
2401 return -1;
2402 return statb.st_mode;
2403}
2404
2405/*
2406 * set file permission for 'name' to 'perm'
2407 *
2408 * return FAIL for failure, OK otherwise
2409 */
2410 int
2411mch_setperm(name, perm)
2412 char_u *name;
2413 long perm;
2414{
2415 return (chmod((char *)
2416#ifdef VMS
2417 vms_fixfilename(name),
2418#else
2419 name,
2420#endif
2421 (mode_t)perm) == 0 ? OK : FAIL);
2422}
2423
2424#if defined(HAVE_ACL) || defined(PROTO)
2425# ifdef HAVE_SYS_ACL_H
2426# include <sys/acl.h>
2427# endif
2428# ifdef HAVE_SYS_ACCESS_H
2429# include <sys/access.h>
2430# endif
2431
2432# ifdef HAVE_SOLARIS_ACL
2433typedef struct vim_acl_solaris_T {
2434 int acl_cnt;
2435 aclent_t *acl_entry;
2436} vim_acl_solaris_T;
2437# endif
2438
2439/*
2440 * Return a pointer to the ACL of file "fname" in allocated memory.
2441 * Return NULL if the ACL is not available for whatever reason.
2442 */
2443 vim_acl_T
2444mch_get_acl(fname)
2445 char_u *fname;
2446{
2447 vim_acl_T ret = NULL;
2448#ifdef HAVE_POSIX_ACL
2449 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2450#else
2451#ifdef HAVE_SOLARIS_ACL
2452 vim_acl_solaris_T *aclent;
2453
2454 aclent = malloc(sizeof(vim_acl_solaris_T));
2455 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2456 {
2457 free(aclent);
2458 return NULL;
2459 }
2460 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2461 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2462 {
2463 free(aclent->acl_entry);
2464 free(aclent);
2465 return NULL;
2466 }
2467 ret = (vim_acl_T)aclent;
2468#else
2469#if defined(HAVE_AIX_ACL)
2470 int aclsize;
2471 struct acl *aclent;
2472
2473 aclsize = sizeof(struct acl);
2474 aclent = malloc(aclsize);
2475 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2476 {
2477 if (errno == ENOSPC)
2478 {
2479 aclsize = aclent->acl_len;
2480 aclent = realloc(aclent, aclsize);
2481 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2482 {
2483 free(aclent);
2484 return NULL;
2485 }
2486 }
2487 else
2488 {
2489 free(aclent);
2490 return NULL;
2491 }
2492 }
2493 ret = (vim_acl_T)aclent;
2494#endif /* HAVE_AIX_ACL */
2495#endif /* HAVE_SOLARIS_ACL */
2496#endif /* HAVE_POSIX_ACL */
2497 return ret;
2498}
2499
2500/*
2501 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2502 */
2503 void
2504mch_set_acl(fname, aclent)
2505 char_u *fname;
2506 vim_acl_T aclent;
2507{
2508 if (aclent == NULL)
2509 return;
2510#ifdef HAVE_POSIX_ACL
2511 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2512#else
2513#ifdef HAVE_SOLARIS_ACL
2514 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2515 ((vim_acl_solaris_T *)aclent)->acl_entry);
2516#else
2517#ifdef HAVE_AIX_ACL
2518 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2519#endif /* HAVE_AIX_ACL */
2520#endif /* HAVE_SOLARIS_ACL */
2521#endif /* HAVE_POSIX_ACL */
2522}
2523
2524 void
2525mch_free_acl(aclent)
2526 vim_acl_T aclent;
2527{
2528 if (aclent == NULL)
2529 return;
2530#ifdef HAVE_POSIX_ACL
2531 acl_free((acl_t)aclent);
2532#else
2533#ifdef HAVE_SOLARIS_ACL
2534 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2535 free(aclent);
2536#else
2537#ifdef HAVE_AIX_ACL
2538 free(aclent);
2539#endif /* HAVE_AIX_ACL */
2540#endif /* HAVE_SOLARIS_ACL */
2541#endif /* HAVE_POSIX_ACL */
2542}
2543#endif
2544
2545/*
2546 * Set hidden flag for "name".
2547 */
2548/* ARGSUSED */
2549 void
2550mch_hide(name)
2551 char_u *name;
2552{
2553 /* can't hide a file */
2554}
2555
2556/*
2557 * return TRUE if "name" is a directory
2558 * return FALSE if "name" is not a directory
2559 * return FALSE for error
2560 */
2561 int
2562mch_isdir(name)
2563 char_u *name;
2564{
2565 struct stat statb;
2566
2567 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2568 return FALSE;
2569 if (stat((char *)name, &statb))
2570 return FALSE;
2571#ifdef _POSIX_SOURCE
2572 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2573#else
2574 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2575#endif
2576}
2577
2578#if defined(FEAT_EVAL) || defined(PROTO)
2579
2580static int executable_file __ARGS((char_u *name));
2581
2582/*
2583 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2584 */
2585 static int
2586executable_file(name)
2587 char_u *name;
2588{
2589 struct stat st;
2590
2591 if (stat((char *)name, &st))
2592 return 0;
2593 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2594}
2595
2596/*
2597 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2598 * Return -1 if unknown.
2599 */
2600 int
2601mch_can_exe(name)
2602 char_u *name;
2603{
2604 char_u *buf;
2605 char_u *p, *e;
2606 int retval;
2607
2608 /* If it's an absolute or relative path don't need to use $PATH. */
2609 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2610 || (name[1] == '.' && name[2] == '/'))))
2611 return executable_file(name);
2612
2613 p = (char_u *)getenv("PATH");
2614 if (p == NULL || *p == NUL)
2615 return -1;
2616 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2617 if (buf == NULL)
2618 return -1;
2619
2620 /*
2621 * Walk through all entries in $PATH to check if "name" exists there and
2622 * is an executable file.
2623 */
2624 for (;;)
2625 {
2626 e = (char_u *)strchr((char *)p, ':');
2627 if (e == NULL)
2628 e = p + STRLEN(p);
2629 if (e - p <= 1) /* empty entry means current dir */
2630 STRCPY(buf, "./");
2631 else
2632 {
2633 STRNCPY(buf, p, e - p);
2634 buf[e - p] = NUL;
2635 add_pathsep(buf);
2636 }
2637 STRCAT(buf, name);
2638 retval = executable_file(buf);
2639 if (retval == 1)
2640 break;
2641
2642 if (*e != ':')
2643 break;
2644 p = e + 1;
2645 }
2646
2647 vim_free(buf);
2648 return retval;
2649}
2650#endif
2651
2652/*
2653 * Check what "name" is:
2654 * NODE_NORMAL: file or directory (or doesn't exist)
2655 * NODE_WRITABLE: writable device, socket, fifo, etc.
2656 * NODE_OTHER: non-writable things
2657 */
2658 int
2659mch_nodetype(name)
2660 char_u *name;
2661{
2662 struct stat st;
2663
2664 if (stat((char *)name, &st))
2665 return NODE_NORMAL;
2666 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2667 return NODE_NORMAL;
2668#ifndef OS2
2669 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2670 return NODE_OTHER;
2671#endif
2672 /* Everything else is writable? */
2673 return NODE_WRITABLE;
2674}
2675
2676 void
2677mch_early_init()
2678{
2679#ifdef HAVE_CHECK_STACK_GROWTH
2680 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002681
Bram Moolenaar071d4272004-06-13 20:20:40 +00002682 check_stack_growth((char *)&i);
2683
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002684# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002685 get_stack_limit();
2686# endif
2687
2688#endif
2689
2690 /*
2691 * Setup an alternative stack for signals. Helps to catch signals when
2692 * running out of stack space.
2693 * Use of sigaltstack() is preferred, it's more portable.
2694 * Ignore any errors.
2695 */
2696#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2697 signal_stack = malloc(SIGSTKSZ);
2698 init_signal_stack();
2699#endif
2700}
2701
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002702#if defined(EXITFREE) || defined(PROTO)
2703 void
2704mch_free_mem()
2705{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002706# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2707 if (clip_star.owned)
2708 clip_lose_selection(&clip_star);
2709 if (clip_plus.owned)
2710 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002711# endif
2712# if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
2713 if (xterm_Shell != (Widget)0)
2714 XtDestroyWidget(xterm_Shell);
2715 if (xterm_dpy != NULL)
2716 XtCloseDisplay(xterm_dpy);
2717 if (app_context != (XtAppContext)NULL)
2718 XtDestroyApplicationContext(app_context);
2719# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002720# ifdef FEAT_X11
2721 if (x11_display != NULL && x11_display != xterm_dpy)
2722 XCloseDisplay(x11_display);
2723# endif
2724# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2725 vim_free(signal_stack);
2726 signal_stack = NULL;
2727# endif
2728# ifdef FEAT_TITLE
2729 vim_free(oldtitle);
2730 vim_free(oldicon);
2731# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002732}
2733#endif
2734
Bram Moolenaar071d4272004-06-13 20:20:40 +00002735static void exit_scroll __ARGS((void));
2736
2737/*
2738 * Output a newline when exiting.
2739 * Make sure the newline goes to the same stream as the text.
2740 */
2741 static void
2742exit_scroll()
2743{
Bram Moolenaardf177f62005-02-22 08:39:57 +00002744 if (silent_mode)
2745 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002746 if (newline_on_exit || msg_didout)
2747 {
2748 if (msg_use_printf())
2749 {
2750 if (info_message)
2751 mch_msg("\n");
2752 else
2753 mch_errmsg("\r\n");
2754 }
2755 else
2756 out_char('\n');
2757 }
2758 else
2759 {
2760 restore_cterm_colors(); /* get original colors back */
2761 msg_clr_eos_force(); /* clear the rest of the display */
2762 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
2763 }
2764}
2765
2766 void
2767mch_exit(r)
2768 int r;
2769{
2770 exiting = TRUE;
2771
2772#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
2773 x11_export_final_selection();
2774#endif
2775
2776#ifdef FEAT_GUI
2777 if (!gui.in_use)
2778#endif
2779 {
2780 settmode(TMODE_COOK);
2781#ifdef FEAT_TITLE
2782 mch_restore_title(3); /* restore xterm title and icon name */
2783#endif
2784 /*
2785 * When t_ti is not empty but it doesn't cause swapping terminal
2786 * pages, need to output a newline when msg_didout is set. But when
2787 * t_ti does swap pages it should not go to the shell page. Do this
2788 * before stoptermcap().
2789 */
2790 if (swapping_screen() && !newline_on_exit)
2791 exit_scroll();
2792
2793 /* Stop termcap: May need to check for T_CRV response, which
2794 * requires RAW mode. */
2795 stoptermcap();
2796
2797 /*
2798 * A newline is only required after a message in the alternate screen.
2799 * This is set to TRUE by wait_return().
2800 */
2801 if (!swapping_screen() || newline_on_exit)
2802 exit_scroll();
2803
2804 /* Cursor may have been switched off without calling starttermcap()
2805 * when doing "vim -u vimrc" and vimrc contains ":q". */
2806 if (full_screen)
2807 cursor_on();
2808 }
2809 out_flush();
2810 ml_close_all(TRUE); /* remove all memfiles */
2811 may_core_dump();
2812#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002813 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002814 gui_exit(r);
2815#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00002816
2817#if defined(MACOS_X) && defined(FEAT_MBYTE)
2818 mac_conv_cleanup();
2819#endif
2820
Bram Moolenaar071d4272004-06-13 20:20:40 +00002821#ifdef __QNX__
2822 /* A core dump won't be created if the signal handler
2823 * doesn't return, so we can't call exit() */
2824 if (deadly_signal != 0)
2825 return;
2826#endif
2827
Bram Moolenaar009b2592004-10-24 19:18:58 +00002828#ifdef FEAT_NETBEANS_INTG
2829 if (usingNetbeans)
2830 netbeans_send_disconnect();
2831#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002832
2833#ifdef EXITFREE
2834 free_all_mem();
2835#endif
2836
Bram Moolenaar071d4272004-06-13 20:20:40 +00002837 exit(r);
2838}
2839
2840 static void
2841may_core_dump()
2842{
2843 if (deadly_signal != 0)
2844 {
2845 signal(deadly_signal, SIG_DFL);
2846 kill(getpid(), deadly_signal); /* Die using the signal we caught */
2847 }
2848}
2849
2850#ifndef VMS
2851
2852 void
2853mch_settmode(tmode)
2854 int tmode;
2855{
2856 static int first = TRUE;
2857
2858 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2859#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2860 /*
2861 * for "new" tty systems
2862 */
2863# ifdef HAVE_TERMIOS_H
2864 static struct termios told;
2865 struct termios tnew;
2866# else
2867 static struct termio told;
2868 struct termio tnew;
2869# endif
2870
2871 if (first)
2872 {
2873 first = FALSE;
2874# if defined(HAVE_TERMIOS_H)
2875 tcgetattr(read_cmd_fd, &told);
2876# else
2877 ioctl(read_cmd_fd, TCGETA, &told);
2878# endif
2879 }
2880
2881 tnew = told;
2882 if (tmode == TMODE_RAW)
2883 {
2884 /*
2885 * ~ICRNL enables typing ^V^M
2886 */
2887 tnew.c_iflag &= ~ICRNL;
2888 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
2889# if defined(IEXTEN) && !defined(__MINT__)
2890 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
2891 /* but it breaks function keys on MINT */
2892# endif
2893 );
2894# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
2895 tnew.c_oflag &= ~ONLCR;
2896# endif
2897 tnew.c_cc[VMIN] = 1; /* return after 1 char */
2898 tnew.c_cc[VTIME] = 0; /* don't wait */
2899 }
2900 else if (tmode == TMODE_SLEEP)
2901 tnew.c_lflag &= ~(ECHO);
2902
2903# if defined(HAVE_TERMIOS_H)
2904 {
2905 int n = 10;
2906
2907 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
2908 * few times. */
2909 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
2910 && errno == EINTR && n > 0)
2911 --n;
2912 }
2913# else
2914 ioctl(read_cmd_fd, TCSETA, &tnew);
2915# endif
2916
2917#else
2918
2919 /*
2920 * for "old" tty systems
2921 */
2922# ifndef TIOCSETN
2923# define TIOCSETN TIOCSETP /* for hpux 9.0 */
2924# endif
2925 static struct sgttyb ttybold;
2926 struct sgttyb ttybnew;
2927
2928 if (first)
2929 {
2930 first = FALSE;
2931 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
2932 }
2933
2934 ttybnew = ttybold;
2935 if (tmode == TMODE_RAW)
2936 {
2937 ttybnew.sg_flags &= ~(CRMOD | ECHO);
2938 ttybnew.sg_flags |= RAW;
2939 }
2940 else if (tmode == TMODE_SLEEP)
2941 ttybnew.sg_flags &= ~(ECHO);
2942 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
2943#endif
2944 curr_tmode = tmode;
2945}
2946
2947/*
2948 * Try to get the code for "t_kb" from the stty setting
2949 *
2950 * Even if termcap claims a backspace key, the user's setting *should*
2951 * prevail. stty knows more about reality than termcap does, and if
2952 * somebody's usual erase key is DEL (which, for most BSD users, it will
2953 * be), they're going to get really annoyed if their erase key starts
2954 * doing forward deletes for no reason. (Eric Fischer)
2955 */
2956 void
2957get_stty()
2958{
2959 char_u buf[2];
2960 char_u *p;
2961
2962 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2963#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2964 /* for "new" tty systems */
2965# ifdef HAVE_TERMIOS_H
2966 struct termios keys;
2967# else
2968 struct termio keys;
2969# endif
2970
2971# if defined(HAVE_TERMIOS_H)
2972 if (tcgetattr(read_cmd_fd, &keys) != -1)
2973# else
2974 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
2975# endif
2976 {
2977 buf[0] = keys.c_cc[VERASE];
2978 intr_char = keys.c_cc[VINTR];
2979#else
2980 /* for "old" tty systems */
2981 struct sgttyb keys;
2982
2983 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
2984 {
2985 buf[0] = keys.sg_erase;
2986 intr_char = keys.sg_kill;
2987#endif
2988 buf[1] = NUL;
2989 add_termcode((char_u *)"kb", buf, FALSE);
2990
2991 /*
2992 * If <BS> and <DEL> are now the same, redefine <DEL>.
2993 */
2994 p = find_termcode((char_u *)"kD");
2995 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
2996 do_fixdel(NULL);
2997 }
2998#if 0
2999 } /* to keep cindent happy */
3000#endif
3001}
3002
3003#endif /* VMS */
3004
3005#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3006/*
3007 * Set mouse clicks on or off.
3008 */
3009 void
3010mch_setmouse(on)
3011 int on;
3012{
3013 static int ison = FALSE;
3014 int xterm_mouse_vers;
3015
3016 if (on == ison) /* return quickly if nothing to do */
3017 return;
3018
3019 xterm_mouse_vers = use_xterm_mouse();
3020 if (xterm_mouse_vers > 0)
3021 {
3022 if (on) /* enable mouse events, use mouse tracking if available */
3023 out_str_nf((char_u *)
3024 (xterm_mouse_vers > 1
3025 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3026 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3027 else /* disable mouse events, could probably always send the same */
3028 out_str_nf((char_u *)
3029 (xterm_mouse_vers > 1
3030 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3031 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3032 ison = on;
3033 }
3034
3035# ifdef FEAT_MOUSE_DEC
3036 else if (ttym_flags == TTYM_DEC)
3037 {
3038 if (on) /* enable mouse events */
3039 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3040 else /* disable mouse events */
3041 out_str_nf((char_u *)"\033['z");
3042 ison = on;
3043 }
3044# endif
3045
3046# ifdef FEAT_MOUSE_GPM
3047 else
3048 {
3049 if (on)
3050 {
3051 if (gpm_open())
3052 ison = TRUE;
3053 }
3054 else
3055 {
3056 gpm_close();
3057 ison = FALSE;
3058 }
3059 }
3060# endif
3061
3062# ifdef FEAT_MOUSE_JSB
3063 else
3064 {
3065 if (on)
3066 {
3067 /* D - Enable Mouse up/down messages
3068 * L - Enable Left Button Reporting
3069 * M - Enable Middle Button Reporting
3070 * R - Enable Right Button Reporting
3071 * K - Enable SHIFT and CTRL key Reporting
3072 * + - Enable Advanced messaging of mouse moves and up/down messages
3073 * Q - Quiet No Ack
3074 * # - Numeric value of mouse pointer required
3075 * 0 = Multiview 2000 cursor, used as standard
3076 * 1 = Windows Arrow
3077 * 2 = Windows I Beam
3078 * 3 = Windows Hour Glass
3079 * 4 = Windows Cross Hair
3080 * 5 = Windows UP Arrow
3081 */
3082#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3083 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3084 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3085#else
3086 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3087 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3088#endif
3089 ison = TRUE;
3090 }
3091 else
3092 {
3093 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3094 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3095 ison = FALSE;
3096 }
3097 }
3098# endif
3099# ifdef FEAT_MOUSE_PTERM
3100 else
3101 {
3102 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3103 if (on)
3104 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3105 else
3106 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3107 ison = on;
3108 }
3109# endif
3110}
3111
3112/*
3113 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3114 */
3115 void
3116check_mouse_termcode()
3117{
3118# ifdef FEAT_MOUSE_XTERM
3119 if (use_xterm_mouse()
3120# ifdef FEAT_GUI
3121 && !gui.in_use
3122# endif
3123 )
3124 {
3125 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003126 ? IF_EB("\233M", CSI_STR "M")
3127 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003128 if (*p_mouse != NUL)
3129 {
3130 /* force mouse off and maybe on to send possibly new mouse
3131 * activation sequence to the xterm, with(out) drag tracing. */
3132 mch_setmouse(FALSE);
3133 setmouse();
3134 }
3135 }
3136 else
3137 del_mouse_termcode(KS_MOUSE);
3138# endif
3139
3140# ifdef FEAT_MOUSE_GPM
3141 if (!use_xterm_mouse()
3142# ifdef FEAT_GUI
3143 && !gui.in_use
3144# endif
3145 )
3146 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3147# endif
3148
3149# ifdef FEAT_MOUSE_JSB
3150 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3151 if (!use_xterm_mouse()
3152# ifdef FEAT_GUI
3153 && !gui.in_use
3154# endif
3155 )
3156 set_mouse_termcode(KS_JSBTERM_MOUSE,
3157 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3158 else
3159 del_mouse_termcode(KS_JSBTERM_MOUSE);
3160# endif
3161
3162# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003163 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003164 * define it in the GUI or when using an xterm. */
3165 if (!use_xterm_mouse()
3166# ifdef FEAT_GUI
3167 && !gui.in_use
3168# endif
3169 )
3170 set_mouse_termcode(KS_NETTERM_MOUSE,
3171 (char_u *)IF_EB("\033}", ESC_STR "}"));
3172 else
3173 del_mouse_termcode(KS_NETTERM_MOUSE);
3174# endif
3175
3176# ifdef FEAT_MOUSE_DEC
3177 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3178 if (!use_xterm_mouse()
3179# ifdef FEAT_GUI
3180 && !gui.in_use
3181# endif
3182 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003183 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3184 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003185 else
3186 del_mouse_termcode(KS_DEC_MOUSE);
3187# endif
3188# ifdef FEAT_MOUSE_PTERM
3189 /* same as the dec mouse */
3190 if (!use_xterm_mouse()
3191# ifdef FEAT_GUI
3192 && !gui.in_use
3193# endif
3194 )
3195 set_mouse_termcode(KS_PTERM_MOUSE,
3196 (char_u *) IF_EB("\033[", ESC_STR "["));
3197 else
3198 del_mouse_termcode(KS_PTERM_MOUSE);
3199# endif
3200}
3201#endif
3202
3203/*
3204 * set screen mode, always fails.
3205 */
3206/* ARGSUSED */
3207 int
3208mch_screenmode(arg)
3209 char_u *arg;
3210{
3211 EMSG(_(e_screenmode));
3212 return FAIL;
3213}
3214
3215#ifndef VMS
3216
3217/*
3218 * Try to get the current window size:
3219 * 1. with an ioctl(), most accurate method
3220 * 2. from the environment variables LINES and COLUMNS
3221 * 3. from the termcap
3222 * 4. keep using the old values
3223 * Return OK when size could be determined, FAIL otherwise.
3224 */
3225 int
3226mch_get_shellsize()
3227{
3228 long rows = 0;
3229 long columns = 0;
3230 char_u *p;
3231
3232 /*
3233 * For OS/2 use _scrsize().
3234 */
3235# ifdef __EMX__
3236 {
3237 int s[2];
3238
3239 _scrsize(s);
3240 columns = s[0];
3241 rows = s[1];
3242 }
3243# endif
3244
3245 /*
3246 * 1. try using an ioctl. It is the most accurate method.
3247 *
3248 * Try using TIOCGWINSZ first, some systems that have it also define
3249 * TIOCGSIZE but don't have a struct ttysize.
3250 */
3251# ifdef TIOCGWINSZ
3252 {
3253 struct winsize ws;
3254 int fd = 1;
3255
3256 /* When stdout is not a tty, use stdin for the ioctl(). */
3257 if (!isatty(fd) && isatty(read_cmd_fd))
3258 fd = read_cmd_fd;
3259 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3260 {
3261 columns = ws.ws_col;
3262 rows = ws.ws_row;
3263 }
3264 }
3265# else /* TIOCGWINSZ */
3266# ifdef TIOCGSIZE
3267 {
3268 struct ttysize ts;
3269 int fd = 1;
3270
3271 /* When stdout is not a tty, use stdin for the ioctl(). */
3272 if (!isatty(fd) && isatty(read_cmd_fd))
3273 fd = read_cmd_fd;
3274 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3275 {
3276 columns = ts.ts_cols;
3277 rows = ts.ts_lines;
3278 }
3279 }
3280# endif /* TIOCGSIZE */
3281# endif /* TIOCGWINSZ */
3282
3283 /*
3284 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003285 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3286 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003287 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003288 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003289 {
3290 if ((p = (char_u *)getenv("LINES")))
3291 rows = atoi((char *)p);
3292 if ((p = (char_u *)getenv("COLUMNS")))
3293 columns = atoi((char *)p);
3294 }
3295
3296#ifdef HAVE_TGETENT
3297 /*
3298 * 3. try reading "co" and "li" entries from termcap
3299 */
3300 if (columns == 0 || rows == 0)
3301 getlinecol(&columns, &rows);
3302#endif
3303
3304 /*
3305 * 4. If everything fails, use the old values
3306 */
3307 if (columns <= 0 || rows <= 0)
3308 return FAIL;
3309
3310 Rows = rows;
3311 Columns = columns;
3312 return OK;
3313}
3314
3315/*
3316 * Try to set the window size to Rows and Columns.
3317 */
3318 void
3319mch_set_shellsize()
3320{
3321 if (*T_CWS)
3322 {
3323 /*
3324 * NOTE: if you get an error here that term_set_winsize() is
3325 * undefined, check the output of configure. It could probably not
3326 * find a ncurses, termcap or termlib library.
3327 */
3328 term_set_winsize((int)Rows, (int)Columns);
3329 out_flush();
3330 screen_start(); /* don't know where cursor is now */
3331 }
3332}
3333
3334#endif /* VMS */
3335
3336/*
3337 * Rows and/or Columns has changed.
3338 */
3339 void
3340mch_new_shellsize()
3341{
3342 /* Nothing to do. */
3343}
3344
Bram Moolenaardf177f62005-02-22 08:39:57 +00003345#ifndef USE_SYSTEM
3346static void append_ga_line __ARGS((garray_T *gap));
3347
3348/*
3349 * Append the text in "gap" below the cursor line and clear "gap".
3350 */
3351 static void
3352append_ga_line(gap)
3353 garray_T *gap;
3354{
3355 /* Remove trailing CR. */
3356 if (gap->ga_len > 0
3357 && !curbuf->b_p_bin
3358 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3359 --gap->ga_len;
3360 ga_append(gap, NUL);
3361 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3362 gap->ga_len = 0;
3363}
3364#endif
3365
Bram Moolenaar071d4272004-06-13 20:20:40 +00003366 int
3367mch_call_shell(cmd, options)
3368 char_u *cmd;
3369 int options; /* SHELL_*, see vim.h */
3370{
3371#ifdef VMS
3372 char *ifn = NULL;
3373 char *ofn = NULL;
3374#endif
3375 int tmode = cur_tmode;
3376#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3377 int x;
3378# ifndef __EMX__
3379 char_u *newcmd; /* only needed for unix */
3380# else
3381 /*
3382 * Set the preferred shell in the EMXSHELL environment variable (but
3383 * only if it is different from what is already in the environment).
3384 * Emx then takes care of whether to use "/c" or "-c" in an
3385 * intelligent way. Simply pass the whole thing to emx's system() call.
3386 * Emx also starts an interactive shell if system() is passed an empty
3387 * string.
3388 */
3389 char_u *p, *old;
3390
3391 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3392 {
3393 /* should check HAVE_SETENV, but I know we don't have it. */
3394 p = alloc(10 + strlen(p_sh));
3395 if (p)
3396 {
3397 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3398 putenv((char *)p); /* don't free the pointer! */
3399 }
3400 }
3401# endif
3402
3403 out_flush();
3404
3405 if (options & SHELL_COOKED)
3406 settmode(TMODE_COOK); /* set to normal mode */
3407
3408# ifdef __EMX__
3409 if (cmd == NULL)
3410 x = system(""); /* this starts an interactive shell in emx */
3411 else
3412 x = system((char *)cmd);
3413 /* system() returns -1 when error occurs in starting shell */
3414 if (x == -1 && !emsg_silent)
3415 {
3416 MSG_PUTS(_("\nCannot execute shell "));
3417 msg_outtrans(p_sh);
3418 msg_putchar('\n');
3419 }
3420# else /* not __EMX__ */
3421 if (cmd == NULL)
3422 x = system((char *)p_sh);
3423 else
3424 {
3425# ifdef VMS
3426 if (ofn = strchr((char *)cmd, '>'))
3427 *ofn++ = '\0';
3428 if (ifn = strchr((char *)cmd, '<'))
3429 {
3430 char *p;
3431
3432 *ifn++ = '\0';
3433 p = strchr(ifn,' '); /* chop off any trailing spaces */
3434 if (p)
3435 *p = '\0';
3436 }
3437 if (ofn)
3438 x = vms_sys((char *)cmd, ofn, ifn);
3439 else
3440 x = system((char *)cmd);
3441# else
3442 newcmd = lalloc(STRLEN(p_sh)
3443 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3444 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3445 if (newcmd == NULL)
3446 x = 0;
3447 else
3448 {
3449 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3450 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3451 (char *)p_shcf,
3452 (char *)cmd);
3453 x = system((char *)newcmd);
3454 vim_free(newcmd);
3455 }
3456# endif
3457 }
3458# ifdef VMS
3459 x = vms_sys_status(x);
3460# endif
3461 if (emsg_silent)
3462 ;
3463 else if (x == 127)
3464 MSG_PUTS(_("\nCannot execute shell sh\n"));
3465# endif /* __EMX__ */
3466 else if (x && !(options & SHELL_SILENT))
3467 {
3468 MSG_PUTS(_("\nshell returned "));
3469 msg_outnum((long)x);
3470 msg_putchar('\n');
3471 }
3472
3473 if (tmode == TMODE_RAW)
3474 settmode(TMODE_RAW); /* set to raw mode */
3475# ifdef FEAT_TITLE
3476 resettitle();
3477# endif
3478 return x;
3479
3480#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3481
Bram Moolenaardf177f62005-02-22 08:39:57 +00003482# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3483 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484
3485 char_u *newcmd = NULL;
3486 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003487 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003488 pid_t wait_pid = 0;
3489# ifdef HAVE_UNION_WAIT
3490 union wait status;
3491# else
3492 int status = -1;
3493# endif
3494 int retval = -1;
3495 char **argv = NULL;
3496 int argc;
3497 int i;
3498 char_u *p;
3499 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003500 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003501# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003502 int pty_slave_fd = -1;
3503 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003504# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003505 int fd_toshell[2]; /* for pipes */
3506 int fd_fromshell[2];
3507 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003508# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003509 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003510# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511 static char envbuf_Rows[20];
3512 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003513# endif
3514 int did_settmode = FALSE; /* TRUE when settmode(TMODE_RAW) called */
3515
3516 out_flush();
3517 if (options & SHELL_COOKED)
3518 settmode(TMODE_COOK); /* set to normal mode */
3519
3520 /*
3521 * 1: find number of arguments
3522 * 2: separate them and built argv[]
3523 */
3524 newcmd = vim_strsave(p_sh);
3525 if (newcmd == NULL) /* out of memory */
3526 goto error;
3527 for (i = 0; i < 2; ++i)
3528 {
3529 p = newcmd;
3530 inquote = FALSE;
3531 argc = 0;
3532 for (;;)
3533 {
3534 if (i == 1)
3535 argv[argc] = (char *)p;
3536 ++argc;
3537 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3538 {
3539 if (*p == '"')
3540 inquote = !inquote;
3541 ++p;
3542 }
3543 if (*p == NUL)
3544 break;
3545 if (i == 1)
3546 *p++ = NUL;
3547 p = skipwhite(p);
3548 }
3549 if (i == 0)
3550 {
3551 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3552 if (argv == NULL) /* out of memory */
3553 goto error;
3554 }
3555 }
3556 if (cmd != NULL)
3557 {
3558 if (extra_shell_arg != NULL)
3559 argv[argc++] = (char *)extra_shell_arg;
3560 argv[argc++] = (char *)p_shcf;
3561 argv[argc++] = (char *)cmd;
3562 }
3563 argv[argc] = NULL;
3564
Bram Moolenaar071d4272004-06-13 20:20:40 +00003565 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003566 * For the GUI, when writing the output into the buffer and when reading
3567 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3568 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003570 if ((options & (SHELL_READ|SHELL_WRITE))
3571# ifdef FEAT_GUI
3572 || (gui.in_use && show_shell_mess)
3573# endif
3574 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003575 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003576# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003577 /*
3578 * Try to open a master pty.
3579 * If this works, open the slave pty.
3580 * If the slave can't be opened, close the master pty.
3581 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003582 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003583 {
3584 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3585 if (pty_master_fd >= 0 && ((pty_slave_fd =
3586 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3587 {
3588 close(pty_master_fd);
3589 pty_master_fd = -1;
3590 }
3591 }
3592 /*
3593 * If not opening a pty or it didn't work, try using pipes.
3594 */
3595 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003596# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597 {
3598 pipe_error = (pipe(fd_toshell) < 0);
3599 if (!pipe_error) /* pipe create OK */
3600 {
3601 pipe_error = (pipe(fd_fromshell) < 0);
3602 if (pipe_error) /* pipe create failed */
3603 {
3604 close(fd_toshell[0]);
3605 close(fd_toshell[1]);
3606 }
3607 }
3608 if (pipe_error)
3609 {
3610 MSG_PUTS(_("\nCannot create pipes\n"));
3611 out_flush();
3612 }
3613 }
3614 }
3615
3616 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617 {
3618# ifdef __BEOS__
3619 beos_cleanup_read_thread();
3620# endif
3621 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3622 {
3623 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003624 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003625# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003626 || (gui.in_use && show_shell_mess)
3627# endif
3628 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003629 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003630# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003631 if (pty_master_fd >= 0) /* close the pseudo tty */
3632 {
3633 close(pty_master_fd);
3634 close(pty_slave_fd);
3635 }
3636 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003637# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003638 {
3639 close(fd_toshell[0]);
3640 close(fd_toshell[1]);
3641 close(fd_fromshell[0]);
3642 close(fd_fromshell[1]);
3643 }
3644 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003645 }
3646 else if (pid == 0) /* child */
3647 {
3648 reset_signals(); /* handle signals normally */
3649
3650 if (!show_shell_mess || (options & SHELL_EXPAND))
3651 {
3652 int fd;
3653
3654 /*
3655 * Don't want to show any message from the shell. Can't just
3656 * close stdout and stderr though, because some systems will
3657 * break if you try to write to them after that, so we must
3658 * use dup() to replace them with something else -- webb
3659 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3660 * waiting for input.
3661 */
3662 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3663 fclose(stdin);
3664 fclose(stdout);
3665 fclose(stderr);
3666
3667 /*
3668 * If any of these open()'s and dup()'s fail, we just continue
3669 * anyway. It's not fatal, and on most systems it will make
3670 * no difference at all. On a few it will cause the execvp()
3671 * to exit with a non-zero status even when the completion
3672 * could be done, which is nothing too serious. If the open()
3673 * or dup() failed we'd just do the same thing ourselves
3674 * anyway -- webb
3675 */
3676 if (fd >= 0)
3677 {
3678 dup(fd); /* To replace stdin (file descriptor 0) */
3679 dup(fd); /* To replace stdout (file descriptor 1) */
3680 dup(fd); /* To replace stderr (file descriptor 2) */
3681
3682 /* Don't need this now that we've duplicated it */
3683 close(fd);
3684 }
3685 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003686 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003687# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003688 || gui.in_use
3689# endif
3690 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003691 {
3692
Bram Moolenaardf177f62005-02-22 08:39:57 +00003693# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00003694 (void)setsid();
Bram Moolenaardf177f62005-02-22 08:39:57 +00003695# endif
3696# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003697 /* push stream discipline modules */
3698 if (options & SHELL_COOKED)
3699 SetupSlavePTY(pty_slave_fd);
3700# ifdef TIOCSCTTY
3701 /* try to become controlling tty (probably doesn't work,
3702 * unless run by root) */
3703 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
3704# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003705# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003706 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003707# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003708 setenv("TERM", "dumb", 1);
3709 sprintf((char *)envbuf, "%ld", Rows);
3710 setenv("ROWS", (char *)envbuf, 1);
3711 sprintf((char *)envbuf, "%ld", Rows);
3712 setenv("LINES", (char *)envbuf, 1);
3713 sprintf((char *)envbuf, "%ld", Columns);
3714 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003715# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716 /*
3717 * Putenv does not copy the string, it has to remain valid.
3718 * Use a static array to avoid loosing allocated memory.
3719 */
3720 putenv("TERM=dumb");
3721 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
3722 putenv(envbuf_Rows);
3723 sprintf(envbuf_Rows, "LINES=%ld", Rows);
3724 putenv(envbuf_Rows);
3725 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
3726 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003727# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003728
Bram Moolenaardf177f62005-02-22 08:39:57 +00003729# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003730 if (pty_master_fd >= 0)
3731 {
3732 close(pty_master_fd); /* close master side of pty */
3733
3734 /* set up stdin/stdout/stderr for the child */
3735 close(0);
3736 dup(pty_slave_fd);
3737 close(1);
3738 dup(pty_slave_fd);
3739 close(2);
3740 dup(pty_slave_fd);
3741
3742 close(pty_slave_fd); /* has been dupped, close it now */
3743 }
3744 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003745# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003746 {
3747 /* set up stdin for the child */
3748 close(fd_toshell[1]);
3749 close(0);
3750 dup(fd_toshell[0]);
3751 close(fd_toshell[0]);
3752
3753 /* set up stdout for the child */
3754 close(fd_fromshell[0]);
3755 close(1);
3756 dup(fd_fromshell[1]);
3757 close(fd_fromshell[1]);
3758
3759 /* set up stderr for the child */
3760 close(2);
3761 dup(1);
3762 }
3763 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003764
Bram Moolenaar071d4272004-06-13 20:20:40 +00003765 /*
3766 * There is no type cast for the argv, because the type may be
3767 * different on different machines. This may cause a warning
3768 * message with strict compilers, don't worry about it.
3769 * Call _exit() instead of exit() to avoid closing the connection
3770 * to the X server (esp. with GTK, which uses atexit()).
3771 */
3772 execvp(argv[0], argv);
3773 _exit(EXEC_FAILED); /* exec failed, return failure code */
3774 }
3775 else /* parent */
3776 {
3777 /*
3778 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003779 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003780 */
3781 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003782 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783
3784 /*
3785 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003786 * This is also used to pipe stdin/stdout to/from the external
3787 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003788 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003789 if ((options & (SHELL_READ|SHELL_WRITE))
3790# ifdef FEAT_GUI
3791 || (gui.in_use && show_shell_mess)
3792# endif
3793 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003794 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003795# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003796 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003797# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003799# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003800 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
3801 int ta_len = 0; /* valid bytes in ta_buf[] */
3802 int len;
3803 int p_more_save;
3804 int old_State;
3805 int c;
3806 int toshell_fd;
3807 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003808 garray_T ga;
3809 int noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003810
Bram Moolenaardf177f62005-02-22 08:39:57 +00003811# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003812 if (pty_master_fd >= 0)
3813 {
3814 close(pty_slave_fd); /* close slave side of pty */
3815 fromshell_fd = pty_master_fd;
3816 toshell_fd = dup(pty_master_fd);
3817 }
3818 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003819# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820 {
3821 close(fd_toshell[0]);
3822 close(fd_fromshell[1]);
3823 toshell_fd = fd_toshell[1];
3824 fromshell_fd = fd_fromshell[0];
3825 }
3826
3827 /*
3828 * Write to the child if there are typed characters.
3829 * Read from the child if there are characters available.
3830 * Repeat the reading a few times if more characters are
3831 * available. Need to check for typed keys now and then, but
3832 * not too often (delays when no chars are available).
3833 * This loop is quit if no characters can be read from the pty
3834 * (WaitForChar detected special condition), or there are no
3835 * characters available and the child has exited.
3836 * Only check if the child has exited when there is no more
3837 * output. The child may exit before all the output has
3838 * been printed.
3839 *
3840 * Currently this busy loops!
3841 * This can probably dead-lock when the write blocks!
3842 */
3843 p_more_save = p_more;
3844 p_more = FALSE;
3845 old_State = State;
3846 State = EXTERNCMD; /* don't redraw at window resize */
3847
Bram Moolenaardf177f62005-02-22 08:39:57 +00003848 if (options & SHELL_WRITE && toshell_fd >= 0)
3849 {
3850 /* Fork a process that will write the lines to the
3851 * external program. */
3852 if ((wpid = fork()) == -1)
3853 {
3854 MSG_PUTS(_("\nCannot fork\n"));
3855 }
3856 else if (wpid == 0)
3857 {
3858 linenr_T lnum = curbuf->b_op_start.lnum;
3859 int written = 0;
3860 char_u *p = ml_get(lnum);
3861 char_u *s;
3862 size_t l;
3863
3864 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00003865 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003866 for (;;)
3867 {
3868 l = STRLEN(p + written);
3869 if (l == 0)
3870 len = 0;
3871 else if (p[written] == NL)
3872 /* NL -> NUL translation */
3873 len = write(toshell_fd, "", (size_t)1);
3874 else
3875 {
3876 s = vim_strchr(p + written, NL);
3877 len = write(toshell_fd, (char *)p + written,
3878 s == NULL ? l : s - (p + written));
3879 }
3880 if (len == l)
3881 {
3882 /* Finished a line, add a NL, unless this line
3883 * should not have one. */
3884 if (lnum != curbuf->b_op_end.lnum
3885 || !curbuf->b_p_bin
3886 || (lnum != write_no_eol_lnum
3887 && (lnum !=
3888 curbuf->b_ml.ml_line_count
3889 || curbuf->b_p_eol)))
3890 write(toshell_fd, "\n", (size_t)1);
3891 ++lnum;
3892 if (lnum > curbuf->b_op_end.lnum)
3893 {
3894 /* finished all the lines, close pipe */
3895 close(toshell_fd);
3896 toshell_fd = -1;
3897 break;
3898 }
3899 p = ml_get(lnum);
3900 written = 0;
3901 }
3902 else if (len > 0)
3903 written += len;
3904 }
3905 _exit(0);
3906 }
3907 else
3908 {
3909 close(toshell_fd);
3910 toshell_fd = -1;
3911 }
3912 }
3913
3914 if (options & SHELL_READ)
3915 ga_init2(&ga, 1, BUFLEN);
3916
3917 noread_cnt = 0;
3918
Bram Moolenaar071d4272004-06-13 20:20:40 +00003919 for (;;)
3920 {
3921 /*
3922 * Check if keys have been typed, write them to the child
3923 * if there are any. Don't do this if we are expanding
3924 * wild cards (would eat typeahead). Don't get extra
3925 * characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003926 * Don't read characters unless we didn't get output for a
3927 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003928 */
3929 len = 0;
3930 if (!(options & SHELL_EXPAND)
3931 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00003932 || (noread_cnt > 4
3933 && (len = ui_inchar(ta_buf,
3934 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003935 {
3936 /*
3937 * For pipes:
3938 * Check for CTRL-C: send interrupt signal to child.
3939 * Check for CTRL-D: EOF, close pipe to child.
3940 */
3941 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
3942 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003943# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003944 /*
3945 * Send SIGINT to the child's group or all
3946 * processes in our group.
3947 */
3948 if (ta_buf[ta_len] == Ctrl_C
3949 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003950 {
3951# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00003952 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003953# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003954 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003956 if (wpid > 0)
3957 kill(wpid, SIGINT);
3958 }
3959# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003960 if (pty_master_fd < 0 && toshell_fd >= 0
3961 && ta_buf[ta_len] == Ctrl_D)
3962 {
3963 close(toshell_fd);
3964 toshell_fd = -1;
3965 }
3966 }
3967
3968 /* replace K_BS by <BS> and K_DEL by <DEL> */
3969 for (i = ta_len; i < ta_len + len; ++i)
3970 {
3971 if (ta_buf[i] == CSI && len - i > 2)
3972 {
3973 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
3974 if (c == K_DEL || c == K_KDEL || c == K_BS)
3975 {
3976 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
3977 (size_t)(len - i - 2));
3978 if (c == K_DEL || c == K_KDEL)
3979 ta_buf[i] = DEL;
3980 else
3981 ta_buf[i] = Ctrl_H;
3982 len -= 2;
3983 }
3984 }
3985 else if (ta_buf[i] == '\r')
3986 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00003987# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003988 if (has_mbyte)
3989 i += (*mb_ptr2len_check)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003990# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003991 }
3992
3993 /*
3994 * For pipes: echo the typed characters.
3995 * For a pty this does not seem to work.
3996 */
3997 if (pty_master_fd < 0)
3998 {
3999 for (i = ta_len; i < ta_len + len; ++i)
4000 {
4001 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4002 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004003# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004 else if (has_mbyte)
4005 {
4006 int l = (*mb_ptr2len_check)(ta_buf + i);
4007
4008 msg_outtrans_len(ta_buf + i, l);
4009 i += l - 1;
4010 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004011# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004012 else
4013 msg_outtrans_len(ta_buf + i, 1);
4014 }
4015 windgoto(msg_row, msg_col);
4016 out_flush();
4017 }
4018
4019 ta_len += len;
4020
4021 /*
4022 * Write the characters to the child, unless EOF has
4023 * been typed for pipes. Write one character at a
4024 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004025 * When writing buffer lines, drop the typed
4026 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004028 if (options & SHELL_WRITE)
4029 ta_len = 0;
4030 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004031 {
4032 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4033 if (len > 0)
4034 {
4035 ta_len -= len;
4036 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004037 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004038 }
4039 }
4040 }
4041
Bram Moolenaardf177f62005-02-22 08:39:57 +00004042 if (got_int)
4043 {
4044 /* CTRL-C sends a signal to the child, we ignore it
4045 * ourselves */
4046# ifdef HAVE_SETSID
4047 kill(-pid, SIGINT);
4048# else
4049 kill(0, SIGINT);
4050# endif
4051 if (wpid > 0)
4052 kill(wpid, SIGINT);
4053 got_int = FALSE;
4054 }
4055
Bram Moolenaar071d4272004-06-13 20:20:40 +00004056 /*
4057 * Check if the child has any characters to be printed.
4058 * Read them and write them to our window. Repeat this as
4059 * long as there is something to do, avoid the 10ms wait
4060 * for mch_inchar(), or sending typeahead characters to
4061 * the external process.
4062 * TODO: This should handle escape sequences, compatible
4063 * to some terminal (vt52?).
4064 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004065 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004066 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4067 {
4068 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004069# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004070 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004071# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004073# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004074 );
4075 if (len <= 0) /* end of file or error */
4076 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004077
4078 noread_cnt = 0;
4079 if (options & SHELL_READ)
4080 {
4081 /* Do NUL -> NL translation, append NL separated
4082 * lines to the current buffer. */
4083 for (i = 0; i < len; ++i)
4084 {
4085 if (buffer[i] == NL)
4086 append_ga_line(&ga);
4087 else if (buffer[i] == NUL)
4088 ga_append(&ga, NL);
4089 else
4090 ga_append(&ga, buffer[i]);
4091 }
4092 }
4093# ifdef FEAT_MBYTE
4094 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004095 {
4096 int l;
4097
Bram Moolenaardf177f62005-02-22 08:39:57 +00004098 len += buffer_off;
4099 buffer[len] = NUL;
4100
Bram Moolenaar071d4272004-06-13 20:20:40 +00004101 /* Check if the last character in buffer[] is
4102 * incomplete, keep these bytes for the next
4103 * round. */
4104 for (p = buffer; p < buffer + len; p += l)
4105 {
4106 if (enc_utf8) /* exclude composing chars */
4107 l = utf_ptr2len_check(p);
4108 else
4109 l = (*mb_ptr2len_check)(p);
4110 if (l == 0)
4111 l = 1; /* NUL byte? */
4112 else if (MB_BYTE2LEN(*p) != l)
4113 break;
4114 }
4115 if (p == buffer) /* no complete character */
4116 {
4117 /* avoid getting stuck at an illegal byte */
4118 if (len >= 12)
4119 ++p;
4120 else
4121 {
4122 buffer_off = len;
4123 continue;
4124 }
4125 }
4126 c = *p;
4127 *p = NUL;
4128 msg_puts(buffer);
4129 if (p < buffer + len)
4130 {
4131 *p = c;
4132 buffer_off = (buffer + len) - p;
4133 mch_memmove(buffer, p, buffer_off);
4134 continue;
4135 }
4136 buffer_off = 0;
4137 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004138# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004139 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140 {
4141 buffer[len] = NUL;
4142 msg_puts(buffer);
4143 }
4144
4145 windgoto(msg_row, msg_col);
4146 cursor_on();
4147 out_flush();
4148 if (got_int)
4149 break;
4150 }
4151
4152 /*
4153 * Check if the child still exists, before checking for
4154 * typed characters (otherwise we would loose typeahead).
4155 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004156# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004157 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004158# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004159 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004160# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4162 || (wait_pid == pid && WIFEXITED(status)))
4163 {
4164 wait_pid = pid;
4165 break;
4166 }
4167 wait_pid = 0;
4168 }
4169finished:
4170 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004171 if (options & SHELL_READ)
4172 {
4173 if (ga.ga_len > 0)
4174 {
4175 append_ga_line(&ga);
4176 /* remember that the NL was missing */
4177 write_no_eol_lnum = curwin->w_cursor.lnum;
4178 }
4179 else
4180 write_no_eol_lnum = 0;
4181 ga_clear(&ga);
4182 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004183
Bram Moolenaar071d4272004-06-13 20:20:40 +00004184 /*
4185 * Give all typeahead that wasn't used back to ui_inchar().
4186 */
4187 if (ta_len)
4188 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004189 State = old_State;
4190 if (toshell_fd >= 0)
4191 close(toshell_fd);
4192 close(fromshell_fd);
4193 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004194
4195 /*
4196 * Wait until our child has exited.
4197 * Ignore wait() returning pids of other children and returning
4198 * because of some signal like SIGWINCH.
4199 * Don't wait if wait_pid was already set above, indicating the
4200 * child already exited.
4201 */
4202 while (wait_pid != pid)
4203 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004204# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004205 /* Ugly hack: when compiled with Python threads are probably
4206 * used, in which case wait() sometimes hangs for no obvious
4207 * reason. Use waitpid() instead and loop (like the GUI). */
4208# ifdef __NeXT__
4209 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4210# else
4211 wait_pid = waitpid(pid, &status, WNOHANG);
4212# endif
4213 if (wait_pid == 0)
4214 {
4215 /* Wait for 1/100 sec before trying again. */
4216 mch_delay(10L, TRUE);
4217 continue;
4218 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004219# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004221# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004222 if (wait_pid <= 0
4223# ifdef ECHILD
4224 && errno == ECHILD
4225# endif
4226 )
4227 break;
4228 }
4229
Bram Moolenaardf177f62005-02-22 08:39:57 +00004230 /* Make sure the child that writes to the external program is
4231 * dead. */
4232 if (wpid > 0)
4233 kill(wpid, SIGKILL);
4234
Bram Moolenaar071d4272004-06-13 20:20:40 +00004235 /*
4236 * Set to raw mode right now, otherwise a CTRL-C after
4237 * catch_signals() will kill Vim.
4238 */
4239 if (tmode == TMODE_RAW)
4240 settmode(TMODE_RAW);
4241 did_settmode = TRUE;
4242 set_signals();
4243
4244 if (WIFEXITED(status))
4245 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004246 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004247 retval = WEXITSTATUS(status);
4248 if (retval && !emsg_silent)
4249 {
4250 if (retval == EXEC_FAILED)
4251 {
4252 MSG_PUTS(_("\nCannot execute shell "));
4253 msg_outtrans(p_sh);
4254 msg_putchar('\n');
4255 }
4256 else if (!(options & SHELL_SILENT))
4257 {
4258 MSG_PUTS(_("\nshell returned "));
4259 msg_outnum((long)retval);
4260 msg_putchar('\n');
4261 }
4262 }
4263 }
4264 else
4265 MSG_PUTS(_("\nCommand terminated\n"));
4266 }
4267 }
4268 vim_free(argv);
4269
4270error:
4271 if (!did_settmode)
4272 if (tmode == TMODE_RAW)
4273 settmode(TMODE_RAW); /* set to raw mode */
4274# ifdef FEAT_TITLE
4275 resettitle();
4276# endif
4277 vim_free(newcmd);
4278
4279 return retval;
4280
4281#endif /* USE_SYSTEM */
4282}
4283
4284/*
4285 * Check for CTRL-C typed by reading all available characters.
4286 * In cooked mode we should get SIGINT, no need to check.
4287 */
4288 void
4289mch_breakcheck()
4290{
4291 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4292 fill_input_buf(FALSE);
4293}
4294
4295/*
4296 * Wait "msec" msec until a character is available from the keyboard or from
4297 * inbuf[]. msec == -1 will block forever.
4298 * When a GUI is being used, this will never get called -- webb
4299 */
4300 static int
4301WaitForChar(msec)
4302 long msec;
4303{
4304#ifdef FEAT_MOUSE_GPM
4305 int gpm_process_wanted;
4306#endif
4307#ifdef FEAT_XCLIPBOARD
4308 int rest;
4309#endif
4310 int avail;
4311
4312 if (input_available()) /* something in inbuf[] */
4313 return 1;
4314
4315#if defined(FEAT_MOUSE_DEC)
4316 /* May need to query the mouse position. */
4317 if (WantQueryMouse)
4318 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004319 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004320 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4321 }
4322#endif
4323
4324 /*
4325 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4326 * events. This is a bit complicated, because they might both be defined.
4327 */
4328#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4329# ifdef FEAT_XCLIPBOARD
4330 rest = 0;
4331 if (do_xterm_trace())
4332 rest = msec;
4333# endif
4334 do
4335 {
4336# ifdef FEAT_XCLIPBOARD
4337 if (rest != 0)
4338 {
4339 msec = XT_TRACE_DELAY;
4340 if (rest >= 0 && rest < XT_TRACE_DELAY)
4341 msec = rest;
4342 if (rest >= 0)
4343 rest -= msec;
4344 }
4345# endif
4346# ifdef FEAT_MOUSE_GPM
4347 gpm_process_wanted = 0;
4348 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4349# else
4350 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4351# endif
4352 if (!avail)
4353 {
4354 if (input_available())
4355 return 1;
4356# ifdef FEAT_XCLIPBOARD
4357 if (rest == 0 || !do_xterm_trace())
4358# endif
4359 break;
4360 }
4361 }
4362 while (FALSE
4363# ifdef FEAT_MOUSE_GPM
4364 || (gpm_process_wanted && mch_gpm_process() == 0)
4365# endif
4366# ifdef FEAT_XCLIPBOARD
4367 || (!avail && rest != 0)
4368# endif
4369 );
4370
4371#else
4372 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4373#endif
4374 return avail;
4375}
4376
4377/*
4378 * Wait "msec" msec until a character is available from file descriptor "fd".
4379 * Time == -1 will block forever.
4380 * When a GUI is being used, this will not be used for input -- webb
4381 * Returns also, when a request from Sniff is waiting -- toni.
4382 * Or when a Linux GPM mouse event is waiting.
4383 */
4384/* ARGSUSED */
4385#if defined(__BEOS__)
4386 int
4387#else
4388 static int
4389#endif
4390RealWaitForChar(fd, msec, check_for_gpm)
4391 int fd;
4392 long msec;
4393 int *check_for_gpm;
4394{
4395 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004396#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004397 static int busy = FALSE;
4398
4399 /* May retry getting characters after an event was handled. */
4400# define MAY_LOOP
4401
4402# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4403 /* Remember at what time we started, so that we know how much longer we
4404 * should wait after being interrupted. */
4405# define USE_START_TV
4406 struct timeval start_tv;
4407
4408 if (msec > 0 && (
4409# ifdef FEAT_XCLIPBOARD
4410 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004411# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004412 ||
4413# endif
4414# endif
4415# ifdef USE_XSMP
4416 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004417# ifdef FEAT_MZSCHEME
4418 ||
4419# endif
4420# endif
4421# ifdef FEAT_MZSCHEME
4422 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004423# endif
4424 ))
4425 gettimeofday(&start_tv, NULL);
4426# endif
4427
4428 /* Handle being called recursively. This may happen for the session
4429 * manager stuff, it may save the file, which does a breakcheck. */
4430 if (busy)
4431 return 0;
4432#endif
4433
4434#ifdef MAY_LOOP
4435 while (1)
4436#endif
4437 {
4438#ifdef MAY_LOOP
4439 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004440# ifdef FEAT_MZSCHEME
4441 int mzquantum_used = FALSE;
4442# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004443#endif
4444#ifndef HAVE_SELECT
4445 struct pollfd fds[5];
4446 int nfd;
4447# ifdef FEAT_XCLIPBOARD
4448 int xterm_idx = -1;
4449# endif
4450# ifdef FEAT_MOUSE_GPM
4451 int gpm_idx = -1;
4452# endif
4453# ifdef USE_XSMP
4454 int xsmp_idx = -1;
4455# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004456 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004457
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004458# ifdef FEAT_MZSCHEME
4459 mzvim_check_threads();
4460 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4461 {
4462 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4463 mzquantum_used = TRUE;
4464 }
4465# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004466 fds[0].fd = fd;
4467 fds[0].events = POLLIN;
4468 nfd = 1;
4469
4470# ifdef FEAT_SNIFF
4471# define SNIFF_IDX 1
4472 if (want_sniff_request)
4473 {
4474 fds[SNIFF_IDX].fd = fd_from_sniff;
4475 fds[SNIFF_IDX].events = POLLIN;
4476 nfd++;
4477 }
4478# endif
4479# ifdef FEAT_XCLIPBOARD
4480 if (xterm_Shell != (Widget)0)
4481 {
4482 xterm_idx = nfd;
4483 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4484 fds[nfd].events = POLLIN;
4485 nfd++;
4486 }
4487# endif
4488# ifdef FEAT_MOUSE_GPM
4489 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4490 {
4491 gpm_idx = nfd;
4492 fds[nfd].fd = gpm_fd;
4493 fds[nfd].events = POLLIN;
4494 nfd++;
4495 }
4496# endif
4497# ifdef USE_XSMP
4498 if (xsmp_icefd != -1)
4499 {
4500 xsmp_idx = nfd;
4501 fds[nfd].fd = xsmp_icefd;
4502 fds[nfd].events = POLLIN;
4503 nfd++;
4504 }
4505# endif
4506
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004507 ret = poll(fds, nfd, towait);
4508# ifdef FEAT_MZSCHEME
4509 if (ret == 0 && mzquantum_used)
4510 /* MzThreads scheduling is required and timeout occured */
4511 finished = FALSE;
4512# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004513
4514# ifdef FEAT_SNIFF
4515 if (ret < 0)
4516 sniff_disconnect(1);
4517 else if (want_sniff_request)
4518 {
4519 if (fds[SNIFF_IDX].revents & POLLHUP)
4520 sniff_disconnect(1);
4521 if (fds[SNIFF_IDX].revents & POLLIN)
4522 sniff_request_waiting = 1;
4523 }
4524# endif
4525# ifdef FEAT_XCLIPBOARD
4526 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4527 {
4528 xterm_update(); /* Maybe we should hand out clipboard */
4529 if (--ret == 0 && !input_available())
4530 /* Try again */
4531 finished = FALSE;
4532 }
4533# endif
4534# ifdef FEAT_MOUSE_GPM
4535 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4536 {
4537 *check_for_gpm = 1;
4538 }
4539# endif
4540# ifdef USE_XSMP
4541 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4542 {
4543 if (fds[xsmp_idx].revents & POLLIN)
4544 {
4545 busy = TRUE;
4546 xsmp_handle_requests();
4547 busy = FALSE;
4548 }
4549 else if (fds[xsmp_idx].revents & POLLHUP)
4550 {
4551 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004552 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004553 xsmp_close();
4554 }
4555 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004556 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004557 }
4558# endif
4559
4560
4561#else /* HAVE_SELECT */
4562
4563 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004564 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565 fd_set rfds, efds;
4566 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004567 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004568
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004569# ifdef FEAT_MZSCHEME
4570 mzvim_check_threads();
4571 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4572 {
4573 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4574 mzquantum_used = TRUE;
4575 }
4576# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004577# ifdef __EMX__
4578 /* don't check for incoming chars if not in raw mode, because select()
4579 * always returns TRUE then (in some version of emx.dll) */
4580 if (curr_tmode != TMODE_RAW)
4581 return 0;
4582# endif
4583
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004584 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004585 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004586 tv.tv_sec = towait / 1000;
4587 tv.tv_usec = (towait % 1000) * (1000000/1000);
4588 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004589 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004590 else
4591 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004592
4593 /*
4594 * Select on ready for reading and exceptional condition (end of file).
4595 */
4596 FD_ZERO(&rfds); /* calls bzero() on a sun */
4597 FD_ZERO(&efds);
4598 FD_SET(fd, &rfds);
4599# if !defined(__QNX__) && !defined(__CYGWIN32__)
4600 /* For QNX select() always returns 1 if this is set. Why? */
4601 FD_SET(fd, &efds);
4602# endif
4603 maxfd = fd;
4604
4605# ifdef FEAT_SNIFF
4606 if (want_sniff_request)
4607 {
4608 FD_SET(fd_from_sniff, &rfds);
4609 FD_SET(fd_from_sniff, &efds);
4610 if (maxfd < fd_from_sniff)
4611 maxfd = fd_from_sniff;
4612 }
4613# endif
4614# ifdef FEAT_XCLIPBOARD
4615 if (xterm_Shell != (Widget)0)
4616 {
4617 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4618 if (maxfd < ConnectionNumber(xterm_dpy))
4619 maxfd = ConnectionNumber(xterm_dpy);
4620 }
4621# endif
4622# ifdef FEAT_MOUSE_GPM
4623 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4624 {
4625 FD_SET(gpm_fd, &rfds);
4626 FD_SET(gpm_fd, &efds);
4627 if (maxfd < gpm_fd)
4628 maxfd = gpm_fd;
4629 }
4630# endif
4631# ifdef USE_XSMP
4632 if (xsmp_icefd != -1)
4633 {
4634 FD_SET(xsmp_icefd, &rfds);
4635 FD_SET(xsmp_icefd, &efds);
4636 if (maxfd < xsmp_icefd)
4637 maxfd = xsmp_icefd;
4638 }
4639# endif
4640
4641# ifdef OLD_VMS
4642 /* Old VMS as v6.2 and older have broken select(). It waits more than
4643 * required. Should not be used */
4644 ret = 0;
4645# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004646 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4647# endif
4648# ifdef FEAT_MZSCHEME
4649 if (ret == 0 && mzquantum_used)
4650 /* loop if MzThreads must be scheduled and timeout occured */
4651 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004652# endif
4653
4654# ifdef FEAT_SNIFF
4655 if (ret < 0 )
4656 sniff_disconnect(1);
4657 else if (ret > 0 && want_sniff_request)
4658 {
4659 if (FD_ISSET(fd_from_sniff, &efds))
4660 sniff_disconnect(1);
4661 if (FD_ISSET(fd_from_sniff, &rfds))
4662 sniff_request_waiting = 1;
4663 }
4664# endif
4665# ifdef FEAT_XCLIPBOARD
4666 if (ret > 0 && xterm_Shell != (Widget)0
4667 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4668 {
4669 xterm_update(); /* Maybe we should hand out clipboard */
4670 /* continue looping when we only got the X event and the input
4671 * buffer is empty */
4672 if (--ret == 0 && !input_available())
4673 {
4674 /* Try again */
4675 finished = FALSE;
4676 }
4677 }
4678# endif
4679# ifdef FEAT_MOUSE_GPM
4680 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4681 {
4682 if (FD_ISSET(gpm_fd, &efds))
4683 gpm_close();
4684 else if (FD_ISSET(gpm_fd, &rfds))
4685 *check_for_gpm = 1;
4686 }
4687# endif
4688# ifdef USE_XSMP
4689 if (ret > 0 && xsmp_icefd != -1)
4690 {
4691 if (FD_ISSET(xsmp_icefd, &efds))
4692 {
4693 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004694 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004695 xsmp_close();
4696 if (--ret == 0)
4697 finished = FALSE; /* keep going if event was only one */
4698 }
4699 else if (FD_ISSET(xsmp_icefd, &rfds))
4700 {
4701 busy = TRUE;
4702 xsmp_handle_requests();
4703 busy = FALSE;
4704 if (--ret == 0)
4705 finished = FALSE; /* keep going if event was only one */
4706 }
4707 }
4708# endif
4709
4710#endif /* HAVE_SELECT */
4711
4712#ifdef MAY_LOOP
4713 if (finished || msec == 0)
4714 break;
4715
4716 /* We're going to loop around again, find out for how long */
4717 if (msec > 0)
4718 {
4719# ifdef USE_START_TV
4720 struct timeval mtv;
4721
4722 /* Compute remaining wait time. */
4723 gettimeofday(&mtv, NULL);
4724 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
4725 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
4726# else
4727 /* Guess we got interrupted halfway. */
4728 msec = msec / 2;
4729# endif
4730 if (msec <= 0)
4731 break; /* waited long enough */
4732 }
4733#endif
4734 }
4735
4736 return (ret > 0);
4737}
4738
4739#ifndef VMS
4740
4741#ifndef NO_EXPANDPATH
4742 static int
4743pstrcmp(a, b)
4744 const void *a, *b;
4745{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004746 return (pathcmp(*(char **)a, *(char **)b, -1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004747}
4748
4749/*
4750 * Recursively expand one path component into all matching files and/or
4751 * directories.
4752 * "path" has backslashes before chars that are not to be expanded, starting
4753 * at "path + wildoff".
4754 * Return the number of matches found.
4755 */
4756 int
4757mch_expandpath(gap, path, flags)
4758 garray_T *gap;
4759 char_u *path;
4760 int flags; /* EW_* flags */
4761{
4762 return unix_expandpath(gap, path, 0, flags);
4763}
4764
4765 static int
4766unix_expandpath(gap, path, wildoff, flags)
4767 garray_T *gap;
4768 char_u *path;
4769 int wildoff;
4770 int flags; /* EW_* flags */
4771{
4772 char_u *buf;
4773 char_u *path_end;
4774 char_u *p, *s, *e;
4775 int start_len, c;
4776 char_u *pat;
4777 DIR *dirp;
4778 regmatch_T regmatch;
4779 struct dirent *dp;
4780 int starts_with_dot;
4781 int matches;
4782 int len;
4783
4784 start_len = gap->ga_len;
4785 buf = alloc(STRLEN(path) + BASENAMELEN + 5);/* make room for file name */
4786 if (buf == NULL)
4787 return 0;
4788
4789/*
4790 * Find the first part in the path name that contains a wildcard.
4791 * Copy it into buf, including the preceding characters.
4792 */
4793 p = buf;
4794 s = buf;
4795 e = NULL;
4796 path_end = path;
4797 while (*path_end != NUL)
4798 {
4799 /* May ignore a wildcard that has a backslash before it; it will
4800 * be removed by rem_backslash() or file_pat_to_reg_pat() below. */
4801 if (path_end >= path + wildoff && rem_backslash(path_end))
4802 *p++ = *path_end++;
4803 else if (*path_end == '/')
4804 {
4805 if (e != NULL)
4806 break;
4807 s = p + 1;
4808 }
4809 else if (path_end >= path + wildoff
4810 && vim_strchr((char_u *)"*?[{~$", *path_end) != NULL)
4811 e = p;
4812#ifdef FEAT_MBYTE
4813 if (has_mbyte)
4814 {
4815 len = (*mb_ptr2len_check)(path_end);
4816 STRNCPY(p, path_end, len);
4817 p += len;
4818 path_end += len;
4819 }
4820 else
4821#endif
4822 *p++ = *path_end++;
4823 }
4824 e = p;
4825 *e = NUL;
4826
4827 /* now we have one wildcard component between s and e */
4828 /* Remove backslashes between "wildoff" and the start of the wildcard
4829 * component. */
4830 for (p = buf + wildoff; p < s; ++p)
4831 if (rem_backslash(p))
4832 {
4833 STRCPY(p, p + 1);
4834 --e;
4835 --s;
4836 }
4837
4838 /* convert the file pattern to a regexp pattern */
4839 starts_with_dot = (*s == '.');
4840 pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
4841 if (pat == NULL)
4842 {
4843 vim_free(buf);
4844 return 0;
4845 }
4846
4847 /* compile the regexp into a program */
4848#ifdef MACOS_X /* Can/Should we use CASE_INSENSITIVE_FILENAME instead ?*/
4849 regmatch.rm_ic = TRUE; /* Behave like Terminal.app */
4850#else
4851 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
4852#endif
4853 regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
4854 vim_free(pat);
4855
4856 if (regmatch.regprog == NULL)
4857 {
4858 vim_free(buf);
4859 return 0;
4860 }
4861
4862 /* open the directory for scanning */
4863 c = *s;
4864 *s = NUL;
4865 dirp = opendir(*buf == NUL ? "." : (char *)buf);
4866 *s = c;
4867
4868 /* Find all matching entries */
4869 if (dirp != NULL)
4870 {
4871 for (;;)
4872 {
4873 dp = readdir(dirp);
4874 if (dp == NULL)
4875 break;
4876 if ((dp->d_name[0] != '.' || starts_with_dot)
4877 && vim_regexec(&regmatch, (char_u *)dp->d_name, (colnr_T)0))
4878 {
4879 STRCPY(s, dp->d_name);
4880 len = STRLEN(buf);
4881 STRCPY(buf + len, path_end);
4882 if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */
4883 {
4884 /* need to expand another component of the path */
4885 /* remove backslashes for the remaining components only */
4886 (void)unix_expandpath(gap, buf, len + 1, flags);
4887 }
4888 else
4889 {
4890 /* no more wildcards, check if there is a match */
4891 /* remove backslashes for the remaining components only */
4892 if (*path_end != NUL)
4893 backslash_halve(buf + len + 1);
4894 if (mch_getperm(buf) >= 0) /* add existing file */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004895 {
4896#if defined(MACOS_X) && defined(FEAT_MBYTE)
4897 size_t precomp_len = STRLEN(buf)+1;
4898 char_u *precomp_buf =
4899 mac_precompose_path(buf, precomp_len, &precomp_len);
4900 if (precomp_buf)
4901 {
4902 mch_memmove(buf, precomp_buf, precomp_len);
4903 vim_free(precomp_buf);
4904 }
4905#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004906 addfile(gap, buf, flags);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004907 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004908 }
4909 }
4910 }
4911
4912 closedir(dirp);
4913 }
4914
4915 vim_free(buf);
4916 vim_free(regmatch.regprog);
4917
4918 matches = gap->ga_len - start_len;
4919 if (matches > 0)
4920 qsort(((char_u **)gap->ga_data) + start_len, matches,
4921 sizeof(char_u *), pstrcmp);
4922 return matches;
4923}
4924#endif
4925
4926/*
4927 * mch_expand_wildcards() - this code does wild-card pattern matching using
4928 * the shell
4929 *
4930 * return OK for success, FAIL for error (you may lose some memory) and put
4931 * an error message in *file.
4932 *
4933 * num_pat is number of input patterns
4934 * pat is array of pointers to input patterns
4935 * num_file is pointer to number of matched file names
4936 * file is pointer to array of pointers to matched file names
4937 */
4938
4939#ifndef SEEK_SET
4940# define SEEK_SET 0
4941#endif
4942#ifndef SEEK_END
4943# define SEEK_END 2
4944#endif
4945
4946/* ARGSUSED */
4947 int
4948mch_expand_wildcards(num_pat, pat, num_file, file, flags)
4949 int num_pat;
4950 char_u **pat;
4951 int *num_file;
4952 char_u ***file;
4953 int flags; /* EW_* flags */
4954{
4955 int i;
4956 size_t len;
4957 char_u *p;
4958 int dir;
4959#ifdef __EMX__
4960# define EXPL_ALLOC_INC 16
4961 char_u **expl_files;
4962 size_t files_alloced, files_free;
4963 char_u *buf;
4964 int has_wildcard;
4965
4966 *num_file = 0; /* default: no files found */
4967 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
4968 files_free = EXPL_ALLOC_INC; /* how much space is not used */
4969 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
4970 if (*file == NULL)
4971 return FAIL;
4972
4973 for (; num_pat > 0; num_pat--, pat++)
4974 {
4975 expl_files = NULL;
4976 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
4977 /* expand environment var or home dir */
4978 buf = expand_env_save(*pat);
4979 else
4980 buf = vim_strsave(*pat);
4981 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00004982 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004983 if (has_wildcard) /* yes, so expand them */
4984 expl_files = (char_u **)_fnexplode(buf);
4985
4986 /*
4987 * return value of buf if no wildcards left,
4988 * OR if no match AND EW_NOTFOUND is set.
4989 */
4990 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
4991 || (expl_files == NULL && (flags & EW_NOTFOUND)))
4992 { /* simply save the current contents of *buf */
4993 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
4994 if (expl_files != NULL)
4995 {
4996 expl_files[0] = vim_strsave(buf);
4997 expl_files[1] = NULL;
4998 }
4999 }
5000 vim_free(buf);
5001
5002 /*
5003 * Count number of names resulting from expansion,
5004 * At the same time add a backslash to the end of names that happen to
5005 * be directories, and replace slashes with backslashes.
5006 */
5007 if (expl_files)
5008 {
5009 for (i = 0; (p = expl_files[i]) != NULL; i++)
5010 {
5011 dir = mch_isdir(p);
5012 /* If we don't want dirs and this is one, skip it */
5013 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5014 continue;
5015
5016 if (--files_free == 0)
5017 {
5018 /* need more room in table of pointers */
5019 files_alloced += EXPL_ALLOC_INC;
5020 *file = (char_u **)vim_realloc(*file,
5021 sizeof(char_u **) * files_alloced);
5022 if (*file == NULL)
5023 {
5024 EMSG(_(e_outofmem));
5025 *num_file = 0;
5026 return FAIL;
5027 }
5028 files_free = EXPL_ALLOC_INC;
5029 }
5030 slash_adjust(p);
5031 if (dir)
5032 {
5033 /* For a directory we add a '/', unless it's already
5034 * there. */
5035 len = STRLEN(p);
5036 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5037 {
5038 STRCPY((*file)[*num_file], p);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005039 if (!after_pathsep((*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005040 {
5041 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005042 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005043 }
5044 }
5045 }
5046 else
5047 {
5048 (*file)[*num_file] = vim_strsave(p);
5049 }
5050
5051 /*
5052 * Error message already given by either alloc or vim_strsave.
5053 * Should return FAIL, but returning OK works also.
5054 */
5055 if ((*file)[*num_file] == NULL)
5056 break;
5057 (*num_file)++;
5058 }
5059 _fnexplodefree((char **)expl_files);
5060 }
5061 }
5062 return OK;
5063
5064#else /* __EMX__ */
5065
5066 int j;
5067 char_u *tempname;
5068 char_u *command;
5069 FILE *fd;
5070 char_u *buffer;
5071#define STYLE_ECHO 0 /* use "echo" to expand */
5072#define STYLE_GLOB 1 /* use "glob" to expand, for csh */
5073#define STYLE_PRINT 2 /* use "print -N" to expand, for zsh */
5074#define STYLE_BT 3 /* `cmd` expansion, execute the pattern directly */
5075 int shell_style = STYLE_ECHO;
5076 int check_spaces;
5077 static int did_find_nul = FALSE;
5078 int ampersent = FALSE;
5079
5080 *num_file = 0; /* default: no files found */
5081 *file = NULL;
5082
5083 /*
5084 * If there are no wildcards, just copy the names to allocated memory.
5085 * Saves a lot of time, because we don't have to start a new shell.
5086 */
5087 if (!have_wildcard(num_pat, pat))
5088 return save_patterns(num_pat, pat, num_file, file);
5089
5090 /*
5091 * Don't allow the use of backticks in secure and restricted mode.
5092 */
5093 if (secure || restricted)
5094 for (i = 0; i < num_pat; ++i)
5095 if (vim_strchr(pat[i], '`') != NULL
5096 && (check_restricted() || check_secure()))
5097 return FAIL;
5098
5099 /*
5100 * get a name for the temp file
5101 */
5102 if ((tempname = vim_tempname('o')) == NULL)
5103 {
5104 EMSG(_(e_notmp));
5105 return FAIL;
5106 }
5107
5108 /*
5109 * Let the shell expand the patterns and write the result into the temp
5110 * file. if expanding `cmd` execute it directly.
5111 * If we use csh, glob will work better than echo.
5112 * If we use zsh, print -N will work better than glob.
5113 */
5114 if (num_pat == 1 && *pat[0] == '`'
5115 && (len = STRLEN(pat[0])) > 2
5116 && *(pat[0] + len - 1) == '`')
5117 shell_style = STYLE_BT;
5118 else if ((len = STRLEN(p_sh)) >= 3)
5119 {
5120 if (STRCMP(p_sh + len - 3, "csh") == 0)
5121 shell_style = STYLE_GLOB;
5122 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5123 shell_style = STYLE_PRINT;
5124 }
5125
5126 /* "unset nonomatch; print -N >" plus two is 29 */
5127 len = STRLEN(tempname) + 29;
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005128 for (i = 0; i < num_pat; ++i)
5129 {
5130 /* Count the length of the patterns in the same way as they are put in
5131 * "command" below. */
5132#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005133 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005134#else
5135 ++len; /* add space */
5136 for (j = 0; pat[i][j] != NUL; )
5137 if (vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5138 {
5139 len += 2; /* add two quotes */
5140 while (pat[i][j] != NUL
5141 && vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5142 {
5143 ++len;
5144 ++j;
5145 }
5146 }
5147 else
5148 {
5149 ++len;
5150 ++j;
5151 }
5152#endif
5153 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005154 command = alloc(len);
5155 if (command == NULL)
5156 {
5157 /* out of memory */
5158 vim_free(tempname);
5159 return FAIL;
5160 }
5161
5162 /*
5163 * Build the shell command:
5164 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5165 * recognizes this).
5166 * - Add the shell command to print the expanded names.
5167 * - Add the temp file name.
5168 * - Add the file name patterns.
5169 */
5170 if (shell_style == STYLE_BT)
5171 {
5172 STRCPY(command, pat[0] + 1); /* exclude first backtick */
5173 p = command + STRLEN(command) - 1;
5174 *p = ' '; /* remove last backtick */
5175 while (p > command && vim_iswhite(*p))
5176 --p;
5177 if (*p == '&') /* remove trailing '&' */
5178 {
5179 ampersent = TRUE;
5180 *p = ' ';
5181 }
5182 STRCAT(command, ">");
5183 }
5184 else
5185 {
5186 if (flags & EW_NOTFOUND)
5187 STRCPY(command, "set nonomatch; ");
5188 else
5189 STRCPY(command, "unset nonomatch; ");
5190 if (shell_style == STYLE_GLOB)
5191 STRCAT(command, "glob >");
5192 else if (shell_style == STYLE_PRINT)
5193 STRCAT(command, "print -N >");
5194 else
5195 STRCAT(command, "echo >");
5196 }
5197 STRCAT(command, tempname);
5198 if (shell_style != STYLE_BT)
5199 for (i = 0; i < num_pat; ++i)
5200 {
5201 /* When using system() always add extra quotes, because the shell
5202 * is started twice. Otherwise only put quotes around spaces and
5203 * single quotes. */
5204#ifdef USE_SYSTEM
5205 STRCAT(command, " \"");
5206 STRCAT(command, pat[i]);
5207 STRCAT(command, "\"");
5208#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005209 int intick = FALSE;
5210
Bram Moolenaar071d4272004-06-13 20:20:40 +00005211 p = command + STRLEN(command);
5212 *p++ = ' ';
5213 for (j = 0; pat[i][j] != NUL; )
Bram Moolenaar582fd852005-03-28 20:58:01 +00005214 {
5215 if (pat[i][j] == '`')
5216 {
5217 intick = !intick;
5218 *p++ = pat[i][j++];
5219 }
5220 else if (!intick && vim_strchr((char_u *)" '",
5221 pat[i][j]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005222 {
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00005223 /* Put quotes around special characters, but not when
5224 * inside ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005225 *p++ = '"';
5226 while (pat[i][j] != NUL
5227 && vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5228 *p++ = pat[i][j++];
5229 *p++ = '"';
5230 }
5231 else
Bram Moolenaar0cf6f542005-01-16 21:59:36 +00005232 {
5233 /* For a backslash also copy the next character, don't
5234 * want to put quotes around it. */
5235 if ((*p++ = pat[i][j++]) == '\\' && pat[i][j] != NUL)
5236 *p++ = pat[i][j++];
5237 }
Bram Moolenaar582fd852005-03-28 20:58:01 +00005238 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005239 *p = NUL;
5240#endif
5241 }
5242 if (flags & EW_SILENT)
5243 show_shell_mess = FALSE;
5244 if (ampersent)
5245 STRCAT(command, "&"); /* put the '&' back after the
5246 redirection */
5247
5248 /*
5249 * Using zsh -G: If a pattern has no matches, it is just deleted from
5250 * the argument list, otherwise zsh gives an error message and doesn't
5251 * expand any other pattern.
5252 */
5253 if (shell_style == STYLE_PRINT)
5254 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5255
5256 /*
5257 * If we use -f then shell variables set in .cshrc won't get expanded.
5258 * vi can do it, so we will too, but it is only necessary if there is a "$"
5259 * in one of the patterns, otherwise we can still use the fast option.
5260 */
5261 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5262 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5263
5264 /*
5265 * execute the shell command
5266 */
5267 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5268
5269 /* When running in the background, give it some time to create the temp
5270 * file, but don't wait for it to finish. */
5271 if (ampersent)
5272 mch_delay(10L, TRUE);
5273
5274 extra_shell_arg = NULL; /* cleanup */
5275 show_shell_mess = TRUE;
5276 vim_free(command);
5277
5278 if (i) /* mch_call_shell() failed */
5279 {
5280 mch_remove(tempname);
5281 vim_free(tempname);
5282 /*
5283 * With interactive completion, the error message is not printed.
5284 * However with USE_SYSTEM, I don't know how to turn off error messages
5285 * from the shell, so screen may still get messed up -- webb.
5286 */
5287#ifndef USE_SYSTEM
5288 if (!(flags & EW_SILENT))
5289#endif
5290 {
5291 redraw_later_clear(); /* probably messed up screen */
5292 msg_putchar('\n'); /* clear bottom line quickly */
5293 cmdline_row = Rows - 1; /* continue on last line */
5294#ifdef USE_SYSTEM
5295 if (!(flags & EW_SILENT))
5296#endif
5297 {
5298 MSG(_(e_wildexpand));
5299 msg_start(); /* don't overwrite this message */
5300 }
5301 }
5302 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5303 * EW_NOTFOUND is given */
5304 if (shell_style == STYLE_BT)
5305 return FAIL;
5306 goto notfound;
5307 }
5308
5309 /*
5310 * read the names from the file into memory
5311 */
5312 fd = fopen((char *)tempname, READBIN);
5313 if (fd == NULL)
5314 {
5315 /* Something went wrong, perhaps a file name with a special char. */
5316 if (!(flags & EW_SILENT))
5317 {
5318 MSG(_(e_wildexpand));
5319 msg_start(); /* don't overwrite this message */
5320 }
5321 vim_free(tempname);
5322 goto notfound;
5323 }
5324 fseek(fd, 0L, SEEK_END);
5325 len = ftell(fd); /* get size of temp file */
5326 fseek(fd, 0L, SEEK_SET);
5327 buffer = alloc(len + 1);
5328 if (buffer == NULL)
5329 {
5330 /* out of memory */
5331 mch_remove(tempname);
5332 vim_free(tempname);
5333 fclose(fd);
5334 return FAIL;
5335 }
5336 i = fread((char *)buffer, 1, len, fd);
5337 fclose(fd);
5338 mch_remove(tempname);
5339 if (i != len)
5340 {
5341 /* unexpected read error */
5342 EMSG2(_(e_notread), tempname);
5343 vim_free(tempname);
5344 vim_free(buffer);
5345 return FAIL;
5346 }
5347 vim_free(tempname);
5348
5349#if defined(__CYGWIN__) || defined(__CYGWIN32__)
5350 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5351 p = buffer;
5352 for (i = 0; i < len; ++i)
5353 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5354 *p++ = buffer[i];
5355 len = p - buffer;
5356# endif
5357
5358
5359 /* file names are separated with Space */
5360 if (shell_style == STYLE_ECHO)
5361 {
5362 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5363 p = buffer;
5364 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5365 {
5366 while (*p != ' ' && *p != '\n')
5367 ++p;
5368 p = skipwhite(p); /* skip to next entry */
5369 }
5370 }
5371 /* file names are separated with NL */
5372 else if (shell_style == STYLE_BT)
5373 {
5374 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5375 p = buffer;
5376 for (i = 0; *p != NUL; ++i) /* count number of entries */
5377 {
5378 while (*p != '\n' && *p != NUL)
5379 ++p;
5380 if (*p != NUL)
5381 ++p;
5382 p = skipwhite(p); /* skip leading white space */
5383 }
5384 }
5385 /* file names are separated with NUL */
5386 else
5387 {
5388 /*
5389 * Some versions of zsh use spaces instead of NULs to separate
5390 * results. Only do this when there is no NUL before the end of the
5391 * buffer, otherwise we would never be able to use file names with
5392 * embedded spaces when zsh does use NULs.
5393 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5394 * don't check for spaces again.
5395 */
5396 check_spaces = FALSE;
5397 if (shell_style == STYLE_PRINT && !did_find_nul)
5398 {
5399 /* If there is a NUL, set did_find_nul, else set check_spaces */
5400 if (len && (int)STRLEN(buffer) < len - 1)
5401 did_find_nul = TRUE;
5402 else
5403 check_spaces = TRUE;
5404 }
5405
5406 /*
5407 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5408 * already is one, for STYLE_GLOB it needs to be added.
5409 */
5410 if (len && buffer[len - 1] == NUL)
5411 --len;
5412 else
5413 buffer[len] = NUL;
5414 i = 0;
5415 for (p = buffer; p < buffer + len; ++p)
5416 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5417 {
5418 ++i;
5419 *p = NUL;
5420 }
5421 if (len)
5422 ++i; /* count last entry */
5423 }
5424 if (i == 0)
5425 {
5426 /*
5427 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5428 * /bin/sh will happily expand it to nothing rather than returning an
5429 * error; and hey, it's good to check anyway -- webb.
5430 */
5431 vim_free(buffer);
5432 goto notfound;
5433 }
5434 *num_file = i;
5435 *file = (char_u **)alloc(sizeof(char_u *) * i);
5436 if (*file == NULL)
5437 {
5438 /* out of memory */
5439 vim_free(buffer);
5440 return FAIL;
5441 }
5442
5443 /*
5444 * Isolate the individual file names.
5445 */
5446 p = buffer;
5447 for (i = 0; i < *num_file; ++i)
5448 {
5449 (*file)[i] = p;
5450 /* Space or NL separates */
5451 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT)
5452 {
5453 while (!(shell_style == STYLE_ECHO && *p == ' ') && *p != '\n')
5454 ++p;
5455 if (p == buffer + len) /* last entry */
5456 *p = NUL;
5457 else
5458 {
5459 *p++ = NUL;
5460 p = skipwhite(p); /* skip to next entry */
5461 }
5462 }
5463 else /* NUL separates */
5464 {
5465 while (*p && p < buffer + len) /* skip entry */
5466 ++p;
5467 ++p; /* skip NUL */
5468 }
5469 }
5470
5471 /*
5472 * Move the file names to allocated memory.
5473 */
5474 for (j = 0, i = 0; i < *num_file; ++i)
5475 {
5476 /* Require the files to exist. Helps when using /bin/sh */
5477 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5478 continue;
5479
5480 /* check if this entry should be included */
5481 dir = (mch_isdir((*file)[i]));
5482 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5483 continue;
5484
5485 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5486 if (p)
5487 {
5488 STRCPY(p, (*file)[i]);
5489 if (dir)
5490 STRCAT(p, "/"); /* add '/' to a directory name */
5491 (*file)[j++] = p;
5492 }
5493 }
5494 vim_free(buffer);
5495 *num_file = j;
5496
5497 if (*num_file == 0) /* rejected all entries */
5498 {
5499 vim_free(*file);
5500 *file = NULL;
5501 goto notfound;
5502 }
5503
5504 return OK;
5505
5506notfound:
5507 if (flags & EW_NOTFOUND)
5508 return save_patterns(num_pat, pat, num_file, file);
5509 return FAIL;
5510
5511#endif /* __EMX__ */
5512}
5513
5514#endif /* VMS */
5515
5516#ifndef __EMX__
5517 static int
5518save_patterns(num_pat, pat, num_file, file)
5519 int num_pat;
5520 char_u **pat;
5521 int *num_file;
5522 char_u ***file;
5523{
5524 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005525 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005526
5527 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5528 if (*file == NULL)
5529 return FAIL;
5530 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005531 {
5532 s = vim_strsave(pat[i]);
5533 if (s != NULL)
5534 /* Be compatible with expand_filename(): halve the number of
5535 * backslashes. */
5536 backslash_halve(s);
5537 (*file)[i] = s;
5538 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005539 *num_file = num_pat;
5540 return OK;
5541}
5542#endif
5543
5544
5545/*
5546 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5547 * expand.
5548 */
5549 int
5550mch_has_exp_wildcard(p)
5551 char_u *p;
5552{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005553 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005554 {
5555#ifndef OS2
5556 if (*p == '\\' && p[1] != NUL)
5557 ++p;
5558 else
5559#endif
5560 if (vim_strchr((char_u *)
5561#ifdef VMS
5562 "*?%"
5563#else
5564# ifdef OS2
5565 "*?"
5566# else
5567 "*?[{'"
5568# endif
5569#endif
5570 , *p) != NULL)
5571 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005572 }
5573 return FALSE;
5574}
5575
5576/*
5577 * Return TRUE if the string "p" contains a wildcard.
5578 * Don't recognize '~' at the end as a wildcard.
5579 */
5580 int
5581mch_has_wildcard(p)
5582 char_u *p;
5583{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005584 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005585 {
5586#ifndef OS2
5587 if (*p == '\\' && p[1] != NUL)
5588 ++p;
5589 else
5590#endif
5591 if (vim_strchr((char_u *)
5592#ifdef VMS
5593 "*?%$"
5594#else
5595# ifdef OS2
5596# ifdef VIM_BACKTICK
5597 "*?$`"
5598# else
5599 "*?$"
5600# endif
5601# else
5602 "*?[{`'$"
5603# endif
5604#endif
5605 , *p) != NULL
5606 || (*p == '~' && p[1] != NUL))
5607 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005608 }
5609 return FALSE;
5610}
5611
5612#ifndef __EMX__
5613 static int
5614have_wildcard(num, file)
5615 int num;
5616 char_u **file;
5617{
5618 int i;
5619
5620 for (i = 0; i < num; i++)
5621 if (mch_has_wildcard(file[i]))
5622 return 1;
5623 return 0;
5624}
5625
5626 static int
5627have_dollars(num, file)
5628 int num;
5629 char_u **file;
5630{
5631 int i;
5632
5633 for (i = 0; i < num; i++)
5634 if (vim_strchr(file[i], '$') != NULL)
5635 return TRUE;
5636 return FALSE;
5637}
5638#endif /* ifndef __EMX__ */
5639
5640#ifndef HAVE_RENAME
5641/*
5642 * Scaled-down version of rename(), which is missing in Xenix.
5643 * This version can only move regular files and will fail if the
5644 * destination exists.
5645 */
5646 int
5647mch_rename(src, dest)
5648 const char *src, *dest;
5649{
5650 struct stat st;
5651
5652 if (stat(dest, &st) >= 0) /* fail if destination exists */
5653 return -1;
5654 if (link(src, dest) != 0) /* link file to new name */
5655 return -1;
5656 if (mch_remove(src) == 0) /* delete link to old name */
5657 return 0;
5658 return -1;
5659}
5660#endif /* !HAVE_RENAME */
5661
5662#ifdef FEAT_MOUSE_GPM
5663/*
5664 * Initializes connection with gpm (if it isn't already opened)
5665 * Return 1 if succeeded (or connection already opened), 0 if failed
5666 */
5667 static int
5668gpm_open()
5669{
5670 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5671
5672 if (!gpm_flag)
5673 {
5674 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5675 gpm_connect.defaultMask = ~GPM_HARD;
5676 /* Default handling for mouse move*/
5677 gpm_connect.minMod = 0; /* Handle any modifier keys */
5678 gpm_connect.maxMod = 0xffff;
5679 if (Gpm_Open(&gpm_connect, 0) > 0)
5680 {
5681 /* gpm library tries to handling TSTP causes
5682 * problems. Anyways, we close connection to Gpm whenever
5683 * we are going to suspend or starting an external process
5684 * so we should'nt have problem with this
5685 */
5686 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5687 return 1; /* succeed */
5688 }
5689 if (gpm_fd == -2)
5690 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5691 return 0;
5692 }
5693 return 1; /* already open */
5694}
5695
5696/*
5697 * Closes connection to gpm
5698 * returns non-zero if connection succesfully closed
5699 */
5700 static void
5701gpm_close()
5702{
5703 if (gpm_flag && gpm_fd >= 0) /* if Open */
5704 Gpm_Close();
5705}
5706
5707/* Reads gpm event and adds special keys to input buf. Returns length of
5708 * generated key sequence.
5709 * This function is made after gui_send_mouse_event
5710 */
5711 static int
5712mch_gpm_process()
5713{
5714 int button;
5715 static Gpm_Event gpm_event;
5716 char_u string[6];
5717 int_u vim_modifiers;
5718 int row,col;
5719 unsigned char buttons_mask;
5720 unsigned char gpm_modifiers;
5721 static unsigned char old_buttons = 0;
5722
5723 Gpm_GetEvent(&gpm_event);
5724
5725#ifdef FEAT_GUI
5726 /* Don't put events in the input queue now. */
5727 if (hold_gui_events)
5728 return 0;
5729#endif
5730
5731 row = gpm_event.y - 1;
5732 col = gpm_event.x - 1;
5733
5734 string[0] = ESC; /* Our termcode */
5735 string[1] = 'M';
5736 string[2] = 'G';
5737 switch (GPM_BARE_EVENTS(gpm_event.type))
5738 {
5739 case GPM_DRAG:
5740 string[3] = MOUSE_DRAG;
5741 break;
5742 case GPM_DOWN:
5743 buttons_mask = gpm_event.buttons & ~old_buttons;
5744 old_buttons = gpm_event.buttons;
5745 switch (buttons_mask)
5746 {
5747 case GPM_B_LEFT:
5748 button = MOUSE_LEFT;
5749 break;
5750 case GPM_B_MIDDLE:
5751 button = MOUSE_MIDDLE;
5752 break;
5753 case GPM_B_RIGHT:
5754 button = MOUSE_RIGHT;
5755 break;
5756 default:
5757 return 0;
5758 /*Don't know what to do. Can more than one button be
5759 * reported in one event? */
5760 }
5761 string[3] = (char_u)(button | 0x20);
5762 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5763 break;
5764 case GPM_UP:
5765 string[3] = MOUSE_RELEASE;
5766 old_buttons &= ~gpm_event.buttons;
5767 break;
5768 default:
5769 return 0;
5770 }
5771 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5772 gpm_modifiers = gpm_event.modifiers;
5773 vim_modifiers = 0x0;
5774 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5775 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5776 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5777 */
5778 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5779 vim_modifiers |= MOUSE_SHIFT;
5780
5781 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5782 vim_modifiers |= MOUSE_CTRL;
5783 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5784 vim_modifiers |= MOUSE_ALT;
5785 string[3] |= vim_modifiers;
5786 string[4] = (char_u)(col + ' ' + 1);
5787 string[5] = (char_u)(row + ' ' + 1);
5788 add_to_input_buf(string, 6);
5789 return 6;
5790}
5791#endif /* FEAT_MOUSE_GPM */
5792
5793#if defined(FEAT_LIBCALL) || defined(PROTO)
5794typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
5795typedef char_u * (*INTPROCSTR)__ARGS((int));
5796typedef int (*STRPROCINT)__ARGS((char_u *));
5797typedef int (*INTPROCINT)__ARGS((int));
5798
5799/*
5800 * Call a DLL routine which takes either a string or int param
5801 * and returns an allocated string.
5802 */
5803 int
5804mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
5805 char_u *libname;
5806 char_u *funcname;
5807 char_u *argstring; /* NULL when using a argint */
5808 int argint;
5809 char_u **string_result;/* NULL when using number_result */
5810 int *number_result;
5811{
5812# if defined(USE_DLOPEN)
5813 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005814 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005815# else
5816 shl_t hinstLib;
5817# endif
5818 STRPROCSTR ProcAdd;
5819 INTPROCSTR ProcAddI;
5820 char_u *retval_str = NULL;
5821 int retval_int = 0;
5822 int success = FALSE;
5823
5824 /* Get a handle to the DLL module. */
5825# if defined(USE_DLOPEN)
5826 hinstLib = dlopen((char *)libname, RTLD_LAZY
5827# ifdef RTLD_LOCAL
5828 | RTLD_LOCAL
5829# endif
5830 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005831 if (hinstLib == NULL)
5832 {
5833 /* "dlerr" must be used before dlclose() */
5834 dlerr = (char *)dlerror();
5835 if (dlerr != NULL)
5836 EMSG2(_("dlerror = \"%s\""), dlerr);
5837 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005838# else
5839 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
5840# endif
5841
5842 /* If the handle is valid, try to get the function address. */
5843 if (hinstLib != NULL)
5844 {
5845# ifdef HAVE_SETJMP_H
5846 /*
5847 * Catch a crash when calling the library function. For example when
5848 * using a number where a string pointer is expected.
5849 */
5850 mch_startjmp();
5851 if (SETJMP(lc_jump_env) != 0)
5852 {
5853 success = FALSE;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005854 dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005855 mch_didjmp();
5856 }
5857 else
5858# endif
5859 {
5860 retval_str = NULL;
5861 retval_int = 0;
5862
5863 if (argstring != NULL)
5864 {
5865# if defined(USE_DLOPEN)
5866 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005867 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005868# else
5869 if (shl_findsym(&hinstLib, (const char *)funcname,
5870 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
5871 ProcAdd = NULL;
5872# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005873 if ((success = (ProcAdd != NULL
5874# if defined(USE_DLOPEN)
5875 && dlerr == NULL
5876# endif
5877 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005878 {
5879 if (string_result == NULL)
5880 retval_int = ((STRPROCINT)ProcAdd)(argstring);
5881 else
5882 retval_str = (ProcAdd)(argstring);
5883 }
5884 }
5885 else
5886 {
5887# if defined(USE_DLOPEN)
5888 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005889 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005890# else
5891 if (shl_findsym(&hinstLib, (const char *)funcname,
5892 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
5893 ProcAddI = NULL;
5894# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005895 if ((success = (ProcAddI != NULL
5896# if defined(USE_DLOPEN)
5897 && dlerr == NULL
5898# endif
5899 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005900 {
5901 if (string_result == NULL)
5902 retval_int = ((INTPROCINT)ProcAddI)(argint);
5903 else
5904 retval_str = (ProcAddI)(argint);
5905 }
5906 }
5907
5908 /* Save the string before we free the library. */
5909 /* Assume that a "1" or "-1" result is an illegal pointer. */
5910 if (string_result == NULL)
5911 *number_result = retval_int;
5912 else if (retval_str != NULL
5913 && retval_str != (char_u *)1
5914 && retval_str != (char_u *)-1)
5915 *string_result = vim_strsave(retval_str);
5916 }
5917
5918# ifdef HAVE_SETJMP_H
5919 mch_endjmp();
5920# ifdef SIGHASARG
5921 if (lc_signal != 0)
5922 {
5923 int i;
5924
5925 /* try to find the name of this signal */
5926 for (i = 0; signal_info[i].sig != -1; i++)
5927 if (lc_signal == signal_info[i].sig)
5928 break;
5929 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
5930 }
5931# endif
5932# endif
5933
Bram Moolenaar071d4272004-06-13 20:20:40 +00005934# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005935 /* "dlerr" must be used before dlclose() */
5936 if (dlerr != NULL)
5937 EMSG2(_("dlerror = \"%s\""), dlerr);
5938
5939 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005940 (void)dlclose(hinstLib);
5941# else
5942 (void)shl_unload(hinstLib);
5943# endif
5944 }
5945
5946 if (!success)
5947 {
5948 EMSG2(_(e_libcall), funcname);
5949 return FAIL;
5950 }
5951
5952 return OK;
5953}
5954#endif
5955
5956#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
5957static int xterm_trace = -1; /* default: disabled */
5958static int xterm_button;
5959
5960/*
5961 * Setup a dummy window for X selections in a terminal.
5962 */
5963 void
5964setup_term_clip()
5965{
5966 int z = 0;
5967 char *strp = "";
5968 Widget AppShell;
5969
5970 if (!x_connect_to_server())
5971 return;
5972
5973 open_app_context();
5974 if (app_context != NULL && xterm_Shell == (Widget)0)
5975 {
5976 int (*oldhandler)();
5977#if defined(HAVE_SETJMP_H)
5978 int (*oldIOhandler)();
5979#endif
5980# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5981 struct timeval start_tv;
5982
5983 if (p_verbose > 0)
5984 gettimeofday(&start_tv, NULL);
5985# endif
5986
5987 /* Ignore X errors while opening the display */
5988 oldhandler = XSetErrorHandler(x_error_check);
5989
5990#if defined(HAVE_SETJMP_H)
5991 /* Ignore X IO errors while opening the display */
5992 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
5993 mch_startjmp();
5994 if (SETJMP(lc_jump_env) != 0)
5995 {
5996 mch_didjmp();
5997 xterm_dpy = NULL;
5998 }
5999 else
6000#endif
6001 {
6002 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
6003 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
6004#if defined(HAVE_SETJMP_H)
6005 mch_endjmp();
6006#endif
6007 }
6008
6009#if defined(HAVE_SETJMP_H)
6010 /* Now handle X IO errors normally. */
6011 (void)XSetIOErrorHandler(oldIOhandler);
6012#endif
6013 /* Now handle X errors normally. */
6014 (void)XSetErrorHandler(oldhandler);
6015
6016 if (xterm_dpy == NULL)
6017 {
6018 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006019 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006020 return;
6021 }
6022
6023 /* Catch terminating error of the X server connection. */
6024 (void)XSetIOErrorHandler(x_IOerror_handler);
6025
6026# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
6027 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006028 {
6029 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006030 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006031 verbose_leave();
6032 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006033# endif
6034
6035 /* Create a Shell to make converters work. */
6036 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6037 applicationShellWidgetClass, xterm_dpy,
6038 NULL);
6039 if (AppShell == (Widget)0)
6040 return;
6041 xterm_Shell = XtVaCreatePopupShell("VIM",
6042 topLevelShellWidgetClass, AppShell,
6043 XtNmappedWhenManaged, 0,
6044 XtNwidth, 1,
6045 XtNheight, 1,
6046 NULL);
6047 if (xterm_Shell == (Widget)0)
6048 return;
6049
6050 x11_setup_atoms(xterm_dpy);
6051 if (x11_display == NULL)
6052 x11_display = xterm_dpy;
6053
6054 XtRealizeWidget(xterm_Shell);
6055 XSync(xterm_dpy, False);
6056 xterm_update();
6057 }
6058 if (xterm_Shell != (Widget)0)
6059 {
6060 clip_init(TRUE);
6061 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6062 x11_window = (Window)atol(strp);
6063 /* Check if $WINDOWID is valid. */
6064 if (test_x11_window(xterm_dpy) == FAIL)
6065 x11_window = 0;
6066 if (x11_window != 0)
6067 xterm_trace = 0;
6068 }
6069}
6070
6071 void
6072start_xterm_trace(button)
6073 int button;
6074{
6075 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6076 return;
6077 xterm_trace = 1;
6078 xterm_button = button;
6079 do_xterm_trace();
6080}
6081
6082
6083 void
6084stop_xterm_trace()
6085{
6086 if (xterm_trace < 0)
6087 return;
6088 xterm_trace = 0;
6089}
6090
6091/*
6092 * Query the xterm pointer and generate mouse termcodes if necessary
6093 * return TRUE if dragging is active, else FALSE
6094 */
6095 static int
6096do_xterm_trace()
6097{
6098 Window root, child;
6099 int root_x, root_y;
6100 int win_x, win_y;
6101 int row, col;
6102 int_u mask_return;
6103 char_u buf[50];
6104 char_u *strp;
6105 long got_hints;
6106 static char_u *mouse_code;
6107 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6108 static int prev_row = 0, prev_col = 0;
6109 static XSizeHints xterm_hints;
6110
6111 if (xterm_trace <= 0)
6112 return FALSE;
6113
6114 if (xterm_trace == 1)
6115 {
6116 /* Get the hints just before tracking starts. The font size might
6117 * have changed recently */
6118 XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints);
6119 if (!(got_hints & PResizeInc)
6120 || xterm_hints.width_inc <= 1
6121 || xterm_hints.height_inc <= 1)
6122 {
6123 xterm_trace = -1; /* Not enough data -- disable tracing */
6124 return FALSE;
6125 }
6126
6127 /* Rely on the same mouse code for the duration of this */
6128 mouse_code = find_termcode(mouse_name);
6129 prev_row = mouse_row;
6130 prev_row = mouse_col;
6131 xterm_trace = 2;
6132
6133 /* Find the offset of the chars, there might be a scrollbar on the
6134 * left of the window and/or a menu on the top (eterm etc.) */
6135 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6136 &win_x, &win_y, &mask_return);
6137 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6138 - (xterm_hints.height_inc / 2);
6139 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6140 xterm_hints.y = 2;
6141 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6142 - (xterm_hints.width_inc / 2);
6143 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6144 xterm_hints.x = 2;
6145 return TRUE;
6146 }
6147 if (mouse_code == NULL)
6148 {
6149 xterm_trace = 0;
6150 return FALSE;
6151 }
6152
6153 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6154 &win_x, &win_y, &mask_return);
6155
6156 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6157 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6158 if (row == prev_row && col == prev_col)
6159 return TRUE;
6160
6161 STRCPY(buf, mouse_code);
6162 strp = buf + STRLEN(buf);
6163 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6164 *strp++ = (char_u)(col + ' ' + 1);
6165 *strp++ = (char_u)(row + ' ' + 1);
6166 *strp = 0;
6167 add_to_input_buf(buf, STRLEN(buf));
6168
6169 prev_row = row;
6170 prev_col = col;
6171 return TRUE;
6172}
6173
6174# if defined(FEAT_GUI) || defined(PROTO)
6175/*
6176 * Destroy the display, window and app_context. Required for GTK.
6177 */
6178 void
6179clear_xterm_clip()
6180{
6181 if (xterm_Shell != (Widget)0)
6182 {
6183 XtDestroyWidget(xterm_Shell);
6184 xterm_Shell = (Widget)0;
6185 }
6186 if (xterm_dpy != NULL)
6187 {
6188#if 0
6189 /* Lesstif and Solaris crash here, lose some memory */
6190 XtCloseDisplay(xterm_dpy);
6191#endif
6192 if (x11_display == xterm_dpy)
6193 x11_display = NULL;
6194 xterm_dpy = NULL;
6195 }
6196#if 0
6197 if (app_context != (XtAppContext)NULL)
6198 {
6199 /* Lesstif and Solaris crash here, lose some memory */
6200 XtDestroyApplicationContext(app_context);
6201 app_context = (XtAppContext)NULL;
6202 }
6203#endif
6204}
6205# endif
6206
6207/*
6208 * Catch up with any queued X events. This may put keyboard input into the
6209 * input buffer, call resize call-backs, trigger timers etc. If there is
6210 * nothing in the X event queue (& no timers pending), then we return
6211 * immediately.
6212 */
6213 static void
6214xterm_update()
6215{
6216 XEvent event;
6217
6218 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6219 {
6220 XtAppNextEvent(app_context, &event);
6221#ifdef FEAT_CLIENTSERVER
6222 {
6223 XPropertyEvent *e = (XPropertyEvent *)&event;
6224
6225 if (e->type == PropertyNotify && e->window == commWindow
6226 && e->atom == commProperty && e->state == PropertyNewValue)
6227 serverEventProc(xterm_dpy, &event);
6228 }
6229#endif
6230 XtDispatchEvent(&event);
6231 }
6232}
6233
6234 int
6235clip_xterm_own_selection(cbd)
6236 VimClipboard *cbd;
6237{
6238 if (xterm_Shell != (Widget)0)
6239 return clip_x11_own_selection(xterm_Shell, cbd);
6240 return FAIL;
6241}
6242
6243 void
6244clip_xterm_lose_selection(cbd)
6245 VimClipboard *cbd;
6246{
6247 if (xterm_Shell != (Widget)0)
6248 clip_x11_lose_selection(xterm_Shell, cbd);
6249}
6250
6251 void
6252clip_xterm_request_selection(cbd)
6253 VimClipboard *cbd;
6254{
6255 if (xterm_Shell != (Widget)0)
6256 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6257}
6258
6259 void
6260clip_xterm_set_selection(cbd)
6261 VimClipboard *cbd;
6262{
6263 clip_x11_set_selection(cbd);
6264}
6265#endif
6266
6267
6268#if defined(USE_XSMP) || defined(PROTO)
6269/*
6270 * Code for X Session Management Protocol.
6271 */
6272static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6273static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6274static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6275static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6276static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6277
6278
6279# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6280static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6281
6282/*
6283 * This is our chance to ask the user if they want to save,
6284 * or abort the logout
6285 */
6286/*ARGSUSED*/
6287 static void
6288xsmp_handle_interaction(smc_conn, client_data)
6289 SmcConn smc_conn;
6290 SmPointer client_data;
6291{
6292 cmdmod_T save_cmdmod;
6293 int cancel_shutdown = False;
6294
6295 save_cmdmod = cmdmod;
6296 cmdmod.confirm = TRUE;
6297 if (check_changed_any(FALSE))
6298 /* Mustn't logout */
6299 cancel_shutdown = True;
6300 cmdmod = save_cmdmod;
6301 setcursor(); /* position cursor */
6302 out_flush();
6303
6304 /* Done interaction */
6305 SmcInteractDone(smc_conn, cancel_shutdown);
6306
6307 /* Finish off
6308 * Only end save-yourself here if we're not cancelling shutdown;
6309 * we'll get a cancelled callback later in which we'll end it.
6310 * Hopefully get around glitchy SMs (like GNOME-1)
6311 */
6312 if (!cancel_shutdown)
6313 {
6314 xsmp.save_yourself = False;
6315 SmcSaveYourselfDone(smc_conn, True);
6316 }
6317}
6318# endif
6319
6320/*
6321 * Callback that starts save-yourself.
6322 */
6323/*ARGSUSED*/
6324 static void
6325xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6326 shutdown, interact_style, fast)
6327 SmcConn smc_conn;
6328 SmPointer client_data;
6329 int save_type;
6330 Bool shutdown;
6331 int interact_style;
6332 Bool fast;
6333{
6334 /* Handle already being in saveyourself */
6335 if (xsmp.save_yourself)
6336 SmcSaveYourselfDone(smc_conn, True);
6337 xsmp.save_yourself = True;
6338 xsmp.shutdown = shutdown;
6339
6340 /* First up, preserve all files */
6341 out_flush();
6342 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6343
6344 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006345 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006346
6347# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6348 /* Now see if we can ask about unsaved files */
6349 if (shutdown && !fast && gui.in_use)
6350 /* Need to interact with user, but need SM's permission */
6351 SmcInteractRequest(smc_conn, SmDialogError,
6352 xsmp_handle_interaction, client_data);
6353 else
6354# endif
6355 {
6356 /* Can stop the cycle here */
6357 SmcSaveYourselfDone(smc_conn, True);
6358 xsmp.save_yourself = False;
6359 }
6360}
6361
6362
6363/*
6364 * Callback to warn us of imminent death.
6365 */
6366/*ARGSUSED*/
6367 static void
6368xsmp_die(smc_conn, client_data)
6369 SmcConn smc_conn;
6370 SmPointer client_data;
6371{
6372 xsmp_close();
6373
6374 /* quit quickly leaving swapfiles for modified buffers behind */
6375 getout_preserve_modified(0);
6376}
6377
6378
6379/*
6380 * Callback to tell us that save-yourself has completed.
6381 */
6382/*ARGSUSED*/
6383 static void
6384xsmp_save_complete(smc_conn, client_data)
6385 SmcConn smc_conn;
6386 SmPointer client_data;
6387{
6388 xsmp.save_yourself = False;
6389}
6390
6391
6392/*
6393 * Callback to tell us that an instigated shutdown was cancelled
6394 * (maybe even by us)
6395 */
6396/*ARGSUSED*/
6397 static void
6398xsmp_shutdown_cancelled(smc_conn, client_data)
6399 SmcConn smc_conn;
6400 SmPointer client_data;
6401{
6402 if (xsmp.save_yourself)
6403 SmcSaveYourselfDone(smc_conn, True);
6404 xsmp.save_yourself = False;
6405 xsmp.shutdown = False;
6406}
6407
6408
6409/*
6410 * Callback to tell us that a new ICE connection has been established.
6411 */
6412/*ARGSUSED*/
6413 static void
6414xsmp_ice_connection(iceConn, clientData, opening, watchData)
6415 IceConn iceConn;
6416 IcePointer clientData;
6417 Bool opening;
6418 IcePointer *watchData;
6419{
6420 /* Intercept creation of ICE connection fd */
6421 if (opening)
6422 {
6423 xsmp_icefd = IceConnectionNumber(iceConn);
6424 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6425 }
6426}
6427
6428
6429/* Handle any ICE processing that's required; return FAIL if SM lost */
6430 int
6431xsmp_handle_requests()
6432{
6433 Bool rep;
6434
6435 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6436 == IceProcessMessagesIOError)
6437 {
6438 /* Lost ICE */
6439 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006440 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006441 xsmp_close();
6442 return FAIL;
6443 }
6444 else
6445 return OK;
6446}
6447
6448static int dummy;
6449
6450/* Set up X Session Management Protocol */
6451 void
6452xsmp_init(void)
6453{
6454 char errorstring[80];
6455 char *clientid;
6456 SmcCallbacks smcallbacks;
6457#if 0
6458 SmPropValue smname;
6459 SmProp smnameprop;
6460 SmProp *smprops[1];
6461#endif
6462
6463 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006464 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006465
6466 xsmp.save_yourself = xsmp.shutdown = False;
6467
6468 /* Set up SM callbacks - must have all, even if they're not used */
6469 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6470 smcallbacks.save_yourself.client_data = NULL;
6471 smcallbacks.die.callback = xsmp_die;
6472 smcallbacks.die.client_data = NULL;
6473 smcallbacks.save_complete.callback = xsmp_save_complete;
6474 smcallbacks.save_complete.client_data = NULL;
6475 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6476 smcallbacks.shutdown_cancelled.client_data = NULL;
6477
6478 /* Set up a watch on ICE connection creations. The "dummy" argument is
6479 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6480 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6481 {
6482 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006483 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006484 return;
6485 }
6486
6487 /* Create an SM connection */
6488 xsmp.smcconn = SmcOpenConnection(
6489 NULL,
6490 NULL,
6491 SmProtoMajor,
6492 SmProtoMinor,
6493 SmcSaveYourselfProcMask | SmcDieProcMask
6494 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6495 &smcallbacks,
6496 NULL,
6497 &clientid,
6498 sizeof(errorstring),
6499 errorstring);
6500 if (xsmp.smcconn == NULL)
6501 {
6502 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00006503
Bram Moolenaar071d4272004-06-13 20:20:40 +00006504 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006505 {
6506 vim_snprintf(errorreport, sizeof(errorreport),
6507 _("XSMP SmcOpenConnection failed: %s"), errorstring);
6508 verb_msg((char_u *)errorreport);
6509 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006510 return;
6511 }
6512 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6513
6514#if 0
6515 /* ID ourselves */
6516 smname.value = "vim";
6517 smname.length = 3;
6518 smnameprop.name = "SmProgram";
6519 smnameprop.type = "SmARRAY8";
6520 smnameprop.num_vals = 1;
6521 smnameprop.vals = &smname;
6522
6523 smprops[0] = &smnameprop;
6524 SmcSetProperties(xsmp.smcconn, 1, smprops);
6525#endif
6526}
6527
6528
6529/* Shut down XSMP comms. */
6530 void
6531xsmp_close()
6532{
6533 if (xsmp_icefd != -1)
6534 {
6535 SmcCloseConnection(xsmp.smcconn, 0, NULL);
6536 xsmp_icefd = -1;
6537 }
6538}
6539#endif /* USE_XSMP */
6540
6541
6542#ifdef EBCDIC
6543/* Translate character to its CTRL- value */
6544char CtrlTable[] =
6545{
6546/* 00 - 5E */
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, 0,
6549 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6550 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6551 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6552 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6553/* ^ */ 0x1E,
6554/* - */ 0x1F,
6555/* 61 - 6C */
6556 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6557/* _ */ 0x1F,
6558/* 6E - 80 */
6559 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6560/* a */ 0x01,
6561/* b */ 0x02,
6562/* c */ 0x03,
6563/* d */ 0x37,
6564/* e */ 0x2D,
6565/* f */ 0x2E,
6566/* g */ 0x2F,
6567/* h */ 0x16,
6568/* i */ 0x05,
6569/* 8A - 90 */
6570 0, 0, 0, 0, 0, 0, 0,
6571/* j */ 0x15,
6572/* k */ 0x0B,
6573/* l */ 0x0C,
6574/* m */ 0x0D,
6575/* n */ 0x0E,
6576/* o */ 0x0F,
6577/* p */ 0x10,
6578/* q */ 0x11,
6579/* r */ 0x12,
6580/* 9A - A1 */
6581 0, 0, 0, 0, 0, 0, 0, 0,
6582/* s */ 0x13,
6583/* t */ 0x3C,
6584/* u */ 0x3D,
6585/* v */ 0x32,
6586/* w */ 0x26,
6587/* x */ 0x18,
6588/* y */ 0x19,
6589/* z */ 0x3F,
6590/* AA - AC */
6591 0, 0, 0,
6592/* [ */ 0x27,
6593/* AE - BC */
6594 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6595/* ] */ 0x1D,
6596/* BE - C0 */ 0, 0, 0,
6597/* A */ 0x01,
6598/* B */ 0x02,
6599/* C */ 0x03,
6600/* D */ 0x37,
6601/* E */ 0x2D,
6602/* F */ 0x2E,
6603/* G */ 0x2F,
6604/* H */ 0x16,
6605/* I */ 0x05,
6606/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6607/* J */ 0x15,
6608/* K */ 0x0B,
6609/* L */ 0x0C,
6610/* M */ 0x0D,
6611/* N */ 0x0E,
6612/* O */ 0x0F,
6613/* P */ 0x10,
6614/* Q */ 0x11,
6615/* R */ 0x12,
6616/* DA - DF */ 0, 0, 0, 0, 0, 0,
6617/* \ */ 0x1C,
6618/* E1 */ 0,
6619/* S */ 0x13,
6620/* T */ 0x3C,
6621/* U */ 0x3D,
6622/* V */ 0x32,
6623/* W */ 0x26,
6624/* X */ 0x18,
6625/* Y */ 0x19,
6626/* Z */ 0x3F,
6627/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6628 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6629};
6630
6631char MetaCharTable[]=
6632{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6633 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6634 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6635 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6636 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6637};
6638
6639
6640/* TODO: Use characters NOT numbers!!! */
6641char CtrlCharTable[]=
6642{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6643 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6644 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6645 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6646 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6647};
6648
6649
6650#endif