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