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