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