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