blob: f41ed464b487292378d17625d5c950d05a83c9eb [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
1310 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
1311}
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);
2095 return OK;
2096 }
2097#endif
2098 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2099 return FAIL; /* a number is not a name */
2100}
2101
2102/*
2103 * Insert host name is s[len].
2104 */
2105
2106#ifdef HAVE_SYS_UTSNAME_H
2107 void
2108mch_get_host_name(s, len)
2109 char_u *s;
2110 int len;
2111{
2112 struct utsname vutsname;
2113
2114 if (uname(&vutsname) < 0)
2115 *s = NUL;
2116 else
2117 STRNCPY(s, vutsname.nodename, len);
2118 s[len - 1] = NUL; /* make sure it's terminated */
2119}
2120#else /* HAVE_SYS_UTSNAME_H */
2121
2122# ifdef HAVE_SYS_SYSTEMINFO_H
2123# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2124# endif
2125
2126 void
2127mch_get_host_name(s, len)
2128 char_u *s;
2129 int len;
2130{
2131# ifdef VAXC
2132 vaxc$gethostname((char *)s, len);
2133# else
2134 gethostname((char *)s, len);
2135# endif
2136 s[len - 1] = NUL; /* make sure it's terminated */
2137}
2138#endif /* HAVE_SYS_UTSNAME_H */
2139
2140/*
2141 * return process ID
2142 */
2143 long
2144mch_get_pid()
2145{
2146 return (long)getpid();
2147}
2148
2149#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2150static char *strerror __ARGS((int));
2151
2152 static char *
2153strerror(err)
2154 int err;
2155{
2156 extern int sys_nerr;
2157 extern char *sys_errlist[];
2158 static char er[20];
2159
2160 if (err > 0 && err < sys_nerr)
2161 return (sys_errlist[err]);
2162 sprintf(er, "Error %d", err);
2163 return er;
2164}
2165#endif
2166
2167/*
2168 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2169 * Return OK for success, FAIL for failure.
2170 */
2171 int
2172mch_dirname(buf, len)
2173 char_u *buf;
2174 int len;
2175{
2176#if defined(USE_GETCWD)
2177 if (getcwd((char *)buf, len) == NULL)
2178 {
2179 STRCPY(buf, strerror(errno));
2180 return FAIL;
2181 }
2182 return OK;
2183#else
2184 return (getwd((char *)buf) != NULL ? OK : FAIL);
2185#endif
2186}
2187
2188#if defined(OS2) || defined(PROTO)
2189/*
2190 * Replace all slashes by backslashes.
2191 * When 'shellslash' set do it the other way around.
2192 */
2193 void
2194slash_adjust(p)
2195 char_u *p;
2196{
2197 while (*p)
2198 {
2199 if (*p == psepcN)
2200 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002201 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002202 }
2203}
2204#endif
2205
2206/*
2207 * Get absolute file name into buffer 'buf' of length 'len' bytes.
2208 *
2209 * return FAIL for failure, OK for success
2210 */
2211 int
2212mch_FullName(fname, buf, len, force)
2213 char_u *fname, *buf;
2214 int len;
2215 int force; /* also expand when already absolute path */
2216{
2217 int l;
2218#ifdef OS2
2219 int only_drive; /* file name is only a drive letter */
2220#endif
2221#ifdef HAVE_FCHDIR
2222 int fd = -1;
2223 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
2224#endif
2225 char_u olddir[MAXPATHL];
2226 char_u *p;
2227 int retval = OK;
2228
2229#ifdef VMS
2230 fname = vms_fixfilename(fname);
2231#endif
2232
2233 /* expand it if forced or not an absolute path */
2234 if (force || !mch_isFullName(fname))
2235 {
2236 /*
2237 * If the file name has a path, change to that directory for a moment,
2238 * and then do the getwd() (and get back to where we were).
2239 * This will get the correct path name with "../" things.
2240 */
2241#ifdef OS2
2242 only_drive = 0;
2243 if (((p = vim_strrchr(fname, '/')) != NULL)
2244 || ((p = vim_strrchr(fname, '\\')) != NULL)
2245 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
2246#else
2247 if ((p = vim_strrchr(fname, '/')) != NULL)
2248#endif
2249 {
2250#ifdef HAVE_FCHDIR
2251 /*
2252 * Use fchdir() if possible, it's said to be faster and more
2253 * reliable. But on SunOS 4 it might not work. Check this by
2254 * doing a fchdir() right now.
2255 */
2256 if (!dont_fchdir)
2257 {
2258 fd = open(".", O_RDONLY | O_EXTRA, 0);
2259 if (fd >= 0 && fchdir(fd) < 0)
2260 {
2261 close(fd);
2262 fd = -1;
2263 dont_fchdir = TRUE; /* don't try again */
2264 }
2265 }
2266#endif
2267
2268 /* Only change directory when we are sure we can return to where
2269 * we are now. After doing "su" chdir(".") might not work. */
2270 if (
2271#ifdef HAVE_FCHDIR
2272 fd < 0 &&
2273#endif
2274 (mch_dirname(olddir, MAXPATHL) == FAIL
2275 || mch_chdir((char *)olddir) != 0))
2276 {
2277 p = NULL; /* can't get current dir: don't chdir */
2278 retval = FAIL;
2279 }
2280 else
2281 {
2282#ifdef OS2
2283 /*
2284 * compensate for case where ':' from "D:" was the only
2285 * path separator detected in the file name; the _next_
2286 * character has to be removed, and then restored later.
2287 */
2288 if (only_drive)
2289 p++;
2290#endif
2291 /* The directory is copied into buf[], to be able to remove
2292 * the file name without changing it (could be a string in
2293 * read-only memory) */
2294 if (p - fname >= len)
2295 retval = FAIL;
2296 else
2297 {
2298 STRNCPY(buf, fname, p - fname);
2299 buf[p - fname] = NUL;
2300 if (mch_chdir((char *)buf))
2301 retval = FAIL;
2302 else
2303 fname = p + 1;
2304 *buf = NUL;
2305 }
2306#ifdef OS2
2307 if (only_drive)
2308 {
2309 p--;
2310 if (retval != FAIL)
2311 fname--;
2312 }
2313#endif
2314 }
2315 }
2316 if (mch_dirname(buf, len) == FAIL)
2317 {
2318 retval = FAIL;
2319 *buf = NUL;
2320 }
2321 if (p != NULL)
2322 {
2323#ifdef HAVE_FCHDIR
2324 if (fd >= 0)
2325 {
2326 l = fchdir(fd);
2327 close(fd);
2328 }
2329 else
2330#endif
2331 l = mch_chdir((char *)olddir);
2332 if (l != 0)
2333 EMSG(_(e_prev_dir));
2334 }
2335
2336 l = STRLEN(buf);
2337 if (l >= len)
2338 retval = FAIL;
2339#ifndef VMS
2340 else
2341 {
2342 if (l > 0 && buf[l - 1] != '/' && *fname != NUL
2343 && STRCMP(fname, ".") != 0)
2344 STRCAT(buf, "/");
2345 }
2346#endif
2347 }
2348 /* Catch file names which are too long. */
2349 if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len)
2350 return FAIL;
2351
2352 /* Do not append ".", "/dir/." is equal to "/dir". */
2353 if (STRCMP(fname, ".") != 0)
2354 STRCAT(buf, fname);
2355
2356 return OK;
2357}
2358
2359/*
2360 * Return TRUE if "fname" does not depend on the current directory.
2361 */
2362 int
2363mch_isFullName(fname)
2364 char_u *fname;
2365{
2366#ifdef __EMX__
2367 return _fnisabs(fname);
2368#else
2369# ifdef VMS
2370 return ( fname[0] == '/' || fname[0] == '.' ||
2371 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2372 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2373 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2374# else
2375 return (*fname == '/' || *fname == '~');
2376# endif
2377#endif
2378}
2379
2380/*
2381 * Get file permissions for 'name'.
2382 * Returns -1 when it doesn't exist.
2383 */
2384 long
2385mch_getperm(name)
2386 char_u *name;
2387{
2388 struct stat statb;
2389
2390 /* Keep the #ifdef outside of stat(), it may be a macro. */
2391#ifdef VMS
2392 if (stat((char *)vms_fixfilename(name), &statb))
2393#else
2394 if (stat((char *)name, &statb))
2395#endif
2396 return -1;
2397 return statb.st_mode;
2398}
2399
2400/*
2401 * set file permission for 'name' to 'perm'
2402 *
2403 * return FAIL for failure, OK otherwise
2404 */
2405 int
2406mch_setperm(name, perm)
2407 char_u *name;
2408 long perm;
2409{
2410 return (chmod((char *)
2411#ifdef VMS
2412 vms_fixfilename(name),
2413#else
2414 name,
2415#endif
2416 (mode_t)perm) == 0 ? OK : FAIL);
2417}
2418
2419#if defined(HAVE_ACL) || defined(PROTO)
2420# ifdef HAVE_SYS_ACL_H
2421# include <sys/acl.h>
2422# endif
2423# ifdef HAVE_SYS_ACCESS_H
2424# include <sys/access.h>
2425# endif
2426
2427# ifdef HAVE_SOLARIS_ACL
2428typedef struct vim_acl_solaris_T {
2429 int acl_cnt;
2430 aclent_t *acl_entry;
2431} vim_acl_solaris_T;
2432# endif
2433
2434/*
2435 * Return a pointer to the ACL of file "fname" in allocated memory.
2436 * Return NULL if the ACL is not available for whatever reason.
2437 */
2438 vim_acl_T
2439mch_get_acl(fname)
2440 char_u *fname;
2441{
2442 vim_acl_T ret = NULL;
2443#ifdef HAVE_POSIX_ACL
2444 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2445#else
2446#ifdef HAVE_SOLARIS_ACL
2447 vim_acl_solaris_T *aclent;
2448
2449 aclent = malloc(sizeof(vim_acl_solaris_T));
2450 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2451 {
2452 free(aclent);
2453 return NULL;
2454 }
2455 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2456 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2457 {
2458 free(aclent->acl_entry);
2459 free(aclent);
2460 return NULL;
2461 }
2462 ret = (vim_acl_T)aclent;
2463#else
2464#if defined(HAVE_AIX_ACL)
2465 int aclsize;
2466 struct acl *aclent;
2467
2468 aclsize = sizeof(struct acl);
2469 aclent = malloc(aclsize);
2470 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2471 {
2472 if (errno == ENOSPC)
2473 {
2474 aclsize = aclent->acl_len;
2475 aclent = realloc(aclent, aclsize);
2476 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2477 {
2478 free(aclent);
2479 return NULL;
2480 }
2481 }
2482 else
2483 {
2484 free(aclent);
2485 return NULL;
2486 }
2487 }
2488 ret = (vim_acl_T)aclent;
2489#endif /* HAVE_AIX_ACL */
2490#endif /* HAVE_SOLARIS_ACL */
2491#endif /* HAVE_POSIX_ACL */
2492 return ret;
2493}
2494
2495/*
2496 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2497 */
2498 void
2499mch_set_acl(fname, aclent)
2500 char_u *fname;
2501 vim_acl_T aclent;
2502{
2503 if (aclent == NULL)
2504 return;
2505#ifdef HAVE_POSIX_ACL
2506 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2507#else
2508#ifdef HAVE_SOLARIS_ACL
2509 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2510 ((vim_acl_solaris_T *)aclent)->acl_entry);
2511#else
2512#ifdef HAVE_AIX_ACL
2513 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2514#endif /* HAVE_AIX_ACL */
2515#endif /* HAVE_SOLARIS_ACL */
2516#endif /* HAVE_POSIX_ACL */
2517}
2518
2519 void
2520mch_free_acl(aclent)
2521 vim_acl_T aclent;
2522{
2523 if (aclent == NULL)
2524 return;
2525#ifdef HAVE_POSIX_ACL
2526 acl_free((acl_t)aclent);
2527#else
2528#ifdef HAVE_SOLARIS_ACL
2529 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2530 free(aclent);
2531#else
2532#ifdef HAVE_AIX_ACL
2533 free(aclent);
2534#endif /* HAVE_AIX_ACL */
2535#endif /* HAVE_SOLARIS_ACL */
2536#endif /* HAVE_POSIX_ACL */
2537}
2538#endif
2539
2540/*
2541 * Set hidden flag for "name".
2542 */
2543/* ARGSUSED */
2544 void
2545mch_hide(name)
2546 char_u *name;
2547{
2548 /* can't hide a file */
2549}
2550
2551/*
2552 * return TRUE if "name" is a directory
2553 * return FALSE if "name" is not a directory
2554 * return FALSE for error
2555 */
2556 int
2557mch_isdir(name)
2558 char_u *name;
2559{
2560 struct stat statb;
2561
2562 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2563 return FALSE;
2564 if (stat((char *)name, &statb))
2565 return FALSE;
2566#ifdef _POSIX_SOURCE
2567 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2568#else
2569 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2570#endif
2571}
2572
2573#if defined(FEAT_EVAL) || defined(PROTO)
2574
2575static int executable_file __ARGS((char_u *name));
2576
2577/*
2578 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2579 */
2580 static int
2581executable_file(name)
2582 char_u *name;
2583{
2584 struct stat st;
2585
2586 if (stat((char *)name, &st))
2587 return 0;
2588 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2589}
2590
2591/*
2592 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2593 * Return -1 if unknown.
2594 */
2595 int
2596mch_can_exe(name)
2597 char_u *name;
2598{
2599 char_u *buf;
2600 char_u *p, *e;
2601 int retval;
2602
2603 /* If it's an absolute or relative path don't need to use $PATH. */
2604 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2605 || (name[1] == '.' && name[2] == '/'))))
2606 return executable_file(name);
2607
2608 p = (char_u *)getenv("PATH");
2609 if (p == NULL || *p == NUL)
2610 return -1;
2611 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2612 if (buf == NULL)
2613 return -1;
2614
2615 /*
2616 * Walk through all entries in $PATH to check if "name" exists there and
2617 * is an executable file.
2618 */
2619 for (;;)
2620 {
2621 e = (char_u *)strchr((char *)p, ':');
2622 if (e == NULL)
2623 e = p + STRLEN(p);
2624 if (e - p <= 1) /* empty entry means current dir */
2625 STRCPY(buf, "./");
2626 else
2627 {
2628 STRNCPY(buf, p, e - p);
2629 buf[e - p] = NUL;
2630 add_pathsep(buf);
2631 }
2632 STRCAT(buf, name);
2633 retval = executable_file(buf);
2634 if (retval == 1)
2635 break;
2636
2637 if (*e != ':')
2638 break;
2639 p = e + 1;
2640 }
2641
2642 vim_free(buf);
2643 return retval;
2644}
2645#endif
2646
2647/*
2648 * Check what "name" is:
2649 * NODE_NORMAL: file or directory (or doesn't exist)
2650 * NODE_WRITABLE: writable device, socket, fifo, etc.
2651 * NODE_OTHER: non-writable things
2652 */
2653 int
2654mch_nodetype(name)
2655 char_u *name;
2656{
2657 struct stat st;
2658
2659 if (stat((char *)name, &st))
2660 return NODE_NORMAL;
2661 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2662 return NODE_NORMAL;
2663#ifndef OS2
2664 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2665 return NODE_OTHER;
2666#endif
2667 /* Everything else is writable? */
2668 return NODE_WRITABLE;
2669}
2670
2671 void
2672mch_early_init()
2673{
2674#ifdef HAVE_CHECK_STACK_GROWTH
2675 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002676
Bram Moolenaar071d4272004-06-13 20:20:40 +00002677 check_stack_growth((char *)&i);
2678
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002679# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002680 get_stack_limit();
2681# endif
2682
2683#endif
2684
2685 /*
2686 * Setup an alternative stack for signals. Helps to catch signals when
2687 * running out of stack space.
2688 * Use of sigaltstack() is preferred, it's more portable.
2689 * Ignore any errors.
2690 */
2691#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2692 signal_stack = malloc(SIGSTKSZ);
2693 init_signal_stack();
2694#endif
2695}
2696
2697static void exit_scroll __ARGS((void));
2698
2699/*
2700 * Output a newline when exiting.
2701 * Make sure the newline goes to the same stream as the text.
2702 */
2703 static void
2704exit_scroll()
2705{
Bram Moolenaardf177f62005-02-22 08:39:57 +00002706 if (silent_mode)
2707 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002708 if (newline_on_exit || msg_didout)
2709 {
2710 if (msg_use_printf())
2711 {
2712 if (info_message)
2713 mch_msg("\n");
2714 else
2715 mch_errmsg("\r\n");
2716 }
2717 else
2718 out_char('\n');
2719 }
2720 else
2721 {
2722 restore_cterm_colors(); /* get original colors back */
2723 msg_clr_eos_force(); /* clear the rest of the display */
2724 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
2725 }
2726}
2727
2728 void
2729mch_exit(r)
2730 int r;
2731{
2732 exiting = TRUE;
2733
2734#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
2735 x11_export_final_selection();
2736#endif
2737
2738#ifdef FEAT_GUI
2739 if (!gui.in_use)
2740#endif
2741 {
2742 settmode(TMODE_COOK);
2743#ifdef FEAT_TITLE
2744 mch_restore_title(3); /* restore xterm title and icon name */
2745#endif
2746 /*
2747 * When t_ti is not empty but it doesn't cause swapping terminal
2748 * pages, need to output a newline when msg_didout is set. But when
2749 * t_ti does swap pages it should not go to the shell page. Do this
2750 * before stoptermcap().
2751 */
2752 if (swapping_screen() && !newline_on_exit)
2753 exit_scroll();
2754
2755 /* Stop termcap: May need to check for T_CRV response, which
2756 * requires RAW mode. */
2757 stoptermcap();
2758
2759 /*
2760 * A newline is only required after a message in the alternate screen.
2761 * This is set to TRUE by wait_return().
2762 */
2763 if (!swapping_screen() || newline_on_exit)
2764 exit_scroll();
2765
2766 /* Cursor may have been switched off without calling starttermcap()
2767 * when doing "vim -u vimrc" and vimrc contains ":q". */
2768 if (full_screen)
2769 cursor_on();
2770 }
2771 out_flush();
2772 ml_close_all(TRUE); /* remove all memfiles */
2773 may_core_dump();
2774#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002775 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002776 gui_exit(r);
2777#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00002778
2779#if defined(MACOS_X) && defined(FEAT_MBYTE)
2780 mac_conv_cleanup();
2781#endif
2782
Bram Moolenaar071d4272004-06-13 20:20:40 +00002783#ifdef __QNX__
2784 /* A core dump won't be created if the signal handler
2785 * doesn't return, so we can't call exit() */
2786 if (deadly_signal != 0)
2787 return;
2788#endif
2789
Bram Moolenaar009b2592004-10-24 19:18:58 +00002790#ifdef FEAT_NETBEANS_INTG
2791 if (usingNetbeans)
2792 netbeans_send_disconnect();
2793#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002794 exit(r);
2795}
2796
2797 static void
2798may_core_dump()
2799{
2800 if (deadly_signal != 0)
2801 {
2802 signal(deadly_signal, SIG_DFL);
2803 kill(getpid(), deadly_signal); /* Die using the signal we caught */
2804 }
2805}
2806
2807#ifndef VMS
2808
2809 void
2810mch_settmode(tmode)
2811 int tmode;
2812{
2813 static int first = TRUE;
2814
2815 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2816#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2817 /*
2818 * for "new" tty systems
2819 */
2820# ifdef HAVE_TERMIOS_H
2821 static struct termios told;
2822 struct termios tnew;
2823# else
2824 static struct termio told;
2825 struct termio tnew;
2826# endif
2827
2828 if (first)
2829 {
2830 first = FALSE;
2831# if defined(HAVE_TERMIOS_H)
2832 tcgetattr(read_cmd_fd, &told);
2833# else
2834 ioctl(read_cmd_fd, TCGETA, &told);
2835# endif
2836 }
2837
2838 tnew = told;
2839 if (tmode == TMODE_RAW)
2840 {
2841 /*
2842 * ~ICRNL enables typing ^V^M
2843 */
2844 tnew.c_iflag &= ~ICRNL;
2845 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
2846# if defined(IEXTEN) && !defined(__MINT__)
2847 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
2848 /* but it breaks function keys on MINT */
2849# endif
2850 );
2851# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
2852 tnew.c_oflag &= ~ONLCR;
2853# endif
2854 tnew.c_cc[VMIN] = 1; /* return after 1 char */
2855 tnew.c_cc[VTIME] = 0; /* don't wait */
2856 }
2857 else if (tmode == TMODE_SLEEP)
2858 tnew.c_lflag &= ~(ECHO);
2859
2860# if defined(HAVE_TERMIOS_H)
2861 {
2862 int n = 10;
2863
2864 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
2865 * few times. */
2866 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
2867 && errno == EINTR && n > 0)
2868 --n;
2869 }
2870# else
2871 ioctl(read_cmd_fd, TCSETA, &tnew);
2872# endif
2873
2874#else
2875
2876 /*
2877 * for "old" tty systems
2878 */
2879# ifndef TIOCSETN
2880# define TIOCSETN TIOCSETP /* for hpux 9.0 */
2881# endif
2882 static struct sgttyb ttybold;
2883 struct sgttyb ttybnew;
2884
2885 if (first)
2886 {
2887 first = FALSE;
2888 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
2889 }
2890
2891 ttybnew = ttybold;
2892 if (tmode == TMODE_RAW)
2893 {
2894 ttybnew.sg_flags &= ~(CRMOD | ECHO);
2895 ttybnew.sg_flags |= RAW;
2896 }
2897 else if (tmode == TMODE_SLEEP)
2898 ttybnew.sg_flags &= ~(ECHO);
2899 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
2900#endif
2901 curr_tmode = tmode;
2902}
2903
2904/*
2905 * Try to get the code for "t_kb" from the stty setting
2906 *
2907 * Even if termcap claims a backspace key, the user's setting *should*
2908 * prevail. stty knows more about reality than termcap does, and if
2909 * somebody's usual erase key is DEL (which, for most BSD users, it will
2910 * be), they're going to get really annoyed if their erase key starts
2911 * doing forward deletes for no reason. (Eric Fischer)
2912 */
2913 void
2914get_stty()
2915{
2916 char_u buf[2];
2917 char_u *p;
2918
2919 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2920#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2921 /* for "new" tty systems */
2922# ifdef HAVE_TERMIOS_H
2923 struct termios keys;
2924# else
2925 struct termio keys;
2926# endif
2927
2928# if defined(HAVE_TERMIOS_H)
2929 if (tcgetattr(read_cmd_fd, &keys) != -1)
2930# else
2931 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
2932# endif
2933 {
2934 buf[0] = keys.c_cc[VERASE];
2935 intr_char = keys.c_cc[VINTR];
2936#else
2937 /* for "old" tty systems */
2938 struct sgttyb keys;
2939
2940 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
2941 {
2942 buf[0] = keys.sg_erase;
2943 intr_char = keys.sg_kill;
2944#endif
2945 buf[1] = NUL;
2946 add_termcode((char_u *)"kb", buf, FALSE);
2947
2948 /*
2949 * If <BS> and <DEL> are now the same, redefine <DEL>.
2950 */
2951 p = find_termcode((char_u *)"kD");
2952 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
2953 do_fixdel(NULL);
2954 }
2955#if 0
2956 } /* to keep cindent happy */
2957#endif
2958}
2959
2960#endif /* VMS */
2961
2962#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2963/*
2964 * Set mouse clicks on or off.
2965 */
2966 void
2967mch_setmouse(on)
2968 int on;
2969{
2970 static int ison = FALSE;
2971 int xterm_mouse_vers;
2972
2973 if (on == ison) /* return quickly if nothing to do */
2974 return;
2975
2976 xterm_mouse_vers = use_xterm_mouse();
2977 if (xterm_mouse_vers > 0)
2978 {
2979 if (on) /* enable mouse events, use mouse tracking if available */
2980 out_str_nf((char_u *)
2981 (xterm_mouse_vers > 1
2982 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
2983 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
2984 else /* disable mouse events, could probably always send the same */
2985 out_str_nf((char_u *)
2986 (xterm_mouse_vers > 1
2987 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
2988 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
2989 ison = on;
2990 }
2991
2992# ifdef FEAT_MOUSE_DEC
2993 else if (ttym_flags == TTYM_DEC)
2994 {
2995 if (on) /* enable mouse events */
2996 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
2997 else /* disable mouse events */
2998 out_str_nf((char_u *)"\033['z");
2999 ison = on;
3000 }
3001# endif
3002
3003# ifdef FEAT_MOUSE_GPM
3004 else
3005 {
3006 if (on)
3007 {
3008 if (gpm_open())
3009 ison = TRUE;
3010 }
3011 else
3012 {
3013 gpm_close();
3014 ison = FALSE;
3015 }
3016 }
3017# endif
3018
3019# ifdef FEAT_MOUSE_JSB
3020 else
3021 {
3022 if (on)
3023 {
3024 /* D - Enable Mouse up/down messages
3025 * L - Enable Left Button Reporting
3026 * M - Enable Middle Button Reporting
3027 * R - Enable Right Button Reporting
3028 * K - Enable SHIFT and CTRL key Reporting
3029 * + - Enable Advanced messaging of mouse moves and up/down messages
3030 * Q - Quiet No Ack
3031 * # - Numeric value of mouse pointer required
3032 * 0 = Multiview 2000 cursor, used as standard
3033 * 1 = Windows Arrow
3034 * 2 = Windows I Beam
3035 * 3 = Windows Hour Glass
3036 * 4 = Windows Cross Hair
3037 * 5 = Windows UP Arrow
3038 */
3039#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3040 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3041 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3042#else
3043 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3044 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3045#endif
3046 ison = TRUE;
3047 }
3048 else
3049 {
3050 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3051 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3052 ison = FALSE;
3053 }
3054 }
3055# endif
3056# ifdef FEAT_MOUSE_PTERM
3057 else
3058 {
3059 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3060 if (on)
3061 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3062 else
3063 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3064 ison = on;
3065 }
3066# endif
3067}
3068
3069/*
3070 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3071 */
3072 void
3073check_mouse_termcode()
3074{
3075# ifdef FEAT_MOUSE_XTERM
3076 if (use_xterm_mouse()
3077# ifdef FEAT_GUI
3078 && !gui.in_use
3079# endif
3080 )
3081 {
3082 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003083 ? IF_EB("\233M", CSI_STR "M")
3084 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003085 if (*p_mouse != NUL)
3086 {
3087 /* force mouse off and maybe on to send possibly new mouse
3088 * activation sequence to the xterm, with(out) drag tracing. */
3089 mch_setmouse(FALSE);
3090 setmouse();
3091 }
3092 }
3093 else
3094 del_mouse_termcode(KS_MOUSE);
3095# endif
3096
3097# ifdef FEAT_MOUSE_GPM
3098 if (!use_xterm_mouse()
3099# ifdef FEAT_GUI
3100 && !gui.in_use
3101# endif
3102 )
3103 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3104# endif
3105
3106# ifdef FEAT_MOUSE_JSB
3107 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3108 if (!use_xterm_mouse()
3109# ifdef FEAT_GUI
3110 && !gui.in_use
3111# endif
3112 )
3113 set_mouse_termcode(KS_JSBTERM_MOUSE,
3114 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3115 else
3116 del_mouse_termcode(KS_JSBTERM_MOUSE);
3117# endif
3118
3119# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003120 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003121 * define it in the GUI or when using an xterm. */
3122 if (!use_xterm_mouse()
3123# ifdef FEAT_GUI
3124 && !gui.in_use
3125# endif
3126 )
3127 set_mouse_termcode(KS_NETTERM_MOUSE,
3128 (char_u *)IF_EB("\033}", ESC_STR "}"));
3129 else
3130 del_mouse_termcode(KS_NETTERM_MOUSE);
3131# endif
3132
3133# ifdef FEAT_MOUSE_DEC
3134 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3135 if (!use_xterm_mouse()
3136# ifdef FEAT_GUI
3137 && !gui.in_use
3138# endif
3139 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003140 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3141 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003142 else
3143 del_mouse_termcode(KS_DEC_MOUSE);
3144# endif
3145# ifdef FEAT_MOUSE_PTERM
3146 /* same as the dec mouse */
3147 if (!use_xterm_mouse()
3148# ifdef FEAT_GUI
3149 && !gui.in_use
3150# endif
3151 )
3152 set_mouse_termcode(KS_PTERM_MOUSE,
3153 (char_u *) IF_EB("\033[", ESC_STR "["));
3154 else
3155 del_mouse_termcode(KS_PTERM_MOUSE);
3156# endif
3157}
3158#endif
3159
3160/*
3161 * set screen mode, always fails.
3162 */
3163/* ARGSUSED */
3164 int
3165mch_screenmode(arg)
3166 char_u *arg;
3167{
3168 EMSG(_(e_screenmode));
3169 return FAIL;
3170}
3171
3172#ifndef VMS
3173
3174/*
3175 * Try to get the current window size:
3176 * 1. with an ioctl(), most accurate method
3177 * 2. from the environment variables LINES and COLUMNS
3178 * 3. from the termcap
3179 * 4. keep using the old values
3180 * Return OK when size could be determined, FAIL otherwise.
3181 */
3182 int
3183mch_get_shellsize()
3184{
3185 long rows = 0;
3186 long columns = 0;
3187 char_u *p;
3188
3189 /*
3190 * For OS/2 use _scrsize().
3191 */
3192# ifdef __EMX__
3193 {
3194 int s[2];
3195
3196 _scrsize(s);
3197 columns = s[0];
3198 rows = s[1];
3199 }
3200# endif
3201
3202 /*
3203 * 1. try using an ioctl. It is the most accurate method.
3204 *
3205 * Try using TIOCGWINSZ first, some systems that have it also define
3206 * TIOCGSIZE but don't have a struct ttysize.
3207 */
3208# ifdef TIOCGWINSZ
3209 {
3210 struct winsize ws;
3211 int fd = 1;
3212
3213 /* When stdout is not a tty, use stdin for the ioctl(). */
3214 if (!isatty(fd) && isatty(read_cmd_fd))
3215 fd = read_cmd_fd;
3216 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3217 {
3218 columns = ws.ws_col;
3219 rows = ws.ws_row;
3220 }
3221 }
3222# else /* TIOCGWINSZ */
3223# ifdef TIOCGSIZE
3224 {
3225 struct ttysize ts;
3226 int fd = 1;
3227
3228 /* When stdout is not a tty, use stdin for the ioctl(). */
3229 if (!isatty(fd) && isatty(read_cmd_fd))
3230 fd = read_cmd_fd;
3231 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3232 {
3233 columns = ts.ts_cols;
3234 rows = ts.ts_lines;
3235 }
3236 }
3237# endif /* TIOCGSIZE */
3238# endif /* TIOCGWINSZ */
3239
3240 /*
3241 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003242 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3243 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003244 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003245 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003246 {
3247 if ((p = (char_u *)getenv("LINES")))
3248 rows = atoi((char *)p);
3249 if ((p = (char_u *)getenv("COLUMNS")))
3250 columns = atoi((char *)p);
3251 }
3252
3253#ifdef HAVE_TGETENT
3254 /*
3255 * 3. try reading "co" and "li" entries from termcap
3256 */
3257 if (columns == 0 || rows == 0)
3258 getlinecol(&columns, &rows);
3259#endif
3260
3261 /*
3262 * 4. If everything fails, use the old values
3263 */
3264 if (columns <= 0 || rows <= 0)
3265 return FAIL;
3266
3267 Rows = rows;
3268 Columns = columns;
3269 return OK;
3270}
3271
3272/*
3273 * Try to set the window size to Rows and Columns.
3274 */
3275 void
3276mch_set_shellsize()
3277{
3278 if (*T_CWS)
3279 {
3280 /*
3281 * NOTE: if you get an error here that term_set_winsize() is
3282 * undefined, check the output of configure. It could probably not
3283 * find a ncurses, termcap or termlib library.
3284 */
3285 term_set_winsize((int)Rows, (int)Columns);
3286 out_flush();
3287 screen_start(); /* don't know where cursor is now */
3288 }
3289}
3290
3291#endif /* VMS */
3292
3293/*
3294 * Rows and/or Columns has changed.
3295 */
3296 void
3297mch_new_shellsize()
3298{
3299 /* Nothing to do. */
3300}
3301
Bram Moolenaardf177f62005-02-22 08:39:57 +00003302#ifndef USE_SYSTEM
3303static void append_ga_line __ARGS((garray_T *gap));
3304
3305/*
3306 * Append the text in "gap" below the cursor line and clear "gap".
3307 */
3308 static void
3309append_ga_line(gap)
3310 garray_T *gap;
3311{
3312 /* Remove trailing CR. */
3313 if (gap->ga_len > 0
3314 && !curbuf->b_p_bin
3315 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3316 --gap->ga_len;
3317 ga_append(gap, NUL);
3318 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3319 gap->ga_len = 0;
3320}
3321#endif
3322
Bram Moolenaar071d4272004-06-13 20:20:40 +00003323 int
3324mch_call_shell(cmd, options)
3325 char_u *cmd;
3326 int options; /* SHELL_*, see vim.h */
3327{
3328#ifdef VMS
3329 char *ifn = NULL;
3330 char *ofn = NULL;
3331#endif
3332 int tmode = cur_tmode;
3333#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3334 int x;
3335# ifndef __EMX__
3336 char_u *newcmd; /* only needed for unix */
3337# else
3338 /*
3339 * Set the preferred shell in the EMXSHELL environment variable (but
3340 * only if it is different from what is already in the environment).
3341 * Emx then takes care of whether to use "/c" or "-c" in an
3342 * intelligent way. Simply pass the whole thing to emx's system() call.
3343 * Emx also starts an interactive shell if system() is passed an empty
3344 * string.
3345 */
3346 char_u *p, *old;
3347
3348 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3349 {
3350 /* should check HAVE_SETENV, but I know we don't have it. */
3351 p = alloc(10 + strlen(p_sh));
3352 if (p)
3353 {
3354 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3355 putenv((char *)p); /* don't free the pointer! */
3356 }
3357 }
3358# endif
3359
3360 out_flush();
3361
3362 if (options & SHELL_COOKED)
3363 settmode(TMODE_COOK); /* set to normal mode */
3364
3365# ifdef __EMX__
3366 if (cmd == NULL)
3367 x = system(""); /* this starts an interactive shell in emx */
3368 else
3369 x = system((char *)cmd);
3370 /* system() returns -1 when error occurs in starting shell */
3371 if (x == -1 && !emsg_silent)
3372 {
3373 MSG_PUTS(_("\nCannot execute shell "));
3374 msg_outtrans(p_sh);
3375 msg_putchar('\n');
3376 }
3377# else /* not __EMX__ */
3378 if (cmd == NULL)
3379 x = system((char *)p_sh);
3380 else
3381 {
3382# ifdef VMS
3383 if (ofn = strchr((char *)cmd, '>'))
3384 *ofn++ = '\0';
3385 if (ifn = strchr((char *)cmd, '<'))
3386 {
3387 char *p;
3388
3389 *ifn++ = '\0';
3390 p = strchr(ifn,' '); /* chop off any trailing spaces */
3391 if (p)
3392 *p = '\0';
3393 }
3394 if (ofn)
3395 x = vms_sys((char *)cmd, ofn, ifn);
3396 else
3397 x = system((char *)cmd);
3398# else
3399 newcmd = lalloc(STRLEN(p_sh)
3400 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3401 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3402 if (newcmd == NULL)
3403 x = 0;
3404 else
3405 {
3406 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3407 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3408 (char *)p_shcf,
3409 (char *)cmd);
3410 x = system((char *)newcmd);
3411 vim_free(newcmd);
3412 }
3413# endif
3414 }
3415# ifdef VMS
3416 x = vms_sys_status(x);
3417# endif
3418 if (emsg_silent)
3419 ;
3420 else if (x == 127)
3421 MSG_PUTS(_("\nCannot execute shell sh\n"));
3422# endif /* __EMX__ */
3423 else if (x && !(options & SHELL_SILENT))
3424 {
3425 MSG_PUTS(_("\nshell returned "));
3426 msg_outnum((long)x);
3427 msg_putchar('\n');
3428 }
3429
3430 if (tmode == TMODE_RAW)
3431 settmode(TMODE_RAW); /* set to raw mode */
3432# ifdef FEAT_TITLE
3433 resettitle();
3434# endif
3435 return x;
3436
3437#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3438
Bram Moolenaardf177f62005-02-22 08:39:57 +00003439# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3440 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003441
3442 char_u *newcmd = NULL;
3443 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003444 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003445 pid_t wait_pid = 0;
3446# ifdef HAVE_UNION_WAIT
3447 union wait status;
3448# else
3449 int status = -1;
3450# endif
3451 int retval = -1;
3452 char **argv = NULL;
3453 int argc;
3454 int i;
3455 char_u *p;
3456 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003457 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003458# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003459 int pty_slave_fd = -1;
3460 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003461# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003462 int fd_toshell[2]; /* for pipes */
3463 int fd_fromshell[2];
3464 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003465# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003466 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003467# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003468 static char envbuf_Rows[20];
3469 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003470# endif
3471 int did_settmode = FALSE; /* TRUE when settmode(TMODE_RAW) called */
3472
3473 out_flush();
3474 if (options & SHELL_COOKED)
3475 settmode(TMODE_COOK); /* set to normal mode */
3476
3477 /*
3478 * 1: find number of arguments
3479 * 2: separate them and built argv[]
3480 */
3481 newcmd = vim_strsave(p_sh);
3482 if (newcmd == NULL) /* out of memory */
3483 goto error;
3484 for (i = 0; i < 2; ++i)
3485 {
3486 p = newcmd;
3487 inquote = FALSE;
3488 argc = 0;
3489 for (;;)
3490 {
3491 if (i == 1)
3492 argv[argc] = (char *)p;
3493 ++argc;
3494 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3495 {
3496 if (*p == '"')
3497 inquote = !inquote;
3498 ++p;
3499 }
3500 if (*p == NUL)
3501 break;
3502 if (i == 1)
3503 *p++ = NUL;
3504 p = skipwhite(p);
3505 }
3506 if (i == 0)
3507 {
3508 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3509 if (argv == NULL) /* out of memory */
3510 goto error;
3511 }
3512 }
3513 if (cmd != NULL)
3514 {
3515 if (extra_shell_arg != NULL)
3516 argv[argc++] = (char *)extra_shell_arg;
3517 argv[argc++] = (char *)p_shcf;
3518 argv[argc++] = (char *)cmd;
3519 }
3520 argv[argc] = NULL;
3521
Bram Moolenaar071d4272004-06-13 20:20:40 +00003522 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003523 * For the GUI, when writing the output into the buffer and when reading
3524 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3525 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003526 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003527 if ((options & (SHELL_READ|SHELL_WRITE))
3528# ifdef FEAT_GUI
3529 || (gui.in_use && show_shell_mess)
3530# endif
3531 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003533# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003534 /*
3535 * Try to open a master pty.
3536 * If this works, open the slave pty.
3537 * If the slave can't be opened, close the master pty.
3538 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003539 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540 {
3541 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3542 if (pty_master_fd >= 0 && ((pty_slave_fd =
3543 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3544 {
3545 close(pty_master_fd);
3546 pty_master_fd = -1;
3547 }
3548 }
3549 /*
3550 * If not opening a pty or it didn't work, try using pipes.
3551 */
3552 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003553# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003554 {
3555 pipe_error = (pipe(fd_toshell) < 0);
3556 if (!pipe_error) /* pipe create OK */
3557 {
3558 pipe_error = (pipe(fd_fromshell) < 0);
3559 if (pipe_error) /* pipe create failed */
3560 {
3561 close(fd_toshell[0]);
3562 close(fd_toshell[1]);
3563 }
3564 }
3565 if (pipe_error)
3566 {
3567 MSG_PUTS(_("\nCannot create pipes\n"));
3568 out_flush();
3569 }
3570 }
3571 }
3572
3573 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003574 {
3575# ifdef __BEOS__
3576 beos_cleanup_read_thread();
3577# endif
3578 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3579 {
3580 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003581 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003582# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003583 || (gui.in_use && show_shell_mess)
3584# endif
3585 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003586 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003587# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003588 if (pty_master_fd >= 0) /* close the pseudo tty */
3589 {
3590 close(pty_master_fd);
3591 close(pty_slave_fd);
3592 }
3593 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003594# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003595 {
3596 close(fd_toshell[0]);
3597 close(fd_toshell[1]);
3598 close(fd_fromshell[0]);
3599 close(fd_fromshell[1]);
3600 }
3601 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602 }
3603 else if (pid == 0) /* child */
3604 {
3605 reset_signals(); /* handle signals normally */
3606
3607 if (!show_shell_mess || (options & SHELL_EXPAND))
3608 {
3609 int fd;
3610
3611 /*
3612 * Don't want to show any message from the shell. Can't just
3613 * close stdout and stderr though, because some systems will
3614 * break if you try to write to them after that, so we must
3615 * use dup() to replace them with something else -- webb
3616 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3617 * waiting for input.
3618 */
3619 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3620 fclose(stdin);
3621 fclose(stdout);
3622 fclose(stderr);
3623
3624 /*
3625 * If any of these open()'s and dup()'s fail, we just continue
3626 * anyway. It's not fatal, and on most systems it will make
3627 * no difference at all. On a few it will cause the execvp()
3628 * to exit with a non-zero status even when the completion
3629 * could be done, which is nothing too serious. If the open()
3630 * or dup() failed we'd just do the same thing ourselves
3631 * anyway -- webb
3632 */
3633 if (fd >= 0)
3634 {
3635 dup(fd); /* To replace stdin (file descriptor 0) */
3636 dup(fd); /* To replace stdout (file descriptor 1) */
3637 dup(fd); /* To replace stderr (file descriptor 2) */
3638
3639 /* Don't need this now that we've duplicated it */
3640 close(fd);
3641 }
3642 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003643 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003644# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003645 || gui.in_use
3646# endif
3647 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003648 {
3649
Bram Moolenaardf177f62005-02-22 08:39:57 +00003650# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00003651 (void)setsid();
Bram Moolenaardf177f62005-02-22 08:39:57 +00003652# endif
3653# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003654 /* push stream discipline modules */
3655 if (options & SHELL_COOKED)
3656 SetupSlavePTY(pty_slave_fd);
3657# ifdef TIOCSCTTY
3658 /* try to become controlling tty (probably doesn't work,
3659 * unless run by root) */
3660 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
3661# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003662# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003663 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003664# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003665 setenv("TERM", "dumb", 1);
3666 sprintf((char *)envbuf, "%ld", Rows);
3667 setenv("ROWS", (char *)envbuf, 1);
3668 sprintf((char *)envbuf, "%ld", Rows);
3669 setenv("LINES", (char *)envbuf, 1);
3670 sprintf((char *)envbuf, "%ld", Columns);
3671 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003672# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003673 /*
3674 * Putenv does not copy the string, it has to remain valid.
3675 * Use a static array to avoid loosing allocated memory.
3676 */
3677 putenv("TERM=dumb");
3678 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
3679 putenv(envbuf_Rows);
3680 sprintf(envbuf_Rows, "LINES=%ld", Rows);
3681 putenv(envbuf_Rows);
3682 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
3683 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003684# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003685
Bram Moolenaardf177f62005-02-22 08:39:57 +00003686# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003687 if (pty_master_fd >= 0)
3688 {
3689 close(pty_master_fd); /* close master side of pty */
3690
3691 /* set up stdin/stdout/stderr for the child */
3692 close(0);
3693 dup(pty_slave_fd);
3694 close(1);
3695 dup(pty_slave_fd);
3696 close(2);
3697 dup(pty_slave_fd);
3698
3699 close(pty_slave_fd); /* has been dupped, close it now */
3700 }
3701 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003702# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003703 {
3704 /* set up stdin for the child */
3705 close(fd_toshell[1]);
3706 close(0);
3707 dup(fd_toshell[0]);
3708 close(fd_toshell[0]);
3709
3710 /* set up stdout for the child */
3711 close(fd_fromshell[0]);
3712 close(1);
3713 dup(fd_fromshell[1]);
3714 close(fd_fromshell[1]);
3715
3716 /* set up stderr for the child */
3717 close(2);
3718 dup(1);
3719 }
3720 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003721
Bram Moolenaar071d4272004-06-13 20:20:40 +00003722 /*
3723 * There is no type cast for the argv, because the type may be
3724 * different on different machines. This may cause a warning
3725 * message with strict compilers, don't worry about it.
3726 * Call _exit() instead of exit() to avoid closing the connection
3727 * to the X server (esp. with GTK, which uses atexit()).
3728 */
3729 execvp(argv[0], argv);
3730 _exit(EXEC_FAILED); /* exec failed, return failure code */
3731 }
3732 else /* parent */
3733 {
3734 /*
3735 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003736 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003737 */
3738 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003739 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003740
3741 /*
3742 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003743 * This is also used to pipe stdin/stdout to/from the external
3744 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003745 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003746 if ((options & (SHELL_READ|SHELL_WRITE))
3747# ifdef FEAT_GUI
3748 || (gui.in_use && show_shell_mess)
3749# endif
3750 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003751 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003752# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003754# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003755 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003756# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003757 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
3758 int ta_len = 0; /* valid bytes in ta_buf[] */
3759 int len;
3760 int p_more_save;
3761 int old_State;
3762 int c;
3763 int toshell_fd;
3764 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003765 garray_T ga;
3766 int noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003767
Bram Moolenaardf177f62005-02-22 08:39:57 +00003768# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769 if (pty_master_fd >= 0)
3770 {
3771 close(pty_slave_fd); /* close slave side of pty */
3772 fromshell_fd = pty_master_fd;
3773 toshell_fd = dup(pty_master_fd);
3774 }
3775 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003776# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003777 {
3778 close(fd_toshell[0]);
3779 close(fd_fromshell[1]);
3780 toshell_fd = fd_toshell[1];
3781 fromshell_fd = fd_fromshell[0];
3782 }
3783
3784 /*
3785 * Write to the child if there are typed characters.
3786 * Read from the child if there are characters available.
3787 * Repeat the reading a few times if more characters are
3788 * available. Need to check for typed keys now and then, but
3789 * not too often (delays when no chars are available).
3790 * This loop is quit if no characters can be read from the pty
3791 * (WaitForChar detected special condition), or there are no
3792 * characters available and the child has exited.
3793 * Only check if the child has exited when there is no more
3794 * output. The child may exit before all the output has
3795 * been printed.
3796 *
3797 * Currently this busy loops!
3798 * This can probably dead-lock when the write blocks!
3799 */
3800 p_more_save = p_more;
3801 p_more = FALSE;
3802 old_State = State;
3803 State = EXTERNCMD; /* don't redraw at window resize */
3804
Bram Moolenaardf177f62005-02-22 08:39:57 +00003805 if (options & SHELL_WRITE && toshell_fd >= 0)
3806 {
3807 /* Fork a process that will write the lines to the
3808 * external program. */
3809 if ((wpid = fork()) == -1)
3810 {
3811 MSG_PUTS(_("\nCannot fork\n"));
3812 }
3813 else if (wpid == 0)
3814 {
3815 linenr_T lnum = curbuf->b_op_start.lnum;
3816 int written = 0;
3817 char_u *p = ml_get(lnum);
3818 char_u *s;
3819 size_t l;
3820
3821 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00003822 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003823 for (;;)
3824 {
3825 l = STRLEN(p + written);
3826 if (l == 0)
3827 len = 0;
3828 else if (p[written] == NL)
3829 /* NL -> NUL translation */
3830 len = write(toshell_fd, "", (size_t)1);
3831 else
3832 {
3833 s = vim_strchr(p + written, NL);
3834 len = write(toshell_fd, (char *)p + written,
3835 s == NULL ? l : s - (p + written));
3836 }
3837 if (len == l)
3838 {
3839 /* Finished a line, add a NL, unless this line
3840 * should not have one. */
3841 if (lnum != curbuf->b_op_end.lnum
3842 || !curbuf->b_p_bin
3843 || (lnum != write_no_eol_lnum
3844 && (lnum !=
3845 curbuf->b_ml.ml_line_count
3846 || curbuf->b_p_eol)))
3847 write(toshell_fd, "\n", (size_t)1);
3848 ++lnum;
3849 if (lnum > curbuf->b_op_end.lnum)
3850 {
3851 /* finished all the lines, close pipe */
3852 close(toshell_fd);
3853 toshell_fd = -1;
3854 break;
3855 }
3856 p = ml_get(lnum);
3857 written = 0;
3858 }
3859 else if (len > 0)
3860 written += len;
3861 }
3862 _exit(0);
3863 }
3864 else
3865 {
3866 close(toshell_fd);
3867 toshell_fd = -1;
3868 }
3869 }
3870
3871 if (options & SHELL_READ)
3872 ga_init2(&ga, 1, BUFLEN);
3873
3874 noread_cnt = 0;
3875
Bram Moolenaar071d4272004-06-13 20:20:40 +00003876 for (;;)
3877 {
3878 /*
3879 * Check if keys have been typed, write them to the child
3880 * if there are any. Don't do this if we are expanding
3881 * wild cards (would eat typeahead). Don't get extra
3882 * characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003883 * Don't read characters unless we didn't get output for a
3884 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 */
3886 len = 0;
3887 if (!(options & SHELL_EXPAND)
3888 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00003889 || (noread_cnt > 4
3890 && (len = ui_inchar(ta_buf,
3891 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003892 {
3893 /*
3894 * For pipes:
3895 * Check for CTRL-C: send interrupt signal to child.
3896 * Check for CTRL-D: EOF, close pipe to child.
3897 */
3898 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
3899 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003900# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901 /*
3902 * Send SIGINT to the child's group or all
3903 * processes in our group.
3904 */
3905 if (ta_buf[ta_len] == Ctrl_C
3906 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003907 {
3908# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00003909 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003910# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003911 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003912# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003913 if (wpid > 0)
3914 kill(wpid, SIGINT);
3915 }
3916# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003917 if (pty_master_fd < 0 && toshell_fd >= 0
3918 && ta_buf[ta_len] == Ctrl_D)
3919 {
3920 close(toshell_fd);
3921 toshell_fd = -1;
3922 }
3923 }
3924
3925 /* replace K_BS by <BS> and K_DEL by <DEL> */
3926 for (i = ta_len; i < ta_len + len; ++i)
3927 {
3928 if (ta_buf[i] == CSI && len - i > 2)
3929 {
3930 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
3931 if (c == K_DEL || c == K_KDEL || c == K_BS)
3932 {
3933 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
3934 (size_t)(len - i - 2));
3935 if (c == K_DEL || c == K_KDEL)
3936 ta_buf[i] = DEL;
3937 else
3938 ta_buf[i] = Ctrl_H;
3939 len -= 2;
3940 }
3941 }
3942 else if (ta_buf[i] == '\r')
3943 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00003944# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003945 if (has_mbyte)
3946 i += (*mb_ptr2len_check)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003947# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003948 }
3949
3950 /*
3951 * For pipes: echo the typed characters.
3952 * For a pty this does not seem to work.
3953 */
3954 if (pty_master_fd < 0)
3955 {
3956 for (i = ta_len; i < ta_len + len; ++i)
3957 {
3958 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
3959 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003960# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003961 else if (has_mbyte)
3962 {
3963 int l = (*mb_ptr2len_check)(ta_buf + i);
3964
3965 msg_outtrans_len(ta_buf + i, l);
3966 i += l - 1;
3967 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003968# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003969 else
3970 msg_outtrans_len(ta_buf + i, 1);
3971 }
3972 windgoto(msg_row, msg_col);
3973 out_flush();
3974 }
3975
3976 ta_len += len;
3977
3978 /*
3979 * Write the characters to the child, unless EOF has
3980 * been typed for pipes. Write one character at a
3981 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003982 * When writing buffer lines, drop the typed
3983 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00003984 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003985 if (options & SHELL_WRITE)
3986 ta_len = 0;
3987 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003988 {
3989 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
3990 if (len > 0)
3991 {
3992 ta_len -= len;
3993 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003994 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003995 }
3996 }
3997 }
3998
Bram Moolenaardf177f62005-02-22 08:39:57 +00003999 if (got_int)
4000 {
4001 /* CTRL-C sends a signal to the child, we ignore it
4002 * ourselves */
4003# ifdef HAVE_SETSID
4004 kill(-pid, SIGINT);
4005# else
4006 kill(0, SIGINT);
4007# endif
4008 if (wpid > 0)
4009 kill(wpid, SIGINT);
4010 got_int = FALSE;
4011 }
4012
Bram Moolenaar071d4272004-06-13 20:20:40 +00004013 /*
4014 * Check if the child has any characters to be printed.
4015 * Read them and write them to our window. Repeat this as
4016 * long as there is something to do, avoid the 10ms wait
4017 * for mch_inchar(), or sending typeahead characters to
4018 * the external process.
4019 * TODO: This should handle escape sequences, compatible
4020 * to some terminal (vt52?).
4021 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004022 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4024 {
4025 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004026# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004027 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004028# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004029 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004030# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004031 );
4032 if (len <= 0) /* end of file or error */
4033 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004034
4035 noread_cnt = 0;
4036 if (options & SHELL_READ)
4037 {
4038 /* Do NUL -> NL translation, append NL separated
4039 * lines to the current buffer. */
4040 for (i = 0; i < len; ++i)
4041 {
4042 if (buffer[i] == NL)
4043 append_ga_line(&ga);
4044 else if (buffer[i] == NUL)
4045 ga_append(&ga, NL);
4046 else
4047 ga_append(&ga, buffer[i]);
4048 }
4049 }
4050# ifdef FEAT_MBYTE
4051 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004052 {
4053 int l;
4054
Bram Moolenaardf177f62005-02-22 08:39:57 +00004055 len += buffer_off;
4056 buffer[len] = NUL;
4057
Bram Moolenaar071d4272004-06-13 20:20:40 +00004058 /* Check if the last character in buffer[] is
4059 * incomplete, keep these bytes for the next
4060 * round. */
4061 for (p = buffer; p < buffer + len; p += l)
4062 {
4063 if (enc_utf8) /* exclude composing chars */
4064 l = utf_ptr2len_check(p);
4065 else
4066 l = (*mb_ptr2len_check)(p);
4067 if (l == 0)
4068 l = 1; /* NUL byte? */
4069 else if (MB_BYTE2LEN(*p) != l)
4070 break;
4071 }
4072 if (p == buffer) /* no complete character */
4073 {
4074 /* avoid getting stuck at an illegal byte */
4075 if (len >= 12)
4076 ++p;
4077 else
4078 {
4079 buffer_off = len;
4080 continue;
4081 }
4082 }
4083 c = *p;
4084 *p = NUL;
4085 msg_puts(buffer);
4086 if (p < buffer + len)
4087 {
4088 *p = c;
4089 buffer_off = (buffer + len) - p;
4090 mch_memmove(buffer, p, buffer_off);
4091 continue;
4092 }
4093 buffer_off = 0;
4094 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004095# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004096 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004097 {
4098 buffer[len] = NUL;
4099 msg_puts(buffer);
4100 }
4101
4102 windgoto(msg_row, msg_col);
4103 cursor_on();
4104 out_flush();
4105 if (got_int)
4106 break;
4107 }
4108
4109 /*
4110 * Check if the child still exists, before checking for
4111 * typed characters (otherwise we would loose typeahead).
4112 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004113# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004115# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004116 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004117# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004118 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4119 || (wait_pid == pid && WIFEXITED(status)))
4120 {
4121 wait_pid = pid;
4122 break;
4123 }
4124 wait_pid = 0;
4125 }
4126finished:
4127 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004128 if (options & SHELL_READ)
4129 {
4130 if (ga.ga_len > 0)
4131 {
4132 append_ga_line(&ga);
4133 /* remember that the NL was missing */
4134 write_no_eol_lnum = curwin->w_cursor.lnum;
4135 }
4136 else
4137 write_no_eol_lnum = 0;
4138 ga_clear(&ga);
4139 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004140
Bram Moolenaar071d4272004-06-13 20:20:40 +00004141 /*
4142 * Give all typeahead that wasn't used back to ui_inchar().
4143 */
4144 if (ta_len)
4145 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004146 State = old_State;
4147 if (toshell_fd >= 0)
4148 close(toshell_fd);
4149 close(fromshell_fd);
4150 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004151
4152 /*
4153 * Wait until our child has exited.
4154 * Ignore wait() returning pids of other children and returning
4155 * because of some signal like SIGWINCH.
4156 * Don't wait if wait_pid was already set above, indicating the
4157 * child already exited.
4158 */
4159 while (wait_pid != pid)
4160 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004161# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162 /* Ugly hack: when compiled with Python threads are probably
4163 * used, in which case wait() sometimes hangs for no obvious
4164 * reason. Use waitpid() instead and loop (like the GUI). */
4165# ifdef __NeXT__
4166 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4167# else
4168 wait_pid = waitpid(pid, &status, WNOHANG);
4169# endif
4170 if (wait_pid == 0)
4171 {
4172 /* Wait for 1/100 sec before trying again. */
4173 mch_delay(10L, TRUE);
4174 continue;
4175 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004176# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004177 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004178# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004179 if (wait_pid <= 0
4180# ifdef ECHILD
4181 && errno == ECHILD
4182# endif
4183 )
4184 break;
4185 }
4186
Bram Moolenaardf177f62005-02-22 08:39:57 +00004187 /* Make sure the child that writes to the external program is
4188 * dead. */
4189 if (wpid > 0)
4190 kill(wpid, SIGKILL);
4191
Bram Moolenaar071d4272004-06-13 20:20:40 +00004192 /*
4193 * Set to raw mode right now, otherwise a CTRL-C after
4194 * catch_signals() will kill Vim.
4195 */
4196 if (tmode == TMODE_RAW)
4197 settmode(TMODE_RAW);
4198 did_settmode = TRUE;
4199 set_signals();
4200
4201 if (WIFEXITED(status))
4202 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004203 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004204 retval = WEXITSTATUS(status);
4205 if (retval && !emsg_silent)
4206 {
4207 if (retval == EXEC_FAILED)
4208 {
4209 MSG_PUTS(_("\nCannot execute shell "));
4210 msg_outtrans(p_sh);
4211 msg_putchar('\n');
4212 }
4213 else if (!(options & SHELL_SILENT))
4214 {
4215 MSG_PUTS(_("\nshell returned "));
4216 msg_outnum((long)retval);
4217 msg_putchar('\n');
4218 }
4219 }
4220 }
4221 else
4222 MSG_PUTS(_("\nCommand terminated\n"));
4223 }
4224 }
4225 vim_free(argv);
4226
4227error:
4228 if (!did_settmode)
4229 if (tmode == TMODE_RAW)
4230 settmode(TMODE_RAW); /* set to raw mode */
4231# ifdef FEAT_TITLE
4232 resettitle();
4233# endif
4234 vim_free(newcmd);
4235
4236 return retval;
4237
4238#endif /* USE_SYSTEM */
4239}
4240
4241/*
4242 * Check for CTRL-C typed by reading all available characters.
4243 * In cooked mode we should get SIGINT, no need to check.
4244 */
4245 void
4246mch_breakcheck()
4247{
4248 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4249 fill_input_buf(FALSE);
4250}
4251
4252/*
4253 * Wait "msec" msec until a character is available from the keyboard or from
4254 * inbuf[]. msec == -1 will block forever.
4255 * When a GUI is being used, this will never get called -- webb
4256 */
4257 static int
4258WaitForChar(msec)
4259 long msec;
4260{
4261#ifdef FEAT_MOUSE_GPM
4262 int gpm_process_wanted;
4263#endif
4264#ifdef FEAT_XCLIPBOARD
4265 int rest;
4266#endif
4267 int avail;
4268
4269 if (input_available()) /* something in inbuf[] */
4270 return 1;
4271
4272#if defined(FEAT_MOUSE_DEC)
4273 /* May need to query the mouse position. */
4274 if (WantQueryMouse)
4275 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004276 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004277 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4278 }
4279#endif
4280
4281 /*
4282 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4283 * events. This is a bit complicated, because they might both be defined.
4284 */
4285#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4286# ifdef FEAT_XCLIPBOARD
4287 rest = 0;
4288 if (do_xterm_trace())
4289 rest = msec;
4290# endif
4291 do
4292 {
4293# ifdef FEAT_XCLIPBOARD
4294 if (rest != 0)
4295 {
4296 msec = XT_TRACE_DELAY;
4297 if (rest >= 0 && rest < XT_TRACE_DELAY)
4298 msec = rest;
4299 if (rest >= 0)
4300 rest -= msec;
4301 }
4302# endif
4303# ifdef FEAT_MOUSE_GPM
4304 gpm_process_wanted = 0;
4305 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4306# else
4307 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4308# endif
4309 if (!avail)
4310 {
4311 if (input_available())
4312 return 1;
4313# ifdef FEAT_XCLIPBOARD
4314 if (rest == 0 || !do_xterm_trace())
4315# endif
4316 break;
4317 }
4318 }
4319 while (FALSE
4320# ifdef FEAT_MOUSE_GPM
4321 || (gpm_process_wanted && mch_gpm_process() == 0)
4322# endif
4323# ifdef FEAT_XCLIPBOARD
4324 || (!avail && rest != 0)
4325# endif
4326 );
4327
4328#else
4329 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4330#endif
4331 return avail;
4332}
4333
4334/*
4335 * Wait "msec" msec until a character is available from file descriptor "fd".
4336 * Time == -1 will block forever.
4337 * When a GUI is being used, this will not be used for input -- webb
4338 * Returns also, when a request from Sniff is waiting -- toni.
4339 * Or when a Linux GPM mouse event is waiting.
4340 */
4341/* ARGSUSED */
4342#if defined(__BEOS__)
4343 int
4344#else
4345 static int
4346#endif
4347RealWaitForChar(fd, msec, check_for_gpm)
4348 int fd;
4349 long msec;
4350 int *check_for_gpm;
4351{
4352 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004353#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004354 static int busy = FALSE;
4355
4356 /* May retry getting characters after an event was handled. */
4357# define MAY_LOOP
4358
4359# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4360 /* Remember at what time we started, so that we know how much longer we
4361 * should wait after being interrupted. */
4362# define USE_START_TV
4363 struct timeval start_tv;
4364
4365 if (msec > 0 && (
4366# ifdef FEAT_XCLIPBOARD
4367 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004368# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004369 ||
4370# endif
4371# endif
4372# ifdef USE_XSMP
4373 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004374# ifdef FEAT_MZSCHEME
4375 ||
4376# endif
4377# endif
4378# ifdef FEAT_MZSCHEME
4379 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004380# endif
4381 ))
4382 gettimeofday(&start_tv, NULL);
4383# endif
4384
4385 /* Handle being called recursively. This may happen for the session
4386 * manager stuff, it may save the file, which does a breakcheck. */
4387 if (busy)
4388 return 0;
4389#endif
4390
4391#ifdef MAY_LOOP
4392 while (1)
4393#endif
4394 {
4395#ifdef MAY_LOOP
4396 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004397# ifdef FEAT_MZSCHEME
4398 int mzquantum_used = FALSE;
4399# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004400#endif
4401#ifndef HAVE_SELECT
4402 struct pollfd fds[5];
4403 int nfd;
4404# ifdef FEAT_XCLIPBOARD
4405 int xterm_idx = -1;
4406# endif
4407# ifdef FEAT_MOUSE_GPM
4408 int gpm_idx = -1;
4409# endif
4410# ifdef USE_XSMP
4411 int xsmp_idx = -1;
4412# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004413 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004414
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004415# ifdef FEAT_MZSCHEME
4416 mzvim_check_threads();
4417 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4418 {
4419 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4420 mzquantum_used = TRUE;
4421 }
4422# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004423 fds[0].fd = fd;
4424 fds[0].events = POLLIN;
4425 nfd = 1;
4426
4427# ifdef FEAT_SNIFF
4428# define SNIFF_IDX 1
4429 if (want_sniff_request)
4430 {
4431 fds[SNIFF_IDX].fd = fd_from_sniff;
4432 fds[SNIFF_IDX].events = POLLIN;
4433 nfd++;
4434 }
4435# endif
4436# ifdef FEAT_XCLIPBOARD
4437 if (xterm_Shell != (Widget)0)
4438 {
4439 xterm_idx = nfd;
4440 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4441 fds[nfd].events = POLLIN;
4442 nfd++;
4443 }
4444# endif
4445# ifdef FEAT_MOUSE_GPM
4446 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4447 {
4448 gpm_idx = nfd;
4449 fds[nfd].fd = gpm_fd;
4450 fds[nfd].events = POLLIN;
4451 nfd++;
4452 }
4453# endif
4454# ifdef USE_XSMP
4455 if (xsmp_icefd != -1)
4456 {
4457 xsmp_idx = nfd;
4458 fds[nfd].fd = xsmp_icefd;
4459 fds[nfd].events = POLLIN;
4460 nfd++;
4461 }
4462# endif
4463
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004464 ret = poll(fds, nfd, towait);
4465# ifdef FEAT_MZSCHEME
4466 if (ret == 0 && mzquantum_used)
4467 /* MzThreads scheduling is required and timeout occured */
4468 finished = FALSE;
4469# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004470
4471# ifdef FEAT_SNIFF
4472 if (ret < 0)
4473 sniff_disconnect(1);
4474 else if (want_sniff_request)
4475 {
4476 if (fds[SNIFF_IDX].revents & POLLHUP)
4477 sniff_disconnect(1);
4478 if (fds[SNIFF_IDX].revents & POLLIN)
4479 sniff_request_waiting = 1;
4480 }
4481# endif
4482# ifdef FEAT_XCLIPBOARD
4483 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4484 {
4485 xterm_update(); /* Maybe we should hand out clipboard */
4486 if (--ret == 0 && !input_available())
4487 /* Try again */
4488 finished = FALSE;
4489 }
4490# endif
4491# ifdef FEAT_MOUSE_GPM
4492 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4493 {
4494 *check_for_gpm = 1;
4495 }
4496# endif
4497# ifdef USE_XSMP
4498 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4499 {
4500 if (fds[xsmp_idx].revents & POLLIN)
4501 {
4502 busy = TRUE;
4503 xsmp_handle_requests();
4504 busy = FALSE;
4505 }
4506 else if (fds[xsmp_idx].revents & POLLHUP)
4507 {
4508 if (p_verbose > 0)
4509 MSG(_("XSMP lost ICE connection"));
4510 xsmp_close();
4511 }
4512 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004513 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004514 }
4515# endif
4516
4517
4518#else /* HAVE_SELECT */
4519
4520 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004521 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522 fd_set rfds, efds;
4523 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004524 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004525
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004526# ifdef FEAT_MZSCHEME
4527 mzvim_check_threads();
4528 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4529 {
4530 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4531 mzquantum_used = TRUE;
4532 }
4533# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534# ifdef __EMX__
4535 /* don't check for incoming chars if not in raw mode, because select()
4536 * always returns TRUE then (in some version of emx.dll) */
4537 if (curr_tmode != TMODE_RAW)
4538 return 0;
4539# endif
4540
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004541 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004542 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004543 tv.tv_sec = towait / 1000;
4544 tv.tv_usec = (towait % 1000) * (1000000/1000);
4545 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004546 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004547 else
4548 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549
4550 /*
4551 * Select on ready for reading and exceptional condition (end of file).
4552 */
4553 FD_ZERO(&rfds); /* calls bzero() on a sun */
4554 FD_ZERO(&efds);
4555 FD_SET(fd, &rfds);
4556# if !defined(__QNX__) && !defined(__CYGWIN32__)
4557 /* For QNX select() always returns 1 if this is set. Why? */
4558 FD_SET(fd, &efds);
4559# endif
4560 maxfd = fd;
4561
4562# ifdef FEAT_SNIFF
4563 if (want_sniff_request)
4564 {
4565 FD_SET(fd_from_sniff, &rfds);
4566 FD_SET(fd_from_sniff, &efds);
4567 if (maxfd < fd_from_sniff)
4568 maxfd = fd_from_sniff;
4569 }
4570# endif
4571# ifdef FEAT_XCLIPBOARD
4572 if (xterm_Shell != (Widget)0)
4573 {
4574 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4575 if (maxfd < ConnectionNumber(xterm_dpy))
4576 maxfd = ConnectionNumber(xterm_dpy);
4577 }
4578# endif
4579# ifdef FEAT_MOUSE_GPM
4580 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4581 {
4582 FD_SET(gpm_fd, &rfds);
4583 FD_SET(gpm_fd, &efds);
4584 if (maxfd < gpm_fd)
4585 maxfd = gpm_fd;
4586 }
4587# endif
4588# ifdef USE_XSMP
4589 if (xsmp_icefd != -1)
4590 {
4591 FD_SET(xsmp_icefd, &rfds);
4592 FD_SET(xsmp_icefd, &efds);
4593 if (maxfd < xsmp_icefd)
4594 maxfd = xsmp_icefd;
4595 }
4596# endif
4597
4598# ifdef OLD_VMS
4599 /* Old VMS as v6.2 and older have broken select(). It waits more than
4600 * required. Should not be used */
4601 ret = 0;
4602# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004603 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4604# endif
4605# ifdef FEAT_MZSCHEME
4606 if (ret == 0 && mzquantum_used)
4607 /* loop if MzThreads must be scheduled and timeout occured */
4608 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004609# endif
4610
4611# ifdef FEAT_SNIFF
4612 if (ret < 0 )
4613 sniff_disconnect(1);
4614 else if (ret > 0 && want_sniff_request)
4615 {
4616 if (FD_ISSET(fd_from_sniff, &efds))
4617 sniff_disconnect(1);
4618 if (FD_ISSET(fd_from_sniff, &rfds))
4619 sniff_request_waiting = 1;
4620 }
4621# endif
4622# ifdef FEAT_XCLIPBOARD
4623 if (ret > 0 && xterm_Shell != (Widget)0
4624 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4625 {
4626 xterm_update(); /* Maybe we should hand out clipboard */
4627 /* continue looping when we only got the X event and the input
4628 * buffer is empty */
4629 if (--ret == 0 && !input_available())
4630 {
4631 /* Try again */
4632 finished = FALSE;
4633 }
4634 }
4635# endif
4636# ifdef FEAT_MOUSE_GPM
4637 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4638 {
4639 if (FD_ISSET(gpm_fd, &efds))
4640 gpm_close();
4641 else if (FD_ISSET(gpm_fd, &rfds))
4642 *check_for_gpm = 1;
4643 }
4644# endif
4645# ifdef USE_XSMP
4646 if (ret > 0 && xsmp_icefd != -1)
4647 {
4648 if (FD_ISSET(xsmp_icefd, &efds))
4649 {
4650 if (p_verbose > 0)
4651 MSG(_("XSMP lost ICE connection"));
4652 xsmp_close();
4653 if (--ret == 0)
4654 finished = FALSE; /* keep going if event was only one */
4655 }
4656 else if (FD_ISSET(xsmp_icefd, &rfds))
4657 {
4658 busy = TRUE;
4659 xsmp_handle_requests();
4660 busy = FALSE;
4661 if (--ret == 0)
4662 finished = FALSE; /* keep going if event was only one */
4663 }
4664 }
4665# endif
4666
4667#endif /* HAVE_SELECT */
4668
4669#ifdef MAY_LOOP
4670 if (finished || msec == 0)
4671 break;
4672
4673 /* We're going to loop around again, find out for how long */
4674 if (msec > 0)
4675 {
4676# ifdef USE_START_TV
4677 struct timeval mtv;
4678
4679 /* Compute remaining wait time. */
4680 gettimeofday(&mtv, NULL);
4681 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
4682 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
4683# else
4684 /* Guess we got interrupted halfway. */
4685 msec = msec / 2;
4686# endif
4687 if (msec <= 0)
4688 break; /* waited long enough */
4689 }
4690#endif
4691 }
4692
4693 return (ret > 0);
4694}
4695
4696#ifndef VMS
4697
4698#ifndef NO_EXPANDPATH
4699 static int
4700pstrcmp(a, b)
4701 const void *a, *b;
4702{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004703 return (pathcmp(*(char **)a, *(char **)b, -1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004704}
4705
4706/*
4707 * Recursively expand one path component into all matching files and/or
4708 * directories.
4709 * "path" has backslashes before chars that are not to be expanded, starting
4710 * at "path + wildoff".
4711 * Return the number of matches found.
4712 */
4713 int
4714mch_expandpath(gap, path, flags)
4715 garray_T *gap;
4716 char_u *path;
4717 int flags; /* EW_* flags */
4718{
4719 return unix_expandpath(gap, path, 0, flags);
4720}
4721
4722 static int
4723unix_expandpath(gap, path, wildoff, flags)
4724 garray_T *gap;
4725 char_u *path;
4726 int wildoff;
4727 int flags; /* EW_* flags */
4728{
4729 char_u *buf;
4730 char_u *path_end;
4731 char_u *p, *s, *e;
4732 int start_len, c;
4733 char_u *pat;
4734 DIR *dirp;
4735 regmatch_T regmatch;
4736 struct dirent *dp;
4737 int starts_with_dot;
4738 int matches;
4739 int len;
4740
4741 start_len = gap->ga_len;
4742 buf = alloc(STRLEN(path) + BASENAMELEN + 5);/* make room for file name */
4743 if (buf == NULL)
4744 return 0;
4745
4746/*
4747 * Find the first part in the path name that contains a wildcard.
4748 * Copy it into buf, including the preceding characters.
4749 */
4750 p = buf;
4751 s = buf;
4752 e = NULL;
4753 path_end = path;
4754 while (*path_end != NUL)
4755 {
4756 /* May ignore a wildcard that has a backslash before it; it will
4757 * be removed by rem_backslash() or file_pat_to_reg_pat() below. */
4758 if (path_end >= path + wildoff && rem_backslash(path_end))
4759 *p++ = *path_end++;
4760 else if (*path_end == '/')
4761 {
4762 if (e != NULL)
4763 break;
4764 s = p + 1;
4765 }
4766 else if (path_end >= path + wildoff
4767 && vim_strchr((char_u *)"*?[{~$", *path_end) != NULL)
4768 e = p;
4769#ifdef FEAT_MBYTE
4770 if (has_mbyte)
4771 {
4772 len = (*mb_ptr2len_check)(path_end);
4773 STRNCPY(p, path_end, len);
4774 p += len;
4775 path_end += len;
4776 }
4777 else
4778#endif
4779 *p++ = *path_end++;
4780 }
4781 e = p;
4782 *e = NUL;
4783
4784 /* now we have one wildcard component between s and e */
4785 /* Remove backslashes between "wildoff" and the start of the wildcard
4786 * component. */
4787 for (p = buf + wildoff; p < s; ++p)
4788 if (rem_backslash(p))
4789 {
4790 STRCPY(p, p + 1);
4791 --e;
4792 --s;
4793 }
4794
4795 /* convert the file pattern to a regexp pattern */
4796 starts_with_dot = (*s == '.');
4797 pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
4798 if (pat == NULL)
4799 {
4800 vim_free(buf);
4801 return 0;
4802 }
4803
4804 /* compile the regexp into a program */
4805#ifdef MACOS_X /* Can/Should we use CASE_INSENSITIVE_FILENAME instead ?*/
4806 regmatch.rm_ic = TRUE; /* Behave like Terminal.app */
4807#else
4808 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
4809#endif
4810 regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
4811 vim_free(pat);
4812
4813 if (regmatch.regprog == NULL)
4814 {
4815 vim_free(buf);
4816 return 0;
4817 }
4818
4819 /* open the directory for scanning */
4820 c = *s;
4821 *s = NUL;
4822 dirp = opendir(*buf == NUL ? "." : (char *)buf);
4823 *s = c;
4824
4825 /* Find all matching entries */
4826 if (dirp != NULL)
4827 {
4828 for (;;)
4829 {
4830 dp = readdir(dirp);
4831 if (dp == NULL)
4832 break;
4833 if ((dp->d_name[0] != '.' || starts_with_dot)
4834 && vim_regexec(&regmatch, (char_u *)dp->d_name, (colnr_T)0))
4835 {
4836 STRCPY(s, dp->d_name);
4837 len = STRLEN(buf);
4838 STRCPY(buf + len, path_end);
4839 if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */
4840 {
4841 /* need to expand another component of the path */
4842 /* remove backslashes for the remaining components only */
4843 (void)unix_expandpath(gap, buf, len + 1, flags);
4844 }
4845 else
4846 {
4847 /* no more wildcards, check if there is a match */
4848 /* remove backslashes for the remaining components only */
4849 if (*path_end != NUL)
4850 backslash_halve(buf + len + 1);
4851 if (mch_getperm(buf) >= 0) /* add existing file */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004852 {
4853#if defined(MACOS_X) && defined(FEAT_MBYTE)
4854 size_t precomp_len = STRLEN(buf)+1;
4855 char_u *precomp_buf =
4856 mac_precompose_path(buf, precomp_len, &precomp_len);
4857 if (precomp_buf)
4858 {
4859 mch_memmove(buf, precomp_buf, precomp_len);
4860 vim_free(precomp_buf);
4861 }
4862#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004863 addfile(gap, buf, flags);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004864 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004865 }
4866 }
4867 }
4868
4869 closedir(dirp);
4870 }
4871
4872 vim_free(buf);
4873 vim_free(regmatch.regprog);
4874
4875 matches = gap->ga_len - start_len;
4876 if (matches > 0)
4877 qsort(((char_u **)gap->ga_data) + start_len, matches,
4878 sizeof(char_u *), pstrcmp);
4879 return matches;
4880}
4881#endif
4882
4883/*
4884 * mch_expand_wildcards() - this code does wild-card pattern matching using
4885 * the shell
4886 *
4887 * return OK for success, FAIL for error (you may lose some memory) and put
4888 * an error message in *file.
4889 *
4890 * num_pat is number of input patterns
4891 * pat is array of pointers to input patterns
4892 * num_file is pointer to number of matched file names
4893 * file is pointer to array of pointers to matched file names
4894 */
4895
4896#ifndef SEEK_SET
4897# define SEEK_SET 0
4898#endif
4899#ifndef SEEK_END
4900# define SEEK_END 2
4901#endif
4902
4903/* ARGSUSED */
4904 int
4905mch_expand_wildcards(num_pat, pat, num_file, file, flags)
4906 int num_pat;
4907 char_u **pat;
4908 int *num_file;
4909 char_u ***file;
4910 int flags; /* EW_* flags */
4911{
4912 int i;
4913 size_t len;
4914 char_u *p;
4915 int dir;
4916#ifdef __EMX__
4917# define EXPL_ALLOC_INC 16
4918 char_u **expl_files;
4919 size_t files_alloced, files_free;
4920 char_u *buf;
4921 int has_wildcard;
4922
4923 *num_file = 0; /* default: no files found */
4924 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
4925 files_free = EXPL_ALLOC_INC; /* how much space is not used */
4926 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
4927 if (*file == NULL)
4928 return FAIL;
4929
4930 for (; num_pat > 0; num_pat--, pat++)
4931 {
4932 expl_files = NULL;
4933 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
4934 /* expand environment var or home dir */
4935 buf = expand_env_save(*pat);
4936 else
4937 buf = vim_strsave(*pat);
4938 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00004939 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004940 if (has_wildcard) /* yes, so expand them */
4941 expl_files = (char_u **)_fnexplode(buf);
4942
4943 /*
4944 * return value of buf if no wildcards left,
4945 * OR if no match AND EW_NOTFOUND is set.
4946 */
4947 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
4948 || (expl_files == NULL && (flags & EW_NOTFOUND)))
4949 { /* simply save the current contents of *buf */
4950 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
4951 if (expl_files != NULL)
4952 {
4953 expl_files[0] = vim_strsave(buf);
4954 expl_files[1] = NULL;
4955 }
4956 }
4957 vim_free(buf);
4958
4959 /*
4960 * Count number of names resulting from expansion,
4961 * At the same time add a backslash to the end of names that happen to
4962 * be directories, and replace slashes with backslashes.
4963 */
4964 if (expl_files)
4965 {
4966 for (i = 0; (p = expl_files[i]) != NULL; i++)
4967 {
4968 dir = mch_isdir(p);
4969 /* If we don't want dirs and this is one, skip it */
4970 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
4971 continue;
4972
4973 if (--files_free == 0)
4974 {
4975 /* need more room in table of pointers */
4976 files_alloced += EXPL_ALLOC_INC;
4977 *file = (char_u **)vim_realloc(*file,
4978 sizeof(char_u **) * files_alloced);
4979 if (*file == NULL)
4980 {
4981 EMSG(_(e_outofmem));
4982 *num_file = 0;
4983 return FAIL;
4984 }
4985 files_free = EXPL_ALLOC_INC;
4986 }
4987 slash_adjust(p);
4988 if (dir)
4989 {
4990 /* For a directory we add a '/', unless it's already
4991 * there. */
4992 len = STRLEN(p);
4993 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
4994 {
4995 STRCPY((*file)[*num_file], p);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004996 if (!after_pathsep((*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004997 {
4998 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004999 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005000 }
5001 }
5002 }
5003 else
5004 {
5005 (*file)[*num_file] = vim_strsave(p);
5006 }
5007
5008 /*
5009 * Error message already given by either alloc or vim_strsave.
5010 * Should return FAIL, but returning OK works also.
5011 */
5012 if ((*file)[*num_file] == NULL)
5013 break;
5014 (*num_file)++;
5015 }
5016 _fnexplodefree((char **)expl_files);
5017 }
5018 }
5019 return OK;
5020
5021#else /* __EMX__ */
5022
5023 int j;
5024 char_u *tempname;
5025 char_u *command;
5026 FILE *fd;
5027 char_u *buffer;
5028#define STYLE_ECHO 0 /* use "echo" to expand */
5029#define STYLE_GLOB 1 /* use "glob" to expand, for csh */
5030#define STYLE_PRINT 2 /* use "print -N" to expand, for zsh */
5031#define STYLE_BT 3 /* `cmd` expansion, execute the pattern directly */
5032 int shell_style = STYLE_ECHO;
5033 int check_spaces;
5034 static int did_find_nul = FALSE;
5035 int ampersent = FALSE;
5036
5037 *num_file = 0; /* default: no files found */
5038 *file = NULL;
5039
5040 /*
5041 * If there are no wildcards, just copy the names to allocated memory.
5042 * Saves a lot of time, because we don't have to start a new shell.
5043 */
5044 if (!have_wildcard(num_pat, pat))
5045 return save_patterns(num_pat, pat, num_file, file);
5046
5047 /*
5048 * Don't allow the use of backticks in secure and restricted mode.
5049 */
5050 if (secure || restricted)
5051 for (i = 0; i < num_pat; ++i)
5052 if (vim_strchr(pat[i], '`') != NULL
5053 && (check_restricted() || check_secure()))
5054 return FAIL;
5055
5056 /*
5057 * get a name for the temp file
5058 */
5059 if ((tempname = vim_tempname('o')) == NULL)
5060 {
5061 EMSG(_(e_notmp));
5062 return FAIL;
5063 }
5064
5065 /*
5066 * Let the shell expand the patterns and write the result into the temp
5067 * file. if expanding `cmd` execute it directly.
5068 * If we use csh, glob will work better than echo.
5069 * If we use zsh, print -N will work better than glob.
5070 */
5071 if (num_pat == 1 && *pat[0] == '`'
5072 && (len = STRLEN(pat[0])) > 2
5073 && *(pat[0] + len - 1) == '`')
5074 shell_style = STYLE_BT;
5075 else if ((len = STRLEN(p_sh)) >= 3)
5076 {
5077 if (STRCMP(p_sh + len - 3, "csh") == 0)
5078 shell_style = STYLE_GLOB;
5079 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5080 shell_style = STYLE_PRINT;
5081 }
5082
5083 /* "unset nonomatch; print -N >" plus two is 29 */
5084 len = STRLEN(tempname) + 29;
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005085 for (i = 0; i < num_pat; ++i)
5086 {
5087 /* Count the length of the patterns in the same way as they are put in
5088 * "command" below. */
5089#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005090 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005091#else
5092 ++len; /* add space */
5093 for (j = 0; pat[i][j] != NUL; )
5094 if (vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5095 {
5096 len += 2; /* add two quotes */
5097 while (pat[i][j] != NUL
5098 && vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5099 {
5100 ++len;
5101 ++j;
5102 }
5103 }
5104 else
5105 {
5106 ++len;
5107 ++j;
5108 }
5109#endif
5110 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005111 command = alloc(len);
5112 if (command == NULL)
5113 {
5114 /* out of memory */
5115 vim_free(tempname);
5116 return FAIL;
5117 }
5118
5119 /*
5120 * Build the shell command:
5121 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5122 * recognizes this).
5123 * - Add the shell command to print the expanded names.
5124 * - Add the temp file name.
5125 * - Add the file name patterns.
5126 */
5127 if (shell_style == STYLE_BT)
5128 {
5129 STRCPY(command, pat[0] + 1); /* exclude first backtick */
5130 p = command + STRLEN(command) - 1;
5131 *p = ' '; /* remove last backtick */
5132 while (p > command && vim_iswhite(*p))
5133 --p;
5134 if (*p == '&') /* remove trailing '&' */
5135 {
5136 ampersent = TRUE;
5137 *p = ' ';
5138 }
5139 STRCAT(command, ">");
5140 }
5141 else
5142 {
5143 if (flags & EW_NOTFOUND)
5144 STRCPY(command, "set nonomatch; ");
5145 else
5146 STRCPY(command, "unset nonomatch; ");
5147 if (shell_style == STYLE_GLOB)
5148 STRCAT(command, "glob >");
5149 else if (shell_style == STYLE_PRINT)
5150 STRCAT(command, "print -N >");
5151 else
5152 STRCAT(command, "echo >");
5153 }
5154 STRCAT(command, tempname);
5155 if (shell_style != STYLE_BT)
5156 for (i = 0; i < num_pat; ++i)
5157 {
5158 /* When using system() always add extra quotes, because the shell
5159 * is started twice. Otherwise only put quotes around spaces and
5160 * single quotes. */
5161#ifdef USE_SYSTEM
5162 STRCAT(command, " \"");
5163 STRCAT(command, pat[i]);
5164 STRCAT(command, "\"");
5165#else
5166 p = command + STRLEN(command);
5167 *p++ = ' ';
5168 for (j = 0; pat[i][j] != NUL; )
5169 if (vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5170 {
5171 *p++ = '"';
5172 while (pat[i][j] != NUL
5173 && vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5174 *p++ = pat[i][j++];
5175 *p++ = '"';
5176 }
5177 else
Bram Moolenaar0cf6f542005-01-16 21:59:36 +00005178 {
5179 /* For a backslash also copy the next character, don't
5180 * want to put quotes around it. */
5181 if ((*p++ = pat[i][j++]) == '\\' && pat[i][j] != NUL)
5182 *p++ = pat[i][j++];
5183 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005184 *p = NUL;
5185#endif
5186 }
5187 if (flags & EW_SILENT)
5188 show_shell_mess = FALSE;
5189 if (ampersent)
5190 STRCAT(command, "&"); /* put the '&' back after the
5191 redirection */
5192
5193 /*
5194 * Using zsh -G: If a pattern has no matches, it is just deleted from
5195 * the argument list, otherwise zsh gives an error message and doesn't
5196 * expand any other pattern.
5197 */
5198 if (shell_style == STYLE_PRINT)
5199 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5200
5201 /*
5202 * If we use -f then shell variables set in .cshrc won't get expanded.
5203 * vi can do it, so we will too, but it is only necessary if there is a "$"
5204 * in one of the patterns, otherwise we can still use the fast option.
5205 */
5206 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5207 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5208
5209 /*
5210 * execute the shell command
5211 */
5212 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5213
5214 /* When running in the background, give it some time to create the temp
5215 * file, but don't wait for it to finish. */
5216 if (ampersent)
5217 mch_delay(10L, TRUE);
5218
5219 extra_shell_arg = NULL; /* cleanup */
5220 show_shell_mess = TRUE;
5221 vim_free(command);
5222
5223 if (i) /* mch_call_shell() failed */
5224 {
5225 mch_remove(tempname);
5226 vim_free(tempname);
5227 /*
5228 * With interactive completion, the error message is not printed.
5229 * However with USE_SYSTEM, I don't know how to turn off error messages
5230 * from the shell, so screen may still get messed up -- webb.
5231 */
5232#ifndef USE_SYSTEM
5233 if (!(flags & EW_SILENT))
5234#endif
5235 {
5236 redraw_later_clear(); /* probably messed up screen */
5237 msg_putchar('\n'); /* clear bottom line quickly */
5238 cmdline_row = Rows - 1; /* continue on last line */
5239#ifdef USE_SYSTEM
5240 if (!(flags & EW_SILENT))
5241#endif
5242 {
5243 MSG(_(e_wildexpand));
5244 msg_start(); /* don't overwrite this message */
5245 }
5246 }
5247 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5248 * EW_NOTFOUND is given */
5249 if (shell_style == STYLE_BT)
5250 return FAIL;
5251 goto notfound;
5252 }
5253
5254 /*
5255 * read the names from the file into memory
5256 */
5257 fd = fopen((char *)tempname, READBIN);
5258 if (fd == NULL)
5259 {
5260 /* Something went wrong, perhaps a file name with a special char. */
5261 if (!(flags & EW_SILENT))
5262 {
5263 MSG(_(e_wildexpand));
5264 msg_start(); /* don't overwrite this message */
5265 }
5266 vim_free(tempname);
5267 goto notfound;
5268 }
5269 fseek(fd, 0L, SEEK_END);
5270 len = ftell(fd); /* get size of temp file */
5271 fseek(fd, 0L, SEEK_SET);
5272 buffer = alloc(len + 1);
5273 if (buffer == NULL)
5274 {
5275 /* out of memory */
5276 mch_remove(tempname);
5277 vim_free(tempname);
5278 fclose(fd);
5279 return FAIL;
5280 }
5281 i = fread((char *)buffer, 1, len, fd);
5282 fclose(fd);
5283 mch_remove(tempname);
5284 if (i != len)
5285 {
5286 /* unexpected read error */
5287 EMSG2(_(e_notread), tempname);
5288 vim_free(tempname);
5289 vim_free(buffer);
5290 return FAIL;
5291 }
5292 vim_free(tempname);
5293
5294#if defined(__CYGWIN__) || defined(__CYGWIN32__)
5295 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5296 p = buffer;
5297 for (i = 0; i < len; ++i)
5298 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5299 *p++ = buffer[i];
5300 len = p - buffer;
5301# endif
5302
5303
5304 /* file names are separated with Space */
5305 if (shell_style == STYLE_ECHO)
5306 {
5307 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5308 p = buffer;
5309 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5310 {
5311 while (*p != ' ' && *p != '\n')
5312 ++p;
5313 p = skipwhite(p); /* skip to next entry */
5314 }
5315 }
5316 /* file names are separated with NL */
5317 else if (shell_style == STYLE_BT)
5318 {
5319 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5320 p = buffer;
5321 for (i = 0; *p != NUL; ++i) /* count number of entries */
5322 {
5323 while (*p != '\n' && *p != NUL)
5324 ++p;
5325 if (*p != NUL)
5326 ++p;
5327 p = skipwhite(p); /* skip leading white space */
5328 }
5329 }
5330 /* file names are separated with NUL */
5331 else
5332 {
5333 /*
5334 * Some versions of zsh use spaces instead of NULs to separate
5335 * results. Only do this when there is no NUL before the end of the
5336 * buffer, otherwise we would never be able to use file names with
5337 * embedded spaces when zsh does use NULs.
5338 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5339 * don't check for spaces again.
5340 */
5341 check_spaces = FALSE;
5342 if (shell_style == STYLE_PRINT && !did_find_nul)
5343 {
5344 /* If there is a NUL, set did_find_nul, else set check_spaces */
5345 if (len && (int)STRLEN(buffer) < len - 1)
5346 did_find_nul = TRUE;
5347 else
5348 check_spaces = TRUE;
5349 }
5350
5351 /*
5352 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5353 * already is one, for STYLE_GLOB it needs to be added.
5354 */
5355 if (len && buffer[len - 1] == NUL)
5356 --len;
5357 else
5358 buffer[len] = NUL;
5359 i = 0;
5360 for (p = buffer; p < buffer + len; ++p)
5361 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5362 {
5363 ++i;
5364 *p = NUL;
5365 }
5366 if (len)
5367 ++i; /* count last entry */
5368 }
5369 if (i == 0)
5370 {
5371 /*
5372 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5373 * /bin/sh will happily expand it to nothing rather than returning an
5374 * error; and hey, it's good to check anyway -- webb.
5375 */
5376 vim_free(buffer);
5377 goto notfound;
5378 }
5379 *num_file = i;
5380 *file = (char_u **)alloc(sizeof(char_u *) * i);
5381 if (*file == NULL)
5382 {
5383 /* out of memory */
5384 vim_free(buffer);
5385 return FAIL;
5386 }
5387
5388 /*
5389 * Isolate the individual file names.
5390 */
5391 p = buffer;
5392 for (i = 0; i < *num_file; ++i)
5393 {
5394 (*file)[i] = p;
5395 /* Space or NL separates */
5396 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT)
5397 {
5398 while (!(shell_style == STYLE_ECHO && *p == ' ') && *p != '\n')
5399 ++p;
5400 if (p == buffer + len) /* last entry */
5401 *p = NUL;
5402 else
5403 {
5404 *p++ = NUL;
5405 p = skipwhite(p); /* skip to next entry */
5406 }
5407 }
5408 else /* NUL separates */
5409 {
5410 while (*p && p < buffer + len) /* skip entry */
5411 ++p;
5412 ++p; /* skip NUL */
5413 }
5414 }
5415
5416 /*
5417 * Move the file names to allocated memory.
5418 */
5419 for (j = 0, i = 0; i < *num_file; ++i)
5420 {
5421 /* Require the files to exist. Helps when using /bin/sh */
5422 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5423 continue;
5424
5425 /* check if this entry should be included */
5426 dir = (mch_isdir((*file)[i]));
5427 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5428 continue;
5429
5430 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5431 if (p)
5432 {
5433 STRCPY(p, (*file)[i]);
5434 if (dir)
5435 STRCAT(p, "/"); /* add '/' to a directory name */
5436 (*file)[j++] = p;
5437 }
5438 }
5439 vim_free(buffer);
5440 *num_file = j;
5441
5442 if (*num_file == 0) /* rejected all entries */
5443 {
5444 vim_free(*file);
5445 *file = NULL;
5446 goto notfound;
5447 }
5448
5449 return OK;
5450
5451notfound:
5452 if (flags & EW_NOTFOUND)
5453 return save_patterns(num_pat, pat, num_file, file);
5454 return FAIL;
5455
5456#endif /* __EMX__ */
5457}
5458
5459#endif /* VMS */
5460
5461#ifndef __EMX__
5462 static int
5463save_patterns(num_pat, pat, num_file, file)
5464 int num_pat;
5465 char_u **pat;
5466 int *num_file;
5467 char_u ***file;
5468{
5469 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005470 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005471
5472 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5473 if (*file == NULL)
5474 return FAIL;
5475 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005476 {
5477 s = vim_strsave(pat[i]);
5478 if (s != NULL)
5479 /* Be compatible with expand_filename(): halve the number of
5480 * backslashes. */
5481 backslash_halve(s);
5482 (*file)[i] = s;
5483 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005484 *num_file = num_pat;
5485 return OK;
5486}
5487#endif
5488
5489
5490/*
5491 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5492 * expand.
5493 */
5494 int
5495mch_has_exp_wildcard(p)
5496 char_u *p;
5497{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005498 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005499 {
5500#ifndef OS2
5501 if (*p == '\\' && p[1] != NUL)
5502 ++p;
5503 else
5504#endif
5505 if (vim_strchr((char_u *)
5506#ifdef VMS
5507 "*?%"
5508#else
5509# ifdef OS2
5510 "*?"
5511# else
5512 "*?[{'"
5513# endif
5514#endif
5515 , *p) != NULL)
5516 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005517 }
5518 return FALSE;
5519}
5520
5521/*
5522 * Return TRUE if the string "p" contains a wildcard.
5523 * Don't recognize '~' at the end as a wildcard.
5524 */
5525 int
5526mch_has_wildcard(p)
5527 char_u *p;
5528{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005529 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005530 {
5531#ifndef OS2
5532 if (*p == '\\' && p[1] != NUL)
5533 ++p;
5534 else
5535#endif
5536 if (vim_strchr((char_u *)
5537#ifdef VMS
5538 "*?%$"
5539#else
5540# ifdef OS2
5541# ifdef VIM_BACKTICK
5542 "*?$`"
5543# else
5544 "*?$"
5545# endif
5546# else
5547 "*?[{`'$"
5548# endif
5549#endif
5550 , *p) != NULL
5551 || (*p == '~' && p[1] != NUL))
5552 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005553 }
5554 return FALSE;
5555}
5556
5557#ifndef __EMX__
5558 static int
5559have_wildcard(num, file)
5560 int num;
5561 char_u **file;
5562{
5563 int i;
5564
5565 for (i = 0; i < num; i++)
5566 if (mch_has_wildcard(file[i]))
5567 return 1;
5568 return 0;
5569}
5570
5571 static int
5572have_dollars(num, file)
5573 int num;
5574 char_u **file;
5575{
5576 int i;
5577
5578 for (i = 0; i < num; i++)
5579 if (vim_strchr(file[i], '$') != NULL)
5580 return TRUE;
5581 return FALSE;
5582}
5583#endif /* ifndef __EMX__ */
5584
5585#ifndef HAVE_RENAME
5586/*
5587 * Scaled-down version of rename(), which is missing in Xenix.
5588 * This version can only move regular files and will fail if the
5589 * destination exists.
5590 */
5591 int
5592mch_rename(src, dest)
5593 const char *src, *dest;
5594{
5595 struct stat st;
5596
5597 if (stat(dest, &st) >= 0) /* fail if destination exists */
5598 return -1;
5599 if (link(src, dest) != 0) /* link file to new name */
5600 return -1;
5601 if (mch_remove(src) == 0) /* delete link to old name */
5602 return 0;
5603 return -1;
5604}
5605#endif /* !HAVE_RENAME */
5606
5607#ifdef FEAT_MOUSE_GPM
5608/*
5609 * Initializes connection with gpm (if it isn't already opened)
5610 * Return 1 if succeeded (or connection already opened), 0 if failed
5611 */
5612 static int
5613gpm_open()
5614{
5615 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5616
5617 if (!gpm_flag)
5618 {
5619 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5620 gpm_connect.defaultMask = ~GPM_HARD;
5621 /* Default handling for mouse move*/
5622 gpm_connect.minMod = 0; /* Handle any modifier keys */
5623 gpm_connect.maxMod = 0xffff;
5624 if (Gpm_Open(&gpm_connect, 0) > 0)
5625 {
5626 /* gpm library tries to handling TSTP causes
5627 * problems. Anyways, we close connection to Gpm whenever
5628 * we are going to suspend or starting an external process
5629 * so we should'nt have problem with this
5630 */
5631 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5632 return 1; /* succeed */
5633 }
5634 if (gpm_fd == -2)
5635 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5636 return 0;
5637 }
5638 return 1; /* already open */
5639}
5640
5641/*
5642 * Closes connection to gpm
5643 * returns non-zero if connection succesfully closed
5644 */
5645 static void
5646gpm_close()
5647{
5648 if (gpm_flag && gpm_fd >= 0) /* if Open */
5649 Gpm_Close();
5650}
5651
5652/* Reads gpm event and adds special keys to input buf. Returns length of
5653 * generated key sequence.
5654 * This function is made after gui_send_mouse_event
5655 */
5656 static int
5657mch_gpm_process()
5658{
5659 int button;
5660 static Gpm_Event gpm_event;
5661 char_u string[6];
5662 int_u vim_modifiers;
5663 int row,col;
5664 unsigned char buttons_mask;
5665 unsigned char gpm_modifiers;
5666 static unsigned char old_buttons = 0;
5667
5668 Gpm_GetEvent(&gpm_event);
5669
5670#ifdef FEAT_GUI
5671 /* Don't put events in the input queue now. */
5672 if (hold_gui_events)
5673 return 0;
5674#endif
5675
5676 row = gpm_event.y - 1;
5677 col = gpm_event.x - 1;
5678
5679 string[0] = ESC; /* Our termcode */
5680 string[1] = 'M';
5681 string[2] = 'G';
5682 switch (GPM_BARE_EVENTS(gpm_event.type))
5683 {
5684 case GPM_DRAG:
5685 string[3] = MOUSE_DRAG;
5686 break;
5687 case GPM_DOWN:
5688 buttons_mask = gpm_event.buttons & ~old_buttons;
5689 old_buttons = gpm_event.buttons;
5690 switch (buttons_mask)
5691 {
5692 case GPM_B_LEFT:
5693 button = MOUSE_LEFT;
5694 break;
5695 case GPM_B_MIDDLE:
5696 button = MOUSE_MIDDLE;
5697 break;
5698 case GPM_B_RIGHT:
5699 button = MOUSE_RIGHT;
5700 break;
5701 default:
5702 return 0;
5703 /*Don't know what to do. Can more than one button be
5704 * reported in one event? */
5705 }
5706 string[3] = (char_u)(button | 0x20);
5707 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5708 break;
5709 case GPM_UP:
5710 string[3] = MOUSE_RELEASE;
5711 old_buttons &= ~gpm_event.buttons;
5712 break;
5713 default:
5714 return 0;
5715 }
5716 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5717 gpm_modifiers = gpm_event.modifiers;
5718 vim_modifiers = 0x0;
5719 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5720 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5721 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5722 */
5723 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5724 vim_modifiers |= MOUSE_SHIFT;
5725
5726 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5727 vim_modifiers |= MOUSE_CTRL;
5728 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5729 vim_modifiers |= MOUSE_ALT;
5730 string[3] |= vim_modifiers;
5731 string[4] = (char_u)(col + ' ' + 1);
5732 string[5] = (char_u)(row + ' ' + 1);
5733 add_to_input_buf(string, 6);
5734 return 6;
5735}
5736#endif /* FEAT_MOUSE_GPM */
5737
5738#if defined(FEAT_LIBCALL) || defined(PROTO)
5739typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
5740typedef char_u * (*INTPROCSTR)__ARGS((int));
5741typedef int (*STRPROCINT)__ARGS((char_u *));
5742typedef int (*INTPROCINT)__ARGS((int));
5743
5744/*
5745 * Call a DLL routine which takes either a string or int param
5746 * and returns an allocated string.
5747 */
5748 int
5749mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
5750 char_u *libname;
5751 char_u *funcname;
5752 char_u *argstring; /* NULL when using a argint */
5753 int argint;
5754 char_u **string_result;/* NULL when using number_result */
5755 int *number_result;
5756{
5757# if defined(USE_DLOPEN)
5758 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005759 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005760# else
5761 shl_t hinstLib;
5762# endif
5763 STRPROCSTR ProcAdd;
5764 INTPROCSTR ProcAddI;
5765 char_u *retval_str = NULL;
5766 int retval_int = 0;
5767 int success = FALSE;
5768
5769 /* Get a handle to the DLL module. */
5770# if defined(USE_DLOPEN)
5771 hinstLib = dlopen((char *)libname, RTLD_LAZY
5772# ifdef RTLD_LOCAL
5773 | RTLD_LOCAL
5774# endif
5775 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005776 if (hinstLib == NULL)
5777 {
5778 /* "dlerr" must be used before dlclose() */
5779 dlerr = (char *)dlerror();
5780 if (dlerr != NULL)
5781 EMSG2(_("dlerror = \"%s\""), dlerr);
5782 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005783# else
5784 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
5785# endif
5786
5787 /* If the handle is valid, try to get the function address. */
5788 if (hinstLib != NULL)
5789 {
5790# ifdef HAVE_SETJMP_H
5791 /*
5792 * Catch a crash when calling the library function. For example when
5793 * using a number where a string pointer is expected.
5794 */
5795 mch_startjmp();
5796 if (SETJMP(lc_jump_env) != 0)
5797 {
5798 success = FALSE;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005799 dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005800 mch_didjmp();
5801 }
5802 else
5803# endif
5804 {
5805 retval_str = NULL;
5806 retval_int = 0;
5807
5808 if (argstring != NULL)
5809 {
5810# if defined(USE_DLOPEN)
5811 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005812 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005813# else
5814 if (shl_findsym(&hinstLib, (const char *)funcname,
5815 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
5816 ProcAdd = NULL;
5817# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005818 if ((success = (ProcAdd != NULL
5819# if defined(USE_DLOPEN)
5820 && dlerr == NULL
5821# endif
5822 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005823 {
5824 if (string_result == NULL)
5825 retval_int = ((STRPROCINT)ProcAdd)(argstring);
5826 else
5827 retval_str = (ProcAdd)(argstring);
5828 }
5829 }
5830 else
5831 {
5832# if defined(USE_DLOPEN)
5833 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005834 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005835# else
5836 if (shl_findsym(&hinstLib, (const char *)funcname,
5837 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
5838 ProcAddI = NULL;
5839# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005840 if ((success = (ProcAddI != NULL
5841# if defined(USE_DLOPEN)
5842 && dlerr == NULL
5843# endif
5844 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845 {
5846 if (string_result == NULL)
5847 retval_int = ((INTPROCINT)ProcAddI)(argint);
5848 else
5849 retval_str = (ProcAddI)(argint);
5850 }
5851 }
5852
5853 /* Save the string before we free the library. */
5854 /* Assume that a "1" or "-1" result is an illegal pointer. */
5855 if (string_result == NULL)
5856 *number_result = retval_int;
5857 else if (retval_str != NULL
5858 && retval_str != (char_u *)1
5859 && retval_str != (char_u *)-1)
5860 *string_result = vim_strsave(retval_str);
5861 }
5862
5863# ifdef HAVE_SETJMP_H
5864 mch_endjmp();
5865# ifdef SIGHASARG
5866 if (lc_signal != 0)
5867 {
5868 int i;
5869
5870 /* try to find the name of this signal */
5871 for (i = 0; signal_info[i].sig != -1; i++)
5872 if (lc_signal == signal_info[i].sig)
5873 break;
5874 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
5875 }
5876# endif
5877# endif
5878
Bram Moolenaar071d4272004-06-13 20:20:40 +00005879# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005880 /* "dlerr" must be used before dlclose() */
5881 if (dlerr != NULL)
5882 EMSG2(_("dlerror = \"%s\""), dlerr);
5883
5884 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005885 (void)dlclose(hinstLib);
5886# else
5887 (void)shl_unload(hinstLib);
5888# endif
5889 }
5890
5891 if (!success)
5892 {
5893 EMSG2(_(e_libcall), funcname);
5894 return FAIL;
5895 }
5896
5897 return OK;
5898}
5899#endif
5900
5901#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
5902static int xterm_trace = -1; /* default: disabled */
5903static int xterm_button;
5904
5905/*
5906 * Setup a dummy window for X selections in a terminal.
5907 */
5908 void
5909setup_term_clip()
5910{
5911 int z = 0;
5912 char *strp = "";
5913 Widget AppShell;
5914
5915 if (!x_connect_to_server())
5916 return;
5917
5918 open_app_context();
5919 if (app_context != NULL && xterm_Shell == (Widget)0)
5920 {
5921 int (*oldhandler)();
5922#if defined(HAVE_SETJMP_H)
5923 int (*oldIOhandler)();
5924#endif
5925# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5926 struct timeval start_tv;
5927
5928 if (p_verbose > 0)
5929 gettimeofday(&start_tv, NULL);
5930# endif
5931
5932 /* Ignore X errors while opening the display */
5933 oldhandler = XSetErrorHandler(x_error_check);
5934
5935#if defined(HAVE_SETJMP_H)
5936 /* Ignore X IO errors while opening the display */
5937 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
5938 mch_startjmp();
5939 if (SETJMP(lc_jump_env) != 0)
5940 {
5941 mch_didjmp();
5942 xterm_dpy = NULL;
5943 }
5944 else
5945#endif
5946 {
5947 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
5948 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
5949#if defined(HAVE_SETJMP_H)
5950 mch_endjmp();
5951#endif
5952 }
5953
5954#if defined(HAVE_SETJMP_H)
5955 /* Now handle X IO errors normally. */
5956 (void)XSetIOErrorHandler(oldIOhandler);
5957#endif
5958 /* Now handle X errors normally. */
5959 (void)XSetErrorHandler(oldhandler);
5960
5961 if (xterm_dpy == NULL)
5962 {
5963 if (p_verbose > 0)
5964 MSG(_("Opening the X display failed"));
5965 return;
5966 }
5967
5968 /* Catch terminating error of the X server connection. */
5969 (void)XSetIOErrorHandler(x_IOerror_handler);
5970
5971# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5972 if (p_verbose > 0)
5973 xopen_message(&start_tv);
5974# endif
5975
5976 /* Create a Shell to make converters work. */
5977 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
5978 applicationShellWidgetClass, xterm_dpy,
5979 NULL);
5980 if (AppShell == (Widget)0)
5981 return;
5982 xterm_Shell = XtVaCreatePopupShell("VIM",
5983 topLevelShellWidgetClass, AppShell,
5984 XtNmappedWhenManaged, 0,
5985 XtNwidth, 1,
5986 XtNheight, 1,
5987 NULL);
5988 if (xterm_Shell == (Widget)0)
5989 return;
5990
5991 x11_setup_atoms(xterm_dpy);
5992 if (x11_display == NULL)
5993 x11_display = xterm_dpy;
5994
5995 XtRealizeWidget(xterm_Shell);
5996 XSync(xterm_dpy, False);
5997 xterm_update();
5998 }
5999 if (xterm_Shell != (Widget)0)
6000 {
6001 clip_init(TRUE);
6002 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6003 x11_window = (Window)atol(strp);
6004 /* Check if $WINDOWID is valid. */
6005 if (test_x11_window(xterm_dpy) == FAIL)
6006 x11_window = 0;
6007 if (x11_window != 0)
6008 xterm_trace = 0;
6009 }
6010}
6011
6012 void
6013start_xterm_trace(button)
6014 int button;
6015{
6016 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6017 return;
6018 xterm_trace = 1;
6019 xterm_button = button;
6020 do_xterm_trace();
6021}
6022
6023
6024 void
6025stop_xterm_trace()
6026{
6027 if (xterm_trace < 0)
6028 return;
6029 xterm_trace = 0;
6030}
6031
6032/*
6033 * Query the xterm pointer and generate mouse termcodes if necessary
6034 * return TRUE if dragging is active, else FALSE
6035 */
6036 static int
6037do_xterm_trace()
6038{
6039 Window root, child;
6040 int root_x, root_y;
6041 int win_x, win_y;
6042 int row, col;
6043 int_u mask_return;
6044 char_u buf[50];
6045 char_u *strp;
6046 long got_hints;
6047 static char_u *mouse_code;
6048 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6049 static int prev_row = 0, prev_col = 0;
6050 static XSizeHints xterm_hints;
6051
6052 if (xterm_trace <= 0)
6053 return FALSE;
6054
6055 if (xterm_trace == 1)
6056 {
6057 /* Get the hints just before tracking starts. The font size might
6058 * have changed recently */
6059 XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints);
6060 if (!(got_hints & PResizeInc)
6061 || xterm_hints.width_inc <= 1
6062 || xterm_hints.height_inc <= 1)
6063 {
6064 xterm_trace = -1; /* Not enough data -- disable tracing */
6065 return FALSE;
6066 }
6067
6068 /* Rely on the same mouse code for the duration of this */
6069 mouse_code = find_termcode(mouse_name);
6070 prev_row = mouse_row;
6071 prev_row = mouse_col;
6072 xterm_trace = 2;
6073
6074 /* Find the offset of the chars, there might be a scrollbar on the
6075 * left of the window and/or a menu on the top (eterm etc.) */
6076 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6077 &win_x, &win_y, &mask_return);
6078 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6079 - (xterm_hints.height_inc / 2);
6080 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6081 xterm_hints.y = 2;
6082 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6083 - (xterm_hints.width_inc / 2);
6084 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6085 xterm_hints.x = 2;
6086 return TRUE;
6087 }
6088 if (mouse_code == NULL)
6089 {
6090 xterm_trace = 0;
6091 return FALSE;
6092 }
6093
6094 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6095 &win_x, &win_y, &mask_return);
6096
6097 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6098 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6099 if (row == prev_row && col == prev_col)
6100 return TRUE;
6101
6102 STRCPY(buf, mouse_code);
6103 strp = buf + STRLEN(buf);
6104 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6105 *strp++ = (char_u)(col + ' ' + 1);
6106 *strp++ = (char_u)(row + ' ' + 1);
6107 *strp = 0;
6108 add_to_input_buf(buf, STRLEN(buf));
6109
6110 prev_row = row;
6111 prev_col = col;
6112 return TRUE;
6113}
6114
6115# if defined(FEAT_GUI) || defined(PROTO)
6116/*
6117 * Destroy the display, window and app_context. Required for GTK.
6118 */
6119 void
6120clear_xterm_clip()
6121{
6122 if (xterm_Shell != (Widget)0)
6123 {
6124 XtDestroyWidget(xterm_Shell);
6125 xterm_Shell = (Widget)0;
6126 }
6127 if (xterm_dpy != NULL)
6128 {
6129#if 0
6130 /* Lesstif and Solaris crash here, lose some memory */
6131 XtCloseDisplay(xterm_dpy);
6132#endif
6133 if (x11_display == xterm_dpy)
6134 x11_display = NULL;
6135 xterm_dpy = NULL;
6136 }
6137#if 0
6138 if (app_context != (XtAppContext)NULL)
6139 {
6140 /* Lesstif and Solaris crash here, lose some memory */
6141 XtDestroyApplicationContext(app_context);
6142 app_context = (XtAppContext)NULL;
6143 }
6144#endif
6145}
6146# endif
6147
6148/*
6149 * Catch up with any queued X events. This may put keyboard input into the
6150 * input buffer, call resize call-backs, trigger timers etc. If there is
6151 * nothing in the X event queue (& no timers pending), then we return
6152 * immediately.
6153 */
6154 static void
6155xterm_update()
6156{
6157 XEvent event;
6158
6159 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6160 {
6161 XtAppNextEvent(app_context, &event);
6162#ifdef FEAT_CLIENTSERVER
6163 {
6164 XPropertyEvent *e = (XPropertyEvent *)&event;
6165
6166 if (e->type == PropertyNotify && e->window == commWindow
6167 && e->atom == commProperty && e->state == PropertyNewValue)
6168 serverEventProc(xterm_dpy, &event);
6169 }
6170#endif
6171 XtDispatchEvent(&event);
6172 }
6173}
6174
6175 int
6176clip_xterm_own_selection(cbd)
6177 VimClipboard *cbd;
6178{
6179 if (xterm_Shell != (Widget)0)
6180 return clip_x11_own_selection(xterm_Shell, cbd);
6181 return FAIL;
6182}
6183
6184 void
6185clip_xterm_lose_selection(cbd)
6186 VimClipboard *cbd;
6187{
6188 if (xterm_Shell != (Widget)0)
6189 clip_x11_lose_selection(xterm_Shell, cbd);
6190}
6191
6192 void
6193clip_xterm_request_selection(cbd)
6194 VimClipboard *cbd;
6195{
6196 if (xterm_Shell != (Widget)0)
6197 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6198}
6199
6200 void
6201clip_xterm_set_selection(cbd)
6202 VimClipboard *cbd;
6203{
6204 clip_x11_set_selection(cbd);
6205}
6206#endif
6207
6208
6209#if defined(USE_XSMP) || defined(PROTO)
6210/*
6211 * Code for X Session Management Protocol.
6212 */
6213static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6214static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6215static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6216static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6217static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6218
6219
6220# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6221static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6222
6223/*
6224 * This is our chance to ask the user if they want to save,
6225 * or abort the logout
6226 */
6227/*ARGSUSED*/
6228 static void
6229xsmp_handle_interaction(smc_conn, client_data)
6230 SmcConn smc_conn;
6231 SmPointer client_data;
6232{
6233 cmdmod_T save_cmdmod;
6234 int cancel_shutdown = False;
6235
6236 save_cmdmod = cmdmod;
6237 cmdmod.confirm = TRUE;
6238 if (check_changed_any(FALSE))
6239 /* Mustn't logout */
6240 cancel_shutdown = True;
6241 cmdmod = save_cmdmod;
6242 setcursor(); /* position cursor */
6243 out_flush();
6244
6245 /* Done interaction */
6246 SmcInteractDone(smc_conn, cancel_shutdown);
6247
6248 /* Finish off
6249 * Only end save-yourself here if we're not cancelling shutdown;
6250 * we'll get a cancelled callback later in which we'll end it.
6251 * Hopefully get around glitchy SMs (like GNOME-1)
6252 */
6253 if (!cancel_shutdown)
6254 {
6255 xsmp.save_yourself = False;
6256 SmcSaveYourselfDone(smc_conn, True);
6257 }
6258}
6259# endif
6260
6261/*
6262 * Callback that starts save-yourself.
6263 */
6264/*ARGSUSED*/
6265 static void
6266xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6267 shutdown, interact_style, fast)
6268 SmcConn smc_conn;
6269 SmPointer client_data;
6270 int save_type;
6271 Bool shutdown;
6272 int interact_style;
6273 Bool fast;
6274{
6275 /* Handle already being in saveyourself */
6276 if (xsmp.save_yourself)
6277 SmcSaveYourselfDone(smc_conn, True);
6278 xsmp.save_yourself = True;
6279 xsmp.shutdown = shutdown;
6280
6281 /* First up, preserve all files */
6282 out_flush();
6283 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6284
6285 if (p_verbose > 0)
6286 MSG(_("XSMP handling save-yourself request"));
6287
6288# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6289 /* Now see if we can ask about unsaved files */
6290 if (shutdown && !fast && gui.in_use)
6291 /* Need to interact with user, but need SM's permission */
6292 SmcInteractRequest(smc_conn, SmDialogError,
6293 xsmp_handle_interaction, client_data);
6294 else
6295# endif
6296 {
6297 /* Can stop the cycle here */
6298 SmcSaveYourselfDone(smc_conn, True);
6299 xsmp.save_yourself = False;
6300 }
6301}
6302
6303
6304/*
6305 * Callback to warn us of imminent death.
6306 */
6307/*ARGSUSED*/
6308 static void
6309xsmp_die(smc_conn, client_data)
6310 SmcConn smc_conn;
6311 SmPointer client_data;
6312{
6313 xsmp_close();
6314
6315 /* quit quickly leaving swapfiles for modified buffers behind */
6316 getout_preserve_modified(0);
6317}
6318
6319
6320/*
6321 * Callback to tell us that save-yourself has completed.
6322 */
6323/*ARGSUSED*/
6324 static void
6325xsmp_save_complete(smc_conn, client_data)
6326 SmcConn smc_conn;
6327 SmPointer client_data;
6328{
6329 xsmp.save_yourself = False;
6330}
6331
6332
6333/*
6334 * Callback to tell us that an instigated shutdown was cancelled
6335 * (maybe even by us)
6336 */
6337/*ARGSUSED*/
6338 static void
6339xsmp_shutdown_cancelled(smc_conn, client_data)
6340 SmcConn smc_conn;
6341 SmPointer client_data;
6342{
6343 if (xsmp.save_yourself)
6344 SmcSaveYourselfDone(smc_conn, True);
6345 xsmp.save_yourself = False;
6346 xsmp.shutdown = False;
6347}
6348
6349
6350/*
6351 * Callback to tell us that a new ICE connection has been established.
6352 */
6353/*ARGSUSED*/
6354 static void
6355xsmp_ice_connection(iceConn, clientData, opening, watchData)
6356 IceConn iceConn;
6357 IcePointer clientData;
6358 Bool opening;
6359 IcePointer *watchData;
6360{
6361 /* Intercept creation of ICE connection fd */
6362 if (opening)
6363 {
6364 xsmp_icefd = IceConnectionNumber(iceConn);
6365 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6366 }
6367}
6368
6369
6370/* Handle any ICE processing that's required; return FAIL if SM lost */
6371 int
6372xsmp_handle_requests()
6373{
6374 Bool rep;
6375
6376 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6377 == IceProcessMessagesIOError)
6378 {
6379 /* Lost ICE */
6380 if (p_verbose > 0)
6381 MSG(_("XSMP lost ICE connection"));
6382 xsmp_close();
6383 return FAIL;
6384 }
6385 else
6386 return OK;
6387}
6388
6389static int dummy;
6390
6391/* Set up X Session Management Protocol */
6392 void
6393xsmp_init(void)
6394{
6395 char errorstring[80];
6396 char *clientid;
6397 SmcCallbacks smcallbacks;
6398#if 0
6399 SmPropValue smname;
6400 SmProp smnameprop;
6401 SmProp *smprops[1];
6402#endif
6403
6404 if (p_verbose > 0)
6405 MSG(_("XSMP opening connection"));
6406
6407 xsmp.save_yourself = xsmp.shutdown = False;
6408
6409 /* Set up SM callbacks - must have all, even if they're not used */
6410 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6411 smcallbacks.save_yourself.client_data = NULL;
6412 smcallbacks.die.callback = xsmp_die;
6413 smcallbacks.die.client_data = NULL;
6414 smcallbacks.save_complete.callback = xsmp_save_complete;
6415 smcallbacks.save_complete.client_data = NULL;
6416 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6417 smcallbacks.shutdown_cancelled.client_data = NULL;
6418
6419 /* Set up a watch on ICE connection creations. The "dummy" argument is
6420 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6421 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6422 {
6423 if (p_verbose > 0)
6424 MSG(_("XSMP ICE connection watch failed"));
6425 return;
6426 }
6427
6428 /* Create an SM connection */
6429 xsmp.smcconn = SmcOpenConnection(
6430 NULL,
6431 NULL,
6432 SmProtoMajor,
6433 SmProtoMinor,
6434 SmcSaveYourselfProcMask | SmcDieProcMask
6435 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6436 &smcallbacks,
6437 NULL,
6438 &clientid,
6439 sizeof(errorstring),
6440 errorstring);
6441 if (xsmp.smcconn == NULL)
6442 {
6443 char errorreport[132];
6444 sprintf(errorreport, _("XSMP SmcOpenConnection failed: %s"),
6445 errorstring);
6446 if (p_verbose > 0)
6447 MSG(errorreport);
6448 return;
6449 }
6450 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6451
6452#if 0
6453 /* ID ourselves */
6454 smname.value = "vim";
6455 smname.length = 3;
6456 smnameprop.name = "SmProgram";
6457 smnameprop.type = "SmARRAY8";
6458 smnameprop.num_vals = 1;
6459 smnameprop.vals = &smname;
6460
6461 smprops[0] = &smnameprop;
6462 SmcSetProperties(xsmp.smcconn, 1, smprops);
6463#endif
6464}
6465
6466
6467/* Shut down XSMP comms. */
6468 void
6469xsmp_close()
6470{
6471 if (xsmp_icefd != -1)
6472 {
6473 SmcCloseConnection(xsmp.smcconn, 0, NULL);
6474 xsmp_icefd = -1;
6475 }
6476}
6477#endif /* USE_XSMP */
6478
6479
6480#ifdef EBCDIC
6481/* Translate character to its CTRL- value */
6482char CtrlTable[] =
6483{
6484/* 00 - 5E */
6485 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6486 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6487 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6488 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6489 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6490 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6491/* ^ */ 0x1E,
6492/* - */ 0x1F,
6493/* 61 - 6C */
6494 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6495/* _ */ 0x1F,
6496/* 6E - 80 */
6497 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6498/* a */ 0x01,
6499/* b */ 0x02,
6500/* c */ 0x03,
6501/* d */ 0x37,
6502/* e */ 0x2D,
6503/* f */ 0x2E,
6504/* g */ 0x2F,
6505/* h */ 0x16,
6506/* i */ 0x05,
6507/* 8A - 90 */
6508 0, 0, 0, 0, 0, 0, 0,
6509/* j */ 0x15,
6510/* k */ 0x0B,
6511/* l */ 0x0C,
6512/* m */ 0x0D,
6513/* n */ 0x0E,
6514/* o */ 0x0F,
6515/* p */ 0x10,
6516/* q */ 0x11,
6517/* r */ 0x12,
6518/* 9A - A1 */
6519 0, 0, 0, 0, 0, 0, 0, 0,
6520/* s */ 0x13,
6521/* t */ 0x3C,
6522/* u */ 0x3D,
6523/* v */ 0x32,
6524/* w */ 0x26,
6525/* x */ 0x18,
6526/* y */ 0x19,
6527/* z */ 0x3F,
6528/* AA - AC */
6529 0, 0, 0,
6530/* [ */ 0x27,
6531/* AE - BC */
6532 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6533/* ] */ 0x1D,
6534/* BE - C0 */ 0, 0, 0,
6535/* A */ 0x01,
6536/* B */ 0x02,
6537/* C */ 0x03,
6538/* D */ 0x37,
6539/* E */ 0x2D,
6540/* F */ 0x2E,
6541/* G */ 0x2F,
6542/* H */ 0x16,
6543/* I */ 0x05,
6544/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6545/* J */ 0x15,
6546/* K */ 0x0B,
6547/* L */ 0x0C,
6548/* M */ 0x0D,
6549/* N */ 0x0E,
6550/* O */ 0x0F,
6551/* P */ 0x10,
6552/* Q */ 0x11,
6553/* R */ 0x12,
6554/* DA - DF */ 0, 0, 0, 0, 0, 0,
6555/* \ */ 0x1C,
6556/* E1 */ 0,
6557/* S */ 0x13,
6558/* T */ 0x3C,
6559/* U */ 0x3D,
6560/* V */ 0x32,
6561/* W */ 0x26,
6562/* X */ 0x18,
6563/* Y */ 0x19,
6564/* Z */ 0x3F,
6565/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6566 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6567};
6568
6569char MetaCharTable[]=
6570{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6571 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6572 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6573 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6574 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6575};
6576
6577
6578/* TODO: Use characters NOT numbers!!! */
6579char CtrlCharTable[]=
6580{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6581 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6582 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6583 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6584 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6585};
6586
6587
6588#endif