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