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