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