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