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