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