blob: 639ef312769b981c255a41d03c3a2e3c1b2cf009 [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/*
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002205 * Get absolute file name into "buf[len]".
Bram Moolenaar071d4272004-06-13 20:20:40 +00002206 *
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{
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002215#ifdef VMS
2216 /*
2217 * VMS does this in a completely different way.
2218 *
2219 * By default a file found in a complex path is written to the first
2220 * directory in the path and not to the original directory. This
2221 * behaviour should be avoided for the existing files and we need to find
2222 * the exact path of the edited file.
2223 */
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002224 {
2225 char_u *fixed_fname = vms_fixfilename(fname);
2226 int fd = mch_open((char *)fixed_fname, O_RDONLY | O_EXTRA, 0);
2227
2228 if (fd > 0)
2229 {
2230 char nbuf[MAXNAMLEN];
2231
2232 /* File exists, use getname() to get the real name. */
2233 if (getname(fd, nbuf))
2234 vim_strncpy(fixed_fname, (char_u *)nbuf, (size_t)(len - 1));
2235 close(fd);
2236 }
2237
2238 if (STRLEN(fixed_fname) >= len)
2239 return FAIL;
2240
2241 STRCPY(buf, fixed_fname);
2242 }
2243
2244#else /* not VMS */
2245
Bram Moolenaar071d4272004-06-13 20:20:40 +00002246 int l;
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002247# ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002248 int only_drive; /* file name is only a drive letter */
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002249# endif
2250# ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002251 int fd = -1;
2252 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002253# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002254 char_u olddir[MAXPATHL];
2255 char_u *p;
2256 int retval = OK;
2257
Bram Moolenaar071d4272004-06-13 20:20:40 +00002258 /* expand it if forced or not an absolute path */
2259 if (force || !mch_isFullName(fname))
2260 {
2261 /*
2262 * If the file name has a path, change to that directory for a moment,
2263 * and then do the getwd() (and get back to where we were).
2264 * This will get the correct path name with "../" things.
2265 */
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002266# ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 only_drive = 0;
2268 if (((p = vim_strrchr(fname, '/')) != NULL)
2269 || ((p = vim_strrchr(fname, '\\')) != NULL)
2270 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002271# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002272 if ((p = vim_strrchr(fname, '/')) != NULL)
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002273# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002274 {
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002275# ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002276 /*
2277 * Use fchdir() if possible, it's said to be faster and more
2278 * reliable. But on SunOS 4 it might not work. Check this by
2279 * doing a fchdir() right now.
2280 */
2281 if (!dont_fchdir)
2282 {
2283 fd = open(".", O_RDONLY | O_EXTRA, 0);
2284 if (fd >= 0 && fchdir(fd) < 0)
2285 {
2286 close(fd);
2287 fd = -1;
2288 dont_fchdir = TRUE; /* don't try again */
2289 }
2290 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002291# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002292
2293 /* Only change directory when we are sure we can return to where
2294 * we are now. After doing "su" chdir(".") might not work. */
2295 if (
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002296# ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002297 fd < 0 &&
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002298# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002299 (mch_dirname(olddir, MAXPATHL) == FAIL
2300 || mch_chdir((char *)olddir) != 0))
2301 {
2302 p = NULL; /* can't get current dir: don't chdir */
2303 retval = FAIL;
2304 }
2305 else
2306 {
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002307# ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002308 /*
2309 * compensate for case where ':' from "D:" was the only
2310 * path separator detected in the file name; the _next_
2311 * character has to be removed, and then restored later.
2312 */
2313 if (only_drive)
2314 p++;
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002315# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002316 /* The directory is copied into buf[], to be able to remove
2317 * the file name without changing it (could be a string in
2318 * read-only memory) */
2319 if (p - fname >= len)
2320 retval = FAIL;
2321 else
2322 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002323 vim_strncpy(buf, fname, p - fname);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002324 if (mch_chdir((char *)buf))
2325 retval = FAIL;
2326 else
2327 fname = p + 1;
2328 *buf = NUL;
2329 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002330# ifdef OS2
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331 if (only_drive)
2332 {
2333 p--;
2334 if (retval != FAIL)
2335 fname--;
2336 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002337# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002338 }
2339 }
2340 if (mch_dirname(buf, len) == FAIL)
2341 {
2342 retval = FAIL;
2343 *buf = NUL;
2344 }
2345 if (p != NULL)
2346 {
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002347# ifdef HAVE_FCHDIR
Bram Moolenaar071d4272004-06-13 20:20:40 +00002348 if (fd >= 0)
2349 {
2350 l = fchdir(fd);
2351 close(fd);
2352 }
2353 else
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002354# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002355 l = mch_chdir((char *)olddir);
2356 if (l != 0)
2357 EMSG(_(e_prev_dir));
2358 }
2359
2360 l = STRLEN(buf);
2361 if (l >= len)
2362 retval = FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002363 else
2364 {
2365 if (l > 0 && buf[l - 1] != '/' && *fname != NUL
2366 && STRCMP(fname, ".") != 0)
2367 STRCAT(buf, "/");
2368 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369 }
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002370
Bram Moolenaar071d4272004-06-13 20:20:40 +00002371 /* Catch file names which are too long. */
2372 if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len)
2373 return FAIL;
2374
2375 /* Do not append ".", "/dir/." is equal to "/dir". */
2376 if (STRCMP(fname, ".") != 0)
2377 STRCAT(buf, fname);
2378
Bram Moolenaar3d20ca12006-11-28 16:43:58 +00002379#endif /* VMS */
2380
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381 return OK;
2382}
2383
2384/*
2385 * Return TRUE if "fname" does not depend on the current directory.
2386 */
2387 int
2388mch_isFullName(fname)
2389 char_u *fname;
2390{
2391#ifdef __EMX__
2392 return _fnisabs(fname);
2393#else
2394# ifdef VMS
2395 return ( fname[0] == '/' || fname[0] == '.' ||
2396 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2397 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2398 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2399# else
2400 return (*fname == '/' || *fname == '~');
2401# endif
2402#endif
2403}
2404
Bram Moolenaar24552be2005-12-10 20:17:30 +00002405#if defined(USE_FNAME_CASE) || defined(PROTO)
2406/*
2407 * Set the case of the file name, if it already exists. This will cause the
2408 * file name to remain exactly the same.
2409 * Only required for file systems where case is ingored and preserved.
2410 */
2411/*ARGSUSED*/
2412 void
2413fname_case(name, len)
2414 char_u *name;
2415 int len; /* buffer size, only used when name gets longer */
2416{
2417 struct stat st;
2418 char_u *slash, *tail;
2419 DIR *dirp;
2420 struct dirent *dp;
2421
2422 if (lstat((char *)name, &st) >= 0)
2423 {
2424 /* Open the directory where the file is located. */
2425 slash = vim_strrchr(name, '/');
2426 if (slash == NULL)
2427 {
2428 dirp = opendir(".");
2429 tail = name;
2430 }
2431 else
2432 {
2433 *slash = NUL;
2434 dirp = opendir((char *)name);
2435 *slash = '/';
2436 tail = slash + 1;
2437 }
2438
2439 if (dirp != NULL)
2440 {
2441 while ((dp = readdir(dirp)) != NULL)
2442 {
2443 /* Only accept names that differ in case and are the same byte
2444 * length. TODO: accept different length name. */
2445 if (STRICMP(tail, dp->d_name) == 0
2446 && STRLEN(tail) == STRLEN(dp->d_name))
2447 {
2448 char_u newname[MAXPATHL + 1];
2449 struct stat st2;
2450
2451 /* Verify the inode is equal. */
2452 vim_strncpy(newname, name, MAXPATHL);
2453 vim_strncpy(newname + (tail - name), (char_u *)dp->d_name,
2454 MAXPATHL - (tail - name));
2455 if (lstat((char *)newname, &st2) >= 0
2456 && st.st_ino == st2.st_ino
2457 && st.st_dev == st2.st_dev)
2458 {
2459 STRCPY(tail, dp->d_name);
2460 break;
2461 }
2462 }
2463 }
2464
2465 closedir(dirp);
2466 }
2467 }
2468}
2469#endif
2470
Bram Moolenaar071d4272004-06-13 20:20:40 +00002471/*
2472 * Get file permissions for 'name'.
2473 * Returns -1 when it doesn't exist.
2474 */
2475 long
2476mch_getperm(name)
2477 char_u *name;
2478{
2479 struct stat statb;
2480
2481 /* Keep the #ifdef outside of stat(), it may be a macro. */
2482#ifdef VMS
2483 if (stat((char *)vms_fixfilename(name), &statb))
2484#else
2485 if (stat((char *)name, &statb))
2486#endif
2487 return -1;
2488 return statb.st_mode;
2489}
2490
2491/*
2492 * set file permission for 'name' to 'perm'
2493 *
2494 * return FAIL for failure, OK otherwise
2495 */
2496 int
2497mch_setperm(name, perm)
2498 char_u *name;
2499 long perm;
2500{
2501 return (chmod((char *)
2502#ifdef VMS
2503 vms_fixfilename(name),
2504#else
2505 name,
2506#endif
2507 (mode_t)perm) == 0 ? OK : FAIL);
2508}
2509
2510#if defined(HAVE_ACL) || defined(PROTO)
2511# ifdef HAVE_SYS_ACL_H
2512# include <sys/acl.h>
2513# endif
2514# ifdef HAVE_SYS_ACCESS_H
2515# include <sys/access.h>
2516# endif
2517
2518# ifdef HAVE_SOLARIS_ACL
2519typedef struct vim_acl_solaris_T {
2520 int acl_cnt;
2521 aclent_t *acl_entry;
2522} vim_acl_solaris_T;
2523# endif
2524
2525/*
2526 * Return a pointer to the ACL of file "fname" in allocated memory.
2527 * Return NULL if the ACL is not available for whatever reason.
2528 */
2529 vim_acl_T
2530mch_get_acl(fname)
2531 char_u *fname;
2532{
2533 vim_acl_T ret = NULL;
2534#ifdef HAVE_POSIX_ACL
2535 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2536#else
2537#ifdef HAVE_SOLARIS_ACL
2538 vim_acl_solaris_T *aclent;
2539
2540 aclent = malloc(sizeof(vim_acl_solaris_T));
2541 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2542 {
2543 free(aclent);
2544 return NULL;
2545 }
2546 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2547 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2548 {
2549 free(aclent->acl_entry);
2550 free(aclent);
2551 return NULL;
2552 }
2553 ret = (vim_acl_T)aclent;
2554#else
2555#if defined(HAVE_AIX_ACL)
2556 int aclsize;
2557 struct acl *aclent;
2558
2559 aclsize = sizeof(struct acl);
2560 aclent = malloc(aclsize);
2561 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2562 {
2563 if (errno == ENOSPC)
2564 {
2565 aclsize = aclent->acl_len;
2566 aclent = realloc(aclent, aclsize);
2567 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2568 {
2569 free(aclent);
2570 return NULL;
2571 }
2572 }
2573 else
2574 {
2575 free(aclent);
2576 return NULL;
2577 }
2578 }
2579 ret = (vim_acl_T)aclent;
2580#endif /* HAVE_AIX_ACL */
2581#endif /* HAVE_SOLARIS_ACL */
2582#endif /* HAVE_POSIX_ACL */
2583 return ret;
2584}
2585
2586/*
2587 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2588 */
2589 void
2590mch_set_acl(fname, aclent)
2591 char_u *fname;
2592 vim_acl_T aclent;
2593{
2594 if (aclent == NULL)
2595 return;
2596#ifdef HAVE_POSIX_ACL
2597 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2598#else
2599#ifdef HAVE_SOLARIS_ACL
2600 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2601 ((vim_acl_solaris_T *)aclent)->acl_entry);
2602#else
2603#ifdef HAVE_AIX_ACL
2604 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2605#endif /* HAVE_AIX_ACL */
2606#endif /* HAVE_SOLARIS_ACL */
2607#endif /* HAVE_POSIX_ACL */
2608}
2609
2610 void
2611mch_free_acl(aclent)
2612 vim_acl_T aclent;
2613{
2614 if (aclent == NULL)
2615 return;
2616#ifdef HAVE_POSIX_ACL
2617 acl_free((acl_t)aclent);
2618#else
2619#ifdef HAVE_SOLARIS_ACL
2620 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2621 free(aclent);
2622#else
2623#ifdef HAVE_AIX_ACL
2624 free(aclent);
2625#endif /* HAVE_AIX_ACL */
2626#endif /* HAVE_SOLARIS_ACL */
2627#endif /* HAVE_POSIX_ACL */
2628}
2629#endif
2630
2631/*
2632 * Set hidden flag for "name".
2633 */
2634/* ARGSUSED */
2635 void
2636mch_hide(name)
2637 char_u *name;
2638{
2639 /* can't hide a file */
2640}
2641
2642/*
2643 * return TRUE if "name" is a directory
2644 * return FALSE if "name" is not a directory
2645 * return FALSE for error
2646 */
2647 int
2648mch_isdir(name)
2649 char_u *name;
2650{
2651 struct stat statb;
2652
2653 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2654 return FALSE;
2655 if (stat((char *)name, &statb))
2656 return FALSE;
2657#ifdef _POSIX_SOURCE
2658 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2659#else
2660 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2661#endif
2662}
2663
Bram Moolenaar071d4272004-06-13 20:20:40 +00002664static int executable_file __ARGS((char_u *name));
2665
2666/*
2667 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2668 */
2669 static int
2670executable_file(name)
2671 char_u *name;
2672{
2673 struct stat st;
2674
2675 if (stat((char *)name, &st))
2676 return 0;
2677 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2678}
2679
2680/*
2681 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2682 * Return -1 if unknown.
2683 */
2684 int
2685mch_can_exe(name)
2686 char_u *name;
2687{
2688 char_u *buf;
2689 char_u *p, *e;
2690 int retval;
2691
2692 /* If it's an absolute or relative path don't need to use $PATH. */
2693 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2694 || (name[1] == '.' && name[2] == '/'))))
2695 return executable_file(name);
2696
2697 p = (char_u *)getenv("PATH");
2698 if (p == NULL || *p == NUL)
2699 return -1;
2700 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2701 if (buf == NULL)
2702 return -1;
2703
2704 /*
2705 * Walk through all entries in $PATH to check if "name" exists there and
2706 * is an executable file.
2707 */
2708 for (;;)
2709 {
2710 e = (char_u *)strchr((char *)p, ':');
2711 if (e == NULL)
2712 e = p + STRLEN(p);
2713 if (e - p <= 1) /* empty entry means current dir */
2714 STRCPY(buf, "./");
2715 else
2716 {
Bram Moolenaarbbebc852005-07-18 21:47:53 +00002717 vim_strncpy(buf, p, e - p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002718 add_pathsep(buf);
2719 }
2720 STRCAT(buf, name);
2721 retval = executable_file(buf);
2722 if (retval == 1)
2723 break;
2724
2725 if (*e != ':')
2726 break;
2727 p = e + 1;
2728 }
2729
2730 vim_free(buf);
2731 return retval;
2732}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002733
2734/*
2735 * Check what "name" is:
2736 * NODE_NORMAL: file or directory (or doesn't exist)
2737 * NODE_WRITABLE: writable device, socket, fifo, etc.
2738 * NODE_OTHER: non-writable things
2739 */
2740 int
2741mch_nodetype(name)
2742 char_u *name;
2743{
2744 struct stat st;
2745
2746 if (stat((char *)name, &st))
2747 return NODE_NORMAL;
2748 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2749 return NODE_NORMAL;
2750#ifndef OS2
2751 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2752 return NODE_OTHER;
2753#endif
2754 /* Everything else is writable? */
2755 return NODE_WRITABLE;
2756}
2757
2758 void
2759mch_early_init()
2760{
2761#ifdef HAVE_CHECK_STACK_GROWTH
2762 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002763
Bram Moolenaar071d4272004-06-13 20:20:40 +00002764 check_stack_growth((char *)&i);
2765
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002766# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002767 get_stack_limit();
2768# endif
2769
2770#endif
2771
2772 /*
2773 * Setup an alternative stack for signals. Helps to catch signals when
2774 * running out of stack space.
2775 * Use of sigaltstack() is preferred, it's more portable.
2776 * Ignore any errors.
2777 */
2778#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2779 signal_stack = malloc(SIGSTKSZ);
2780 init_signal_stack();
2781#endif
2782}
2783
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002784#if defined(EXITFREE) || defined(PROTO)
2785 void
2786mch_free_mem()
2787{
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002788# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
2789 if (clip_star.owned)
2790 clip_lose_selection(&clip_star);
2791 if (clip_plus.owned)
2792 clip_lose_selection(&clip_plus);
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002793# endif
2794# if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
2795 if (xterm_Shell != (Widget)0)
2796 XtDestroyWidget(xterm_Shell);
2797 if (xterm_dpy != NULL)
2798 XtCloseDisplay(xterm_dpy);
2799 if (app_context != (XtAppContext)NULL)
2800 XtDestroyApplicationContext(app_context);
2801# endif
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00002802# ifdef FEAT_X11
2803 if (x11_display != NULL && x11_display != xterm_dpy)
2804 XCloseDisplay(x11_display);
2805# endif
2806# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2807 vim_free(signal_stack);
2808 signal_stack = NULL;
2809# endif
2810# ifdef FEAT_TITLE
2811 vim_free(oldtitle);
2812 vim_free(oldicon);
2813# endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002814}
2815#endif
2816
Bram Moolenaar071d4272004-06-13 20:20:40 +00002817static void exit_scroll __ARGS((void));
2818
2819/*
2820 * Output a newline when exiting.
2821 * Make sure the newline goes to the same stream as the text.
2822 */
2823 static void
2824exit_scroll()
2825{
Bram Moolenaardf177f62005-02-22 08:39:57 +00002826 if (silent_mode)
2827 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002828 if (newline_on_exit || msg_didout)
2829 {
2830 if (msg_use_printf())
2831 {
2832 if (info_message)
2833 mch_msg("\n");
2834 else
2835 mch_errmsg("\r\n");
2836 }
2837 else
2838 out_char('\n');
2839 }
2840 else
2841 {
2842 restore_cterm_colors(); /* get original colors back */
2843 msg_clr_eos_force(); /* clear the rest of the display */
2844 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
2845 }
2846}
2847
2848 void
2849mch_exit(r)
2850 int r;
2851{
2852 exiting = TRUE;
2853
2854#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
2855 x11_export_final_selection();
2856#endif
2857
2858#ifdef FEAT_GUI
2859 if (!gui.in_use)
2860#endif
2861 {
2862 settmode(TMODE_COOK);
2863#ifdef FEAT_TITLE
2864 mch_restore_title(3); /* restore xterm title and icon name */
2865#endif
2866 /*
2867 * When t_ti is not empty but it doesn't cause swapping terminal
2868 * pages, need to output a newline when msg_didout is set. But when
2869 * t_ti does swap pages it should not go to the shell page. Do this
2870 * before stoptermcap().
2871 */
2872 if (swapping_screen() && !newline_on_exit)
2873 exit_scroll();
2874
2875 /* Stop termcap: May need to check for T_CRV response, which
2876 * requires RAW mode. */
2877 stoptermcap();
2878
2879 /*
2880 * A newline is only required after a message in the alternate screen.
2881 * This is set to TRUE by wait_return().
2882 */
2883 if (!swapping_screen() || newline_on_exit)
2884 exit_scroll();
2885
2886 /* Cursor may have been switched off without calling starttermcap()
2887 * when doing "vim -u vimrc" and vimrc contains ":q". */
2888 if (full_screen)
2889 cursor_on();
2890 }
2891 out_flush();
2892 ml_close_all(TRUE); /* remove all memfiles */
2893 may_core_dump();
2894#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002895 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002896 gui_exit(r);
2897#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00002898
Bram Moolenaar56718732006-03-15 22:53:57 +00002899#ifdef MACOS_CONVERT
Bram Moolenaardf177f62005-02-22 08:39:57 +00002900 mac_conv_cleanup();
2901#endif
2902
Bram Moolenaar071d4272004-06-13 20:20:40 +00002903#ifdef __QNX__
2904 /* A core dump won't be created if the signal handler
2905 * doesn't return, so we can't call exit() */
2906 if (deadly_signal != 0)
2907 return;
2908#endif
2909
Bram Moolenaar009b2592004-10-24 19:18:58 +00002910#ifdef FEAT_NETBEANS_INTG
2911 if (usingNetbeans)
2912 netbeans_send_disconnect();
2913#endif
Bram Moolenaar0a5fe212005-06-24 23:01:23 +00002914
2915#ifdef EXITFREE
2916 free_all_mem();
2917#endif
2918
Bram Moolenaar071d4272004-06-13 20:20:40 +00002919 exit(r);
2920}
2921
2922 static void
2923may_core_dump()
2924{
2925 if (deadly_signal != 0)
2926 {
2927 signal(deadly_signal, SIG_DFL);
2928 kill(getpid(), deadly_signal); /* Die using the signal we caught */
2929 }
2930}
2931
2932#ifndef VMS
2933
2934 void
2935mch_settmode(tmode)
2936 int tmode;
2937{
2938 static int first = TRUE;
2939
2940 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2941#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2942 /*
2943 * for "new" tty systems
2944 */
2945# ifdef HAVE_TERMIOS_H
2946 static struct termios told;
2947 struct termios tnew;
2948# else
2949 static struct termio told;
2950 struct termio tnew;
2951# endif
2952
2953 if (first)
2954 {
2955 first = FALSE;
2956# if defined(HAVE_TERMIOS_H)
2957 tcgetattr(read_cmd_fd, &told);
2958# else
2959 ioctl(read_cmd_fd, TCGETA, &told);
2960# endif
2961 }
2962
2963 tnew = told;
2964 if (tmode == TMODE_RAW)
2965 {
2966 /*
2967 * ~ICRNL enables typing ^V^M
2968 */
2969 tnew.c_iflag &= ~ICRNL;
2970 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
2971# if defined(IEXTEN) && !defined(__MINT__)
2972 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
2973 /* but it breaks function keys on MINT */
2974# endif
2975 );
2976# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
2977 tnew.c_oflag &= ~ONLCR;
2978# endif
2979 tnew.c_cc[VMIN] = 1; /* return after 1 char */
2980 tnew.c_cc[VTIME] = 0; /* don't wait */
2981 }
2982 else if (tmode == TMODE_SLEEP)
2983 tnew.c_lflag &= ~(ECHO);
2984
2985# if defined(HAVE_TERMIOS_H)
2986 {
2987 int n = 10;
2988
2989 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
2990 * few times. */
2991 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
2992 && errno == EINTR && n > 0)
2993 --n;
2994 }
2995# else
2996 ioctl(read_cmd_fd, TCSETA, &tnew);
2997# endif
2998
2999#else
3000
3001 /*
3002 * for "old" tty systems
3003 */
3004# ifndef TIOCSETN
3005# define TIOCSETN TIOCSETP /* for hpux 9.0 */
3006# endif
3007 static struct sgttyb ttybold;
3008 struct sgttyb ttybnew;
3009
3010 if (first)
3011 {
3012 first = FALSE;
3013 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
3014 }
3015
3016 ttybnew = ttybold;
3017 if (tmode == TMODE_RAW)
3018 {
3019 ttybnew.sg_flags &= ~(CRMOD | ECHO);
3020 ttybnew.sg_flags |= RAW;
3021 }
3022 else if (tmode == TMODE_SLEEP)
3023 ttybnew.sg_flags &= ~(ECHO);
3024 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
3025#endif
3026 curr_tmode = tmode;
3027}
3028
3029/*
3030 * Try to get the code for "t_kb" from the stty setting
3031 *
3032 * Even if termcap claims a backspace key, the user's setting *should*
3033 * prevail. stty knows more about reality than termcap does, and if
3034 * somebody's usual erase key is DEL (which, for most BSD users, it will
3035 * be), they're going to get really annoyed if their erase key starts
3036 * doing forward deletes for no reason. (Eric Fischer)
3037 */
3038 void
3039get_stty()
3040{
3041 char_u buf[2];
3042 char_u *p;
3043
3044 /* Why is NeXT excluded here (and not in os_unixx.h)? */
3045#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
3046 /* for "new" tty systems */
3047# ifdef HAVE_TERMIOS_H
3048 struct termios keys;
3049# else
3050 struct termio keys;
3051# endif
3052
3053# if defined(HAVE_TERMIOS_H)
3054 if (tcgetattr(read_cmd_fd, &keys) != -1)
3055# else
3056 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
3057# endif
3058 {
3059 buf[0] = keys.c_cc[VERASE];
3060 intr_char = keys.c_cc[VINTR];
3061#else
3062 /* for "old" tty systems */
3063 struct sgttyb keys;
3064
3065 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
3066 {
3067 buf[0] = keys.sg_erase;
3068 intr_char = keys.sg_kill;
3069#endif
3070 buf[1] = NUL;
3071 add_termcode((char_u *)"kb", buf, FALSE);
3072
3073 /*
3074 * If <BS> and <DEL> are now the same, redefine <DEL>.
3075 */
3076 p = find_termcode((char_u *)"kD");
3077 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
3078 do_fixdel(NULL);
3079 }
3080#if 0
3081 } /* to keep cindent happy */
3082#endif
3083}
3084
3085#endif /* VMS */
3086
3087#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
3088/*
3089 * Set mouse clicks on or off.
3090 */
3091 void
3092mch_setmouse(on)
3093 int on;
3094{
3095 static int ison = FALSE;
3096 int xterm_mouse_vers;
3097
3098 if (on == ison) /* return quickly if nothing to do */
3099 return;
3100
3101 xterm_mouse_vers = use_xterm_mouse();
3102 if (xterm_mouse_vers > 0)
3103 {
3104 if (on) /* enable mouse events, use mouse tracking if available */
3105 out_str_nf((char_u *)
3106 (xterm_mouse_vers > 1
3107 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
3108 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3109 else /* disable mouse events, could probably always send the same */
3110 out_str_nf((char_u *)
3111 (xterm_mouse_vers > 1
3112 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3113 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3114 ison = on;
3115 }
3116
3117# ifdef FEAT_MOUSE_DEC
3118 else if (ttym_flags == TTYM_DEC)
3119 {
3120 if (on) /* enable mouse events */
3121 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3122 else /* disable mouse events */
3123 out_str_nf((char_u *)"\033['z");
3124 ison = on;
3125 }
3126# endif
3127
3128# ifdef FEAT_MOUSE_GPM
3129 else
3130 {
3131 if (on)
3132 {
3133 if (gpm_open())
3134 ison = TRUE;
3135 }
3136 else
3137 {
3138 gpm_close();
3139 ison = FALSE;
3140 }
3141 }
3142# endif
3143
3144# ifdef FEAT_MOUSE_JSB
3145 else
3146 {
3147 if (on)
3148 {
3149 /* D - Enable Mouse up/down messages
3150 * L - Enable Left Button Reporting
3151 * M - Enable Middle Button Reporting
3152 * R - Enable Right Button Reporting
3153 * K - Enable SHIFT and CTRL key Reporting
3154 * + - Enable Advanced messaging of mouse moves and up/down messages
3155 * Q - Quiet No Ack
3156 * # - Numeric value of mouse pointer required
3157 * 0 = Multiview 2000 cursor, used as standard
3158 * 1 = Windows Arrow
3159 * 2 = Windows I Beam
3160 * 3 = Windows Hour Glass
3161 * 4 = Windows Cross Hair
3162 * 5 = Windows UP Arrow
3163 */
3164#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3165 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3166 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3167#else
3168 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3169 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3170#endif
3171 ison = TRUE;
3172 }
3173 else
3174 {
3175 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3176 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3177 ison = FALSE;
3178 }
3179 }
3180# endif
3181# ifdef FEAT_MOUSE_PTERM
3182 else
3183 {
3184 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3185 if (on)
3186 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3187 else
3188 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3189 ison = on;
3190 }
3191# endif
3192}
3193
3194/*
3195 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3196 */
3197 void
3198check_mouse_termcode()
3199{
3200# ifdef FEAT_MOUSE_XTERM
3201 if (use_xterm_mouse()
3202# ifdef FEAT_GUI
3203 && !gui.in_use
3204# endif
3205 )
3206 {
3207 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003208 ? IF_EB("\233M", CSI_STR "M")
3209 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210 if (*p_mouse != NUL)
3211 {
3212 /* force mouse off and maybe on to send possibly new mouse
3213 * activation sequence to the xterm, with(out) drag tracing. */
3214 mch_setmouse(FALSE);
3215 setmouse();
3216 }
3217 }
3218 else
3219 del_mouse_termcode(KS_MOUSE);
3220# endif
3221
3222# ifdef FEAT_MOUSE_GPM
3223 if (!use_xterm_mouse()
3224# ifdef FEAT_GUI
3225 && !gui.in_use
3226# endif
3227 )
3228 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3229# endif
3230
3231# ifdef FEAT_MOUSE_JSB
3232 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3233 if (!use_xterm_mouse()
3234# ifdef FEAT_GUI
3235 && !gui.in_use
3236# endif
3237 )
3238 set_mouse_termcode(KS_JSBTERM_MOUSE,
3239 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3240 else
3241 del_mouse_termcode(KS_JSBTERM_MOUSE);
3242# endif
3243
3244# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003245 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003246 * define it in the GUI or when using an xterm. */
3247 if (!use_xterm_mouse()
3248# ifdef FEAT_GUI
3249 && !gui.in_use
3250# endif
3251 )
3252 set_mouse_termcode(KS_NETTERM_MOUSE,
3253 (char_u *)IF_EB("\033}", ESC_STR "}"));
3254 else
3255 del_mouse_termcode(KS_NETTERM_MOUSE);
3256# endif
3257
3258# ifdef FEAT_MOUSE_DEC
3259 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3260 if (!use_xterm_mouse()
3261# ifdef FEAT_GUI
3262 && !gui.in_use
3263# endif
3264 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003265 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3266 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003267 else
3268 del_mouse_termcode(KS_DEC_MOUSE);
3269# endif
3270# ifdef FEAT_MOUSE_PTERM
3271 /* same as the dec mouse */
3272 if (!use_xterm_mouse()
3273# ifdef FEAT_GUI
3274 && !gui.in_use
3275# endif
3276 )
3277 set_mouse_termcode(KS_PTERM_MOUSE,
3278 (char_u *) IF_EB("\033[", ESC_STR "["));
3279 else
3280 del_mouse_termcode(KS_PTERM_MOUSE);
3281# endif
3282}
3283#endif
3284
3285/*
3286 * set screen mode, always fails.
3287 */
3288/* ARGSUSED */
3289 int
3290mch_screenmode(arg)
3291 char_u *arg;
3292{
3293 EMSG(_(e_screenmode));
3294 return FAIL;
3295}
3296
3297#ifndef VMS
3298
3299/*
3300 * Try to get the current window size:
3301 * 1. with an ioctl(), most accurate method
3302 * 2. from the environment variables LINES and COLUMNS
3303 * 3. from the termcap
3304 * 4. keep using the old values
3305 * Return OK when size could be determined, FAIL otherwise.
3306 */
3307 int
3308mch_get_shellsize()
3309{
3310 long rows = 0;
3311 long columns = 0;
3312 char_u *p;
3313
3314 /*
3315 * For OS/2 use _scrsize().
3316 */
3317# ifdef __EMX__
3318 {
3319 int s[2];
3320
3321 _scrsize(s);
3322 columns = s[0];
3323 rows = s[1];
3324 }
3325# endif
3326
3327 /*
3328 * 1. try using an ioctl. It is the most accurate method.
3329 *
3330 * Try using TIOCGWINSZ first, some systems that have it also define
3331 * TIOCGSIZE but don't have a struct ttysize.
3332 */
3333# ifdef TIOCGWINSZ
3334 {
3335 struct winsize ws;
3336 int fd = 1;
3337
3338 /* When stdout is not a tty, use stdin for the ioctl(). */
3339 if (!isatty(fd) && isatty(read_cmd_fd))
3340 fd = read_cmd_fd;
3341 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3342 {
3343 columns = ws.ws_col;
3344 rows = ws.ws_row;
3345 }
3346 }
3347# else /* TIOCGWINSZ */
3348# ifdef TIOCGSIZE
3349 {
3350 struct ttysize ts;
3351 int fd = 1;
3352
3353 /* When stdout is not a tty, use stdin for the ioctl(). */
3354 if (!isatty(fd) && isatty(read_cmd_fd))
3355 fd = read_cmd_fd;
3356 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3357 {
3358 columns = ts.ts_cols;
3359 rows = ts.ts_lines;
3360 }
3361 }
3362# endif /* TIOCGSIZE */
3363# endif /* TIOCGWINSZ */
3364
3365 /*
3366 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003367 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3368 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003369 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003370 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003371 {
3372 if ((p = (char_u *)getenv("LINES")))
3373 rows = atoi((char *)p);
3374 if ((p = (char_u *)getenv("COLUMNS")))
3375 columns = atoi((char *)p);
3376 }
3377
3378#ifdef HAVE_TGETENT
3379 /*
3380 * 3. try reading "co" and "li" entries from termcap
3381 */
3382 if (columns == 0 || rows == 0)
3383 getlinecol(&columns, &rows);
3384#endif
3385
3386 /*
3387 * 4. If everything fails, use the old values
3388 */
3389 if (columns <= 0 || rows <= 0)
3390 return FAIL;
3391
3392 Rows = rows;
3393 Columns = columns;
3394 return OK;
3395}
3396
3397/*
3398 * Try to set the window size to Rows and Columns.
3399 */
3400 void
3401mch_set_shellsize()
3402{
3403 if (*T_CWS)
3404 {
3405 /*
3406 * NOTE: if you get an error here that term_set_winsize() is
3407 * undefined, check the output of configure. It could probably not
3408 * find a ncurses, termcap or termlib library.
3409 */
3410 term_set_winsize((int)Rows, (int)Columns);
3411 out_flush();
3412 screen_start(); /* don't know where cursor is now */
3413 }
3414}
3415
3416#endif /* VMS */
3417
3418/*
3419 * Rows and/or Columns has changed.
3420 */
3421 void
3422mch_new_shellsize()
3423{
3424 /* Nothing to do. */
3425}
3426
Bram Moolenaardf177f62005-02-22 08:39:57 +00003427#ifndef USE_SYSTEM
3428static void append_ga_line __ARGS((garray_T *gap));
3429
3430/*
3431 * Append the text in "gap" below the cursor line and clear "gap".
3432 */
3433 static void
3434append_ga_line(gap)
3435 garray_T *gap;
3436{
3437 /* Remove trailing CR. */
3438 if (gap->ga_len > 0
3439 && !curbuf->b_p_bin
3440 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3441 --gap->ga_len;
3442 ga_append(gap, NUL);
3443 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3444 gap->ga_len = 0;
3445}
3446#endif
3447
Bram Moolenaar071d4272004-06-13 20:20:40 +00003448 int
3449mch_call_shell(cmd, options)
3450 char_u *cmd;
3451 int options; /* SHELL_*, see vim.h */
3452{
3453#ifdef VMS
3454 char *ifn = NULL;
3455 char *ofn = NULL;
3456#endif
3457 int tmode = cur_tmode;
3458#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3459 int x;
3460# ifndef __EMX__
3461 char_u *newcmd; /* only needed for unix */
3462# else
3463 /*
3464 * Set the preferred shell in the EMXSHELL environment variable (but
3465 * only if it is different from what is already in the environment).
3466 * Emx then takes care of whether to use "/c" or "-c" in an
3467 * intelligent way. Simply pass the whole thing to emx's system() call.
3468 * Emx also starts an interactive shell if system() is passed an empty
3469 * string.
3470 */
3471 char_u *p, *old;
3472
3473 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3474 {
3475 /* should check HAVE_SETENV, but I know we don't have it. */
3476 p = alloc(10 + strlen(p_sh));
3477 if (p)
3478 {
3479 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3480 putenv((char *)p); /* don't free the pointer! */
3481 }
3482 }
3483# endif
3484
3485 out_flush();
3486
3487 if (options & SHELL_COOKED)
3488 settmode(TMODE_COOK); /* set to normal mode */
3489
3490# ifdef __EMX__
3491 if (cmd == NULL)
3492 x = system(""); /* this starts an interactive shell in emx */
3493 else
3494 x = system((char *)cmd);
3495 /* system() returns -1 when error occurs in starting shell */
3496 if (x == -1 && !emsg_silent)
3497 {
3498 MSG_PUTS(_("\nCannot execute shell "));
3499 msg_outtrans(p_sh);
3500 msg_putchar('\n');
3501 }
3502# else /* not __EMX__ */
3503 if (cmd == NULL)
3504 x = system((char *)p_sh);
3505 else
3506 {
3507# ifdef VMS
3508 if (ofn = strchr((char *)cmd, '>'))
3509 *ofn++ = '\0';
3510 if (ifn = strchr((char *)cmd, '<'))
3511 {
3512 char *p;
3513
3514 *ifn++ = '\0';
3515 p = strchr(ifn,' '); /* chop off any trailing spaces */
3516 if (p)
3517 *p = '\0';
3518 }
3519 if (ofn)
3520 x = vms_sys((char *)cmd, ofn, ifn);
3521 else
3522 x = system((char *)cmd);
3523# else
3524 newcmd = lalloc(STRLEN(p_sh)
3525 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3526 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3527 if (newcmd == NULL)
3528 x = 0;
3529 else
3530 {
3531 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3532 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3533 (char *)p_shcf,
3534 (char *)cmd);
3535 x = system((char *)newcmd);
3536 vim_free(newcmd);
3537 }
3538# endif
3539 }
3540# ifdef VMS
3541 x = vms_sys_status(x);
3542# endif
3543 if (emsg_silent)
3544 ;
3545 else if (x == 127)
3546 MSG_PUTS(_("\nCannot execute shell sh\n"));
3547# endif /* __EMX__ */
3548 else if (x && !(options & SHELL_SILENT))
3549 {
3550 MSG_PUTS(_("\nshell returned "));
3551 msg_outnum((long)x);
3552 msg_putchar('\n');
3553 }
3554
3555 if (tmode == TMODE_RAW)
3556 settmode(TMODE_RAW); /* set to raw mode */
3557# ifdef FEAT_TITLE
3558 resettitle();
3559# endif
3560 return x;
3561
3562#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3563
Bram Moolenaardf177f62005-02-22 08:39:57 +00003564# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3565 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003566
3567 char_u *newcmd = NULL;
3568 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003569 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003570 pid_t wait_pid = 0;
3571# ifdef HAVE_UNION_WAIT
3572 union wait status;
3573# else
3574 int status = -1;
3575# endif
3576 int retval = -1;
3577 char **argv = NULL;
3578 int argc;
3579 int i;
3580 char_u *p;
3581 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003582 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003583# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584 int pty_slave_fd = -1;
3585 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003586# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003587 int fd_toshell[2]; /* for pipes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003588 int fd_fromshell[2];
3589 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003590# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003591 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003592# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003593 static char envbuf_Rows[20];
3594 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003595# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003596 int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597
3598 out_flush();
3599 if (options & SHELL_COOKED)
3600 settmode(TMODE_COOK); /* set to normal mode */
3601
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602 newcmd = vim_strsave(p_sh);
3603 if (newcmd == NULL) /* out of memory */
3604 goto error;
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003605
3606 /*
3607 * Do this loop twice:
3608 * 1: find number of arguments
3609 * 2: separate them and build argv[]
3610 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003611 for (i = 0; i < 2; ++i)
3612 {
3613 p = newcmd;
3614 inquote = FALSE;
3615 argc = 0;
3616 for (;;)
3617 {
3618 if (i == 1)
3619 argv[argc] = (char *)p;
3620 ++argc;
3621 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3622 {
3623 if (*p == '"')
3624 inquote = !inquote;
3625 ++p;
3626 }
3627 if (*p == NUL)
3628 break;
3629 if (i == 1)
3630 *p++ = NUL;
3631 p = skipwhite(p);
3632 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003633 if (argv == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003634 {
3635 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3636 if (argv == NULL) /* out of memory */
3637 goto error;
3638 }
3639 }
3640 if (cmd != NULL)
3641 {
3642 if (extra_shell_arg != NULL)
3643 argv[argc++] = (char *)extra_shell_arg;
3644 argv[argc++] = (char *)p_shcf;
3645 argv[argc++] = (char *)cmd;
3646 }
3647 argv[argc] = NULL;
3648
Bram Moolenaar071d4272004-06-13 20:20:40 +00003649 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003650 * For the GUI, when writing the output into the buffer and when reading
3651 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3652 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003653 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003654 if ((options & (SHELL_READ|SHELL_WRITE))
3655# ifdef FEAT_GUI
3656 || (gui.in_use && show_shell_mess)
3657# endif
3658 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003659 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003660# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003661 /*
3662 * Try to open a master pty.
3663 * If this works, open the slave pty.
3664 * If the slave can't be opened, close the master pty.
3665 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003666 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667 {
3668 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3669 if (pty_master_fd >= 0 && ((pty_slave_fd =
3670 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3671 {
3672 close(pty_master_fd);
3673 pty_master_fd = -1;
3674 }
3675 }
3676 /*
3677 * If not opening a pty or it didn't work, try using pipes.
3678 */
3679 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003680# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681 {
3682 pipe_error = (pipe(fd_toshell) < 0);
3683 if (!pipe_error) /* pipe create OK */
3684 {
3685 pipe_error = (pipe(fd_fromshell) < 0);
3686 if (pipe_error) /* pipe create failed */
3687 {
3688 close(fd_toshell[0]);
3689 close(fd_toshell[1]);
3690 }
3691 }
3692 if (pipe_error)
3693 {
3694 MSG_PUTS(_("\nCannot create pipes\n"));
3695 out_flush();
3696 }
3697 }
3698 }
3699
3700 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701 {
3702# ifdef __BEOS__
3703 beos_cleanup_read_thread();
3704# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003705
Bram Moolenaar071d4272004-06-13 20:20:40 +00003706 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3707 {
3708 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003709 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003710# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003711 || (gui.in_use && show_shell_mess)
3712# endif
3713 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003714 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003715# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003716 if (pty_master_fd >= 0) /* close the pseudo tty */
3717 {
3718 close(pty_master_fd);
3719 close(pty_slave_fd);
3720 }
3721 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003722# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003723 {
3724 close(fd_toshell[0]);
3725 close(fd_toshell[1]);
3726 close(fd_fromshell[0]);
3727 close(fd_fromshell[1]);
3728 }
3729 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003730 }
3731 else if (pid == 0) /* child */
3732 {
3733 reset_signals(); /* handle signals normally */
3734
3735 if (!show_shell_mess || (options & SHELL_EXPAND))
3736 {
3737 int fd;
3738
3739 /*
3740 * Don't want to show any message from the shell. Can't just
3741 * close stdout and stderr though, because some systems will
3742 * break if you try to write to them after that, so we must
3743 * use dup() to replace them with something else -- webb
3744 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3745 * waiting for input.
3746 */
3747 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3748 fclose(stdin);
3749 fclose(stdout);
3750 fclose(stderr);
3751
3752 /*
3753 * If any of these open()'s and dup()'s fail, we just continue
3754 * anyway. It's not fatal, and on most systems it will make
3755 * no difference at all. On a few it will cause the execvp()
3756 * to exit with a non-zero status even when the completion
3757 * could be done, which is nothing too serious. If the open()
3758 * or dup() failed we'd just do the same thing ourselves
3759 * anyway -- webb
3760 */
3761 if (fd >= 0)
3762 {
3763 dup(fd); /* To replace stdin (file descriptor 0) */
3764 dup(fd); /* To replace stdout (file descriptor 1) */
3765 dup(fd); /* To replace stderr (file descriptor 2) */
3766
3767 /* Don't need this now that we've duplicated it */
3768 close(fd);
3769 }
3770 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003771 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003772# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003773 || gui.in_use
3774# endif
3775 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003776 {
3777
Bram Moolenaardf177f62005-02-22 08:39:57 +00003778# ifdef HAVE_SETSID
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003779 /* Create our own process group, so that the child and all its
3780 * children can be kill()ed. Don't do this when using pipes,
3781 * because stdin is not a tty, we would loose /dev/tty. */
3782 if (p_stmp)
3783 (void)setsid();
Bram Moolenaardf177f62005-02-22 08:39:57 +00003784# endif
3785# ifdef FEAT_GUI
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003786 if (pty_slave_fd >= 0)
3787 {
3788 /* push stream discipline modules */
3789 if (options & SHELL_COOKED)
3790 SetupSlavePTY(pty_slave_fd);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003791# ifdef TIOCSCTTY
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003792 /* Try to become controlling tty (probably doesn't work,
3793 * unless run by root) */
3794 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003795# endif
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003796 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003797# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003799# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003800 setenv("TERM", "dumb", 1);
3801 sprintf((char *)envbuf, "%ld", Rows);
3802 setenv("ROWS", (char *)envbuf, 1);
3803 sprintf((char *)envbuf, "%ld", Rows);
3804 setenv("LINES", (char *)envbuf, 1);
3805 sprintf((char *)envbuf, "%ld", Columns);
3806 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003807# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003808 /*
3809 * Putenv does not copy the string, it has to remain valid.
3810 * Use a static array to avoid loosing allocated memory.
3811 */
3812 putenv("TERM=dumb");
3813 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
3814 putenv(envbuf_Rows);
3815 sprintf(envbuf_Rows, "LINES=%ld", Rows);
3816 putenv(envbuf_Rows);
3817 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
3818 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003819# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003820
Bram Moolenaara5792f52005-11-23 21:25:05 +00003821 /*
3822 * stderr is only redirected when using the GUI, so that a
3823 * program like gpg can still access the terminal to get a
3824 * passphrase using stderr.
3825 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003826# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003827 if (pty_master_fd >= 0)
3828 {
3829 close(pty_master_fd); /* close master side of pty */
3830
3831 /* set up stdin/stdout/stderr for the child */
3832 close(0);
3833 dup(pty_slave_fd);
3834 close(1);
3835 dup(pty_slave_fd);
Bram Moolenaara5792f52005-11-23 21:25:05 +00003836 if (gui.in_use)
3837 {
3838 close(2);
3839 dup(pty_slave_fd);
3840 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003841
3842 close(pty_slave_fd); /* has been dupped, close it now */
3843 }
3844 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003845# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003846 {
3847 /* set up stdin for the child */
3848 close(fd_toshell[1]);
3849 close(0);
3850 dup(fd_toshell[0]);
3851 close(fd_toshell[0]);
3852
3853 /* set up stdout for the child */
3854 close(fd_fromshell[0]);
3855 close(1);
3856 dup(fd_fromshell[1]);
3857 close(fd_fromshell[1]);
3858
Bram Moolenaara5792f52005-11-23 21:25:05 +00003859# ifdef FEAT_GUI
3860 if (gui.in_use)
3861 {
3862 /* set up stderr for the child */
3863 close(2);
3864 dup(1);
3865 }
3866# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003867 }
3868 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003869
Bram Moolenaar071d4272004-06-13 20:20:40 +00003870 /*
3871 * There is no type cast for the argv, because the type may be
3872 * different on different machines. This may cause a warning
3873 * message with strict compilers, don't worry about it.
3874 * Call _exit() instead of exit() to avoid closing the connection
3875 * to the X server (esp. with GTK, which uses atexit()).
3876 */
3877 execvp(argv[0], argv);
3878 _exit(EXEC_FAILED); /* exec failed, return failure code */
3879 }
3880 else /* parent */
3881 {
3882 /*
3883 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003884 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003885 */
3886 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003887 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003888
3889 /*
3890 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003891 * This is also used to pipe stdin/stdout to/from the external
3892 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003893 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003894 if ((options & (SHELL_READ|SHELL_WRITE))
3895# ifdef FEAT_GUI
3896 || (gui.in_use && show_shell_mess)
3897# endif
3898 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003899 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003900# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003902# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003903 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003904# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003905 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
3906 int ta_len = 0; /* valid bytes in ta_buf[] */
3907 int len;
3908 int p_more_save;
3909 int old_State;
3910 int c;
3911 int toshell_fd;
3912 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003913 garray_T ga;
3914 int noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003915
Bram Moolenaardf177f62005-02-22 08:39:57 +00003916# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003917 if (pty_master_fd >= 0)
3918 {
3919 close(pty_slave_fd); /* close slave side of pty */
3920 fromshell_fd = pty_master_fd;
3921 toshell_fd = dup(pty_master_fd);
3922 }
3923 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003924# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003925 {
3926 close(fd_toshell[0]);
3927 close(fd_fromshell[1]);
3928 toshell_fd = fd_toshell[1];
3929 fromshell_fd = fd_fromshell[0];
3930 }
3931
3932 /*
3933 * Write to the child if there are typed characters.
3934 * Read from the child if there are characters available.
3935 * Repeat the reading a few times if more characters are
3936 * available. Need to check for typed keys now and then, but
3937 * not too often (delays when no chars are available).
3938 * This loop is quit if no characters can be read from the pty
3939 * (WaitForChar detected special condition), or there are no
3940 * characters available and the child has exited.
3941 * Only check if the child has exited when there is no more
3942 * output. The child may exit before all the output has
3943 * been printed.
3944 *
3945 * Currently this busy loops!
3946 * This can probably dead-lock when the write blocks!
3947 */
3948 p_more_save = p_more;
3949 p_more = FALSE;
3950 old_State = State;
3951 State = EXTERNCMD; /* don't redraw at window resize */
3952
Bram Moolenaar12033fb2005-12-16 21:49:31 +00003953 if ((options & SHELL_WRITE) && toshell_fd >= 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003954 {
3955 /* Fork a process that will write the lines to the
3956 * external program. */
3957 if ((wpid = fork()) == -1)
3958 {
3959 MSG_PUTS(_("\nCannot fork\n"));
3960 }
3961 else if (wpid == 0)
3962 {
3963 linenr_T lnum = curbuf->b_op_start.lnum;
3964 int written = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00003965 char_u *lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003966 char_u *s;
3967 size_t l;
3968
3969 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00003970 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003971 for (;;)
3972 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00003973 l = STRLEN(lp + written);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003974 if (l == 0)
3975 len = 0;
Bram Moolenaar89d40322006-08-29 15:30:07 +00003976 else if (lp[written] == NL)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003977 /* NL -> NUL translation */
3978 len = write(toshell_fd, "", (size_t)1);
3979 else
3980 {
Bram Moolenaar89d40322006-08-29 15:30:07 +00003981 s = vim_strchr(lp + written, NL);
3982 len = write(toshell_fd, (char *)lp + written,
3983 s == NULL ? l : s - (lp + written));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003984 }
3985 if (len == l)
3986 {
3987 /* Finished a line, add a NL, unless this line
3988 * should not have one. */
3989 if (lnum != curbuf->b_op_end.lnum
3990 || !curbuf->b_p_bin
3991 || (lnum != write_no_eol_lnum
3992 && (lnum !=
3993 curbuf->b_ml.ml_line_count
3994 || curbuf->b_p_eol)))
3995 write(toshell_fd, "\n", (size_t)1);
3996 ++lnum;
3997 if (lnum > curbuf->b_op_end.lnum)
3998 {
3999 /* finished all the lines, close pipe */
4000 close(toshell_fd);
4001 toshell_fd = -1;
4002 break;
4003 }
Bram Moolenaar89d40322006-08-29 15:30:07 +00004004 lp = ml_get(lnum);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004005 written = 0;
4006 }
4007 else if (len > 0)
4008 written += len;
4009 }
4010 _exit(0);
4011 }
4012 else
4013 {
4014 close(toshell_fd);
4015 toshell_fd = -1;
4016 }
4017 }
4018
4019 if (options & SHELL_READ)
4020 ga_init2(&ga, 1, BUFLEN);
4021
4022 noread_cnt = 0;
4023
Bram Moolenaar071d4272004-06-13 20:20:40 +00004024 for (;;)
4025 {
4026 /*
4027 * Check if keys have been typed, write them to the child
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004028 * if there are any.
4029 * Don't do this if we are expanding wild cards (would eat
4030 * typeahead).
4031 * Don't do this when filtering and terminal is in cooked
4032 * mode, the shell command will handle the I/O. Avoids
4033 * that a typed password is echoed for ssh or gpg command.
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004034 * Don't get characters when the child has already
4035 * finished (wait_pid == 0).
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004036 * Don't get extra characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004037 * Don't read characters unless we didn't get output for a
4038 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004039 */
4040 len = 0;
4041 if (!(options & SHELL_EXPAND)
Bram Moolenaar5b962cf2005-12-12 21:58:40 +00004042 && ((options &
4043 (SHELL_READ|SHELL_WRITE|SHELL_COOKED))
4044 != (SHELL_READ|SHELL_WRITE|SHELL_COOKED)
4045#ifdef FEAT_GUI
4046 || gui.in_use
4047#endif
4048 )
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004049 && wait_pid == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00004050 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00004051 || (noread_cnt > 4
4052 && (len = ui_inchar(ta_buf,
4053 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004054 {
4055 /*
4056 * For pipes:
4057 * Check for CTRL-C: send interrupt signal to child.
4058 * Check for CTRL-D: EOF, close pipe to child.
4059 */
4060 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
4061 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004062# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00004063 /*
4064 * Send SIGINT to the child's group or all
4065 * processes in our group.
4066 */
4067 if (ta_buf[ta_len] == Ctrl_C
4068 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004069 {
4070# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00004071 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004072# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004073 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004074# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00004075 if (wpid > 0)
4076 kill(wpid, SIGINT);
4077 }
4078# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004079 if (pty_master_fd < 0 && toshell_fd >= 0
4080 && ta_buf[ta_len] == Ctrl_D)
4081 {
4082 close(toshell_fd);
4083 toshell_fd = -1;
4084 }
4085 }
4086
4087 /* replace K_BS by <BS> and K_DEL by <DEL> */
4088 for (i = ta_len; i < ta_len + len; ++i)
4089 {
4090 if (ta_buf[i] == CSI && len - i > 2)
4091 {
4092 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
4093 if (c == K_DEL || c == K_KDEL || c == K_BS)
4094 {
4095 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
4096 (size_t)(len - i - 2));
4097 if (c == K_DEL || c == K_KDEL)
4098 ta_buf[i] = DEL;
4099 else
4100 ta_buf[i] = Ctrl_H;
4101 len -= 2;
4102 }
4103 }
4104 else if (ta_buf[i] == '\r')
4105 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00004106# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004107 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004108 i += (*mb_ptr2len)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004109# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004110 }
4111
4112 /*
4113 * For pipes: echo the typed characters.
4114 * For a pty this does not seem to work.
4115 */
4116 if (pty_master_fd < 0)
4117 {
4118 for (i = ta_len; i < ta_len + len; ++i)
4119 {
4120 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
4121 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004122# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004123 else if (has_mbyte)
4124 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004125 int l = (*mb_ptr2len)(ta_buf + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126
4127 msg_outtrans_len(ta_buf + i, l);
4128 i += l - 1;
4129 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004130# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004131 else
4132 msg_outtrans_len(ta_buf + i, 1);
4133 }
4134 windgoto(msg_row, msg_col);
4135 out_flush();
4136 }
4137
4138 ta_len += len;
4139
4140 /*
4141 * Write the characters to the child, unless EOF has
4142 * been typed for pipes. Write one character at a
4143 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00004144 * When writing buffer lines, drop the typed
4145 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004146 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004147 if (options & SHELL_WRITE)
4148 ta_len = 0;
4149 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150 {
4151 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4152 if (len > 0)
4153 {
4154 ta_len -= len;
4155 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004156 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004157 }
4158 }
4159 }
4160
Bram Moolenaardf177f62005-02-22 08:39:57 +00004161 if (got_int)
4162 {
4163 /* CTRL-C sends a signal to the child, we ignore it
4164 * ourselves */
4165# ifdef HAVE_SETSID
4166 kill(-pid, SIGINT);
4167# else
4168 kill(0, SIGINT);
4169# endif
4170 if (wpid > 0)
4171 kill(wpid, SIGINT);
4172 got_int = FALSE;
4173 }
4174
Bram Moolenaar071d4272004-06-13 20:20:40 +00004175 /*
4176 * Check if the child has any characters to be printed.
4177 * Read them and write them to our window. Repeat this as
4178 * long as there is something to do, avoid the 10ms wait
4179 * for mch_inchar(), or sending typeahead characters to
4180 * the external process.
4181 * TODO: This should handle escape sequences, compatible
4182 * to some terminal (vt52?).
4183 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004184 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004185 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4186 {
4187 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004188# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004189 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004190# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004191 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004192# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004193 );
4194 if (len <= 0) /* end of file or error */
4195 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004196
4197 noread_cnt = 0;
4198 if (options & SHELL_READ)
4199 {
4200 /* Do NUL -> NL translation, append NL separated
4201 * lines to the current buffer. */
4202 for (i = 0; i < len; ++i)
4203 {
4204 if (buffer[i] == NL)
4205 append_ga_line(&ga);
4206 else if (buffer[i] == NUL)
4207 ga_append(&ga, NL);
4208 else
4209 ga_append(&ga, buffer[i]);
4210 }
4211 }
4212# ifdef FEAT_MBYTE
4213 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004214 {
4215 int l;
4216
Bram Moolenaardf177f62005-02-22 08:39:57 +00004217 len += buffer_off;
4218 buffer[len] = NUL;
4219
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220 /* Check if the last character in buffer[] is
4221 * incomplete, keep these bytes for the next
4222 * round. */
4223 for (p = buffer; p < buffer + len; p += l)
4224 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004225 l = mb_cptr2len(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004226 if (l == 0)
4227 l = 1; /* NUL byte? */
4228 else if (MB_BYTE2LEN(*p) != l)
4229 break;
4230 }
4231 if (p == buffer) /* no complete character */
4232 {
4233 /* avoid getting stuck at an illegal byte */
4234 if (len >= 12)
4235 ++p;
4236 else
4237 {
4238 buffer_off = len;
4239 continue;
4240 }
4241 }
4242 c = *p;
4243 *p = NUL;
4244 msg_puts(buffer);
4245 if (p < buffer + len)
4246 {
4247 *p = c;
4248 buffer_off = (buffer + len) - p;
4249 mch_memmove(buffer, p, buffer_off);
4250 continue;
4251 }
4252 buffer_off = 0;
4253 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004254# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004255 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004256 {
4257 buffer[len] = NUL;
4258 msg_puts(buffer);
4259 }
4260
4261 windgoto(msg_row, msg_col);
4262 cursor_on();
4263 out_flush();
4264 if (got_int)
4265 break;
4266 }
4267
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004268 /* If we already detected the child has finished break the
4269 * loop now. */
4270 if (wait_pid == pid)
4271 break;
4272
Bram Moolenaar071d4272004-06-13 20:20:40 +00004273 /*
4274 * Check if the child still exists, before checking for
4275 * typed characters (otherwise we would loose typeahead).
4276 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004277# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004278 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004279# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004280 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004281# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004282 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4283 || (wait_pid == pid && WIFEXITED(status)))
4284 {
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004285 /* Don't break the loop yet, try reading more
4286 * characters from "fromshell_fd" first. When using
4287 * pipes there might still be something to read and
4288 * then we'll break the loop at the "break" above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004289 wait_pid = pid;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004290 }
Bram Moolenaar12033fb2005-12-16 21:49:31 +00004291 else
4292 wait_pid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004293 }
4294finished:
4295 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004296 if (options & SHELL_READ)
4297 {
4298 if (ga.ga_len > 0)
4299 {
4300 append_ga_line(&ga);
4301 /* remember that the NL was missing */
4302 write_no_eol_lnum = curwin->w_cursor.lnum;
4303 }
4304 else
4305 write_no_eol_lnum = 0;
4306 ga_clear(&ga);
4307 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004308
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309 /*
4310 * Give all typeahead that wasn't used back to ui_inchar().
4311 */
4312 if (ta_len)
4313 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004314 State = old_State;
4315 if (toshell_fd >= 0)
4316 close(toshell_fd);
4317 close(fromshell_fd);
4318 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004319
4320 /*
4321 * Wait until our child has exited.
4322 * Ignore wait() returning pids of other children and returning
4323 * because of some signal like SIGWINCH.
4324 * Don't wait if wait_pid was already set above, indicating the
4325 * child already exited.
4326 */
4327 while (wait_pid != pid)
4328 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004329# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004330 /* Ugly hack: when compiled with Python threads are probably
4331 * used, in which case wait() sometimes hangs for no obvious
4332 * reason. Use waitpid() instead and loop (like the GUI). */
4333# ifdef __NeXT__
4334 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4335# else
4336 wait_pid = waitpid(pid, &status, WNOHANG);
4337# endif
4338 if (wait_pid == 0)
4339 {
4340 /* Wait for 1/100 sec before trying again. */
4341 mch_delay(10L, TRUE);
4342 continue;
4343 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004344# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004345 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004346# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004347 if (wait_pid <= 0
4348# ifdef ECHILD
4349 && errno == ECHILD
4350# endif
4351 )
4352 break;
4353 }
4354
Bram Moolenaardf177f62005-02-22 08:39:57 +00004355 /* Make sure the child that writes to the external program is
4356 * dead. */
4357 if (wpid > 0)
4358 kill(wpid, SIGKILL);
4359
Bram Moolenaar071d4272004-06-13 20:20:40 +00004360 /*
4361 * Set to raw mode right now, otherwise a CTRL-C after
4362 * catch_signals() will kill Vim.
4363 */
4364 if (tmode == TMODE_RAW)
4365 settmode(TMODE_RAW);
4366 did_settmode = TRUE;
4367 set_signals();
4368
4369 if (WIFEXITED(status))
4370 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004371 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004372 retval = WEXITSTATUS(status);
4373 if (retval && !emsg_silent)
4374 {
4375 if (retval == EXEC_FAILED)
4376 {
4377 MSG_PUTS(_("\nCannot execute shell "));
4378 msg_outtrans(p_sh);
4379 msg_putchar('\n');
4380 }
4381 else if (!(options & SHELL_SILENT))
4382 {
4383 MSG_PUTS(_("\nshell returned "));
4384 msg_outnum((long)retval);
4385 msg_putchar('\n');
4386 }
4387 }
4388 }
4389 else
4390 MSG_PUTS(_("\nCommand terminated\n"));
4391 }
4392 }
4393 vim_free(argv);
4394
4395error:
4396 if (!did_settmode)
4397 if (tmode == TMODE_RAW)
4398 settmode(TMODE_RAW); /* set to raw mode */
4399# ifdef FEAT_TITLE
4400 resettitle();
4401# endif
4402 vim_free(newcmd);
4403
4404 return retval;
4405
4406#endif /* USE_SYSTEM */
4407}
4408
4409/*
4410 * Check for CTRL-C typed by reading all available characters.
4411 * In cooked mode we should get SIGINT, no need to check.
4412 */
4413 void
4414mch_breakcheck()
4415{
4416 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4417 fill_input_buf(FALSE);
4418}
4419
4420/*
4421 * Wait "msec" msec until a character is available from the keyboard or from
4422 * inbuf[]. msec == -1 will block forever.
4423 * When a GUI is being used, this will never get called -- webb
4424 */
4425 static int
4426WaitForChar(msec)
4427 long msec;
4428{
4429#ifdef FEAT_MOUSE_GPM
4430 int gpm_process_wanted;
4431#endif
4432#ifdef FEAT_XCLIPBOARD
4433 int rest;
4434#endif
4435 int avail;
4436
4437 if (input_available()) /* something in inbuf[] */
4438 return 1;
4439
4440#if defined(FEAT_MOUSE_DEC)
4441 /* May need to query the mouse position. */
4442 if (WantQueryMouse)
4443 {
Bram Moolenaar6bb68362005-03-22 23:03:44 +00004444 WantQueryMouse = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004445 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4446 }
4447#endif
4448
4449 /*
4450 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4451 * events. This is a bit complicated, because they might both be defined.
4452 */
4453#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4454# ifdef FEAT_XCLIPBOARD
4455 rest = 0;
4456 if (do_xterm_trace())
4457 rest = msec;
4458# endif
4459 do
4460 {
4461# ifdef FEAT_XCLIPBOARD
4462 if (rest != 0)
4463 {
4464 msec = XT_TRACE_DELAY;
4465 if (rest >= 0 && rest < XT_TRACE_DELAY)
4466 msec = rest;
4467 if (rest >= 0)
4468 rest -= msec;
4469 }
4470# endif
4471# ifdef FEAT_MOUSE_GPM
4472 gpm_process_wanted = 0;
4473 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4474# else
4475 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4476# endif
4477 if (!avail)
4478 {
4479 if (input_available())
4480 return 1;
4481# ifdef FEAT_XCLIPBOARD
4482 if (rest == 0 || !do_xterm_trace())
4483# endif
4484 break;
4485 }
4486 }
4487 while (FALSE
4488# ifdef FEAT_MOUSE_GPM
4489 || (gpm_process_wanted && mch_gpm_process() == 0)
4490# endif
4491# ifdef FEAT_XCLIPBOARD
4492 || (!avail && rest != 0)
4493# endif
4494 );
4495
4496#else
4497 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4498#endif
4499 return avail;
4500}
4501
4502/*
4503 * Wait "msec" msec until a character is available from file descriptor "fd".
4504 * Time == -1 will block forever.
4505 * When a GUI is being used, this will not be used for input -- webb
4506 * Returns also, when a request from Sniff is waiting -- toni.
4507 * Or when a Linux GPM mouse event is waiting.
4508 */
4509/* ARGSUSED */
4510#if defined(__BEOS__)
4511 int
4512#else
4513 static int
4514#endif
4515RealWaitForChar(fd, msec, check_for_gpm)
4516 int fd;
4517 long msec;
4518 int *check_for_gpm;
4519{
4520 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004521#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522 static int busy = FALSE;
4523
4524 /* May retry getting characters after an event was handled. */
4525# define MAY_LOOP
4526
4527# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4528 /* Remember at what time we started, so that we know how much longer we
4529 * should wait after being interrupted. */
4530# define USE_START_TV
4531 struct timeval start_tv;
4532
4533 if (msec > 0 && (
4534# ifdef FEAT_XCLIPBOARD
4535 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004536# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004537 ||
4538# endif
4539# endif
4540# ifdef USE_XSMP
4541 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004542# ifdef FEAT_MZSCHEME
4543 ||
4544# endif
4545# endif
4546# ifdef FEAT_MZSCHEME
4547 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004548# endif
4549 ))
4550 gettimeofday(&start_tv, NULL);
4551# endif
4552
4553 /* Handle being called recursively. This may happen for the session
4554 * manager stuff, it may save the file, which does a breakcheck. */
4555 if (busy)
4556 return 0;
4557#endif
4558
4559#ifdef MAY_LOOP
Bram Moolenaar35fdbb52005-07-09 21:08:57 +00004560 for (;;)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004561#endif
4562 {
4563#ifdef MAY_LOOP
4564 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004565# ifdef FEAT_MZSCHEME
4566 int mzquantum_used = FALSE;
4567# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004568#endif
4569#ifndef HAVE_SELECT
4570 struct pollfd fds[5];
4571 int nfd;
4572# ifdef FEAT_XCLIPBOARD
4573 int xterm_idx = -1;
4574# endif
4575# ifdef FEAT_MOUSE_GPM
4576 int gpm_idx = -1;
4577# endif
4578# ifdef USE_XSMP
4579 int xsmp_idx = -1;
4580# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004581 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004582
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004583# ifdef FEAT_MZSCHEME
4584 mzvim_check_threads();
4585 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4586 {
4587 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4588 mzquantum_used = TRUE;
4589 }
4590# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004591 fds[0].fd = fd;
4592 fds[0].events = POLLIN;
4593 nfd = 1;
4594
4595# ifdef FEAT_SNIFF
4596# define SNIFF_IDX 1
4597 if (want_sniff_request)
4598 {
4599 fds[SNIFF_IDX].fd = fd_from_sniff;
4600 fds[SNIFF_IDX].events = POLLIN;
4601 nfd++;
4602 }
4603# endif
4604# ifdef FEAT_XCLIPBOARD
4605 if (xterm_Shell != (Widget)0)
4606 {
4607 xterm_idx = nfd;
4608 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4609 fds[nfd].events = POLLIN;
4610 nfd++;
4611 }
4612# endif
4613# ifdef FEAT_MOUSE_GPM
4614 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4615 {
4616 gpm_idx = nfd;
4617 fds[nfd].fd = gpm_fd;
4618 fds[nfd].events = POLLIN;
4619 nfd++;
4620 }
4621# endif
4622# ifdef USE_XSMP
4623 if (xsmp_icefd != -1)
4624 {
4625 xsmp_idx = nfd;
4626 fds[nfd].fd = xsmp_icefd;
4627 fds[nfd].events = POLLIN;
4628 nfd++;
4629 }
4630# endif
4631
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004632 ret = poll(fds, nfd, towait);
4633# ifdef FEAT_MZSCHEME
4634 if (ret == 0 && mzquantum_used)
4635 /* MzThreads scheduling is required and timeout occured */
4636 finished = FALSE;
4637# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004638
4639# ifdef FEAT_SNIFF
4640 if (ret < 0)
4641 sniff_disconnect(1);
4642 else if (want_sniff_request)
4643 {
4644 if (fds[SNIFF_IDX].revents & POLLHUP)
4645 sniff_disconnect(1);
4646 if (fds[SNIFF_IDX].revents & POLLIN)
4647 sniff_request_waiting = 1;
4648 }
4649# endif
4650# ifdef FEAT_XCLIPBOARD
4651 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4652 {
4653 xterm_update(); /* Maybe we should hand out clipboard */
4654 if (--ret == 0 && !input_available())
4655 /* Try again */
4656 finished = FALSE;
4657 }
4658# endif
4659# ifdef FEAT_MOUSE_GPM
4660 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4661 {
4662 *check_for_gpm = 1;
4663 }
4664# endif
4665# ifdef USE_XSMP
4666 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4667 {
4668 if (fds[xsmp_idx].revents & POLLIN)
4669 {
4670 busy = TRUE;
4671 xsmp_handle_requests();
4672 busy = FALSE;
4673 }
4674 else if (fds[xsmp_idx].revents & POLLHUP)
4675 {
4676 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004677 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004678 xsmp_close();
4679 }
4680 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004681 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004682 }
4683# endif
4684
4685
4686#else /* HAVE_SELECT */
4687
4688 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004689 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004690 fd_set rfds, efds;
4691 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004692 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004693
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004694# ifdef FEAT_MZSCHEME
4695 mzvim_check_threads();
4696 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4697 {
4698 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4699 mzquantum_used = TRUE;
4700 }
4701# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004702# ifdef __EMX__
4703 /* don't check for incoming chars if not in raw mode, because select()
4704 * always returns TRUE then (in some version of emx.dll) */
4705 if (curr_tmode != TMODE_RAW)
4706 return 0;
4707# endif
4708
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004709 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004710 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004711 tv.tv_sec = towait / 1000;
4712 tv.tv_usec = (towait % 1000) * (1000000/1000);
4713 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004715 else
4716 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004717
4718 /*
4719 * Select on ready for reading and exceptional condition (end of file).
4720 */
4721 FD_ZERO(&rfds); /* calls bzero() on a sun */
4722 FD_ZERO(&efds);
4723 FD_SET(fd, &rfds);
4724# if !defined(__QNX__) && !defined(__CYGWIN32__)
4725 /* For QNX select() always returns 1 if this is set. Why? */
4726 FD_SET(fd, &efds);
4727# endif
4728 maxfd = fd;
4729
4730# ifdef FEAT_SNIFF
4731 if (want_sniff_request)
4732 {
4733 FD_SET(fd_from_sniff, &rfds);
4734 FD_SET(fd_from_sniff, &efds);
4735 if (maxfd < fd_from_sniff)
4736 maxfd = fd_from_sniff;
4737 }
4738# endif
4739# ifdef FEAT_XCLIPBOARD
4740 if (xterm_Shell != (Widget)0)
4741 {
4742 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4743 if (maxfd < ConnectionNumber(xterm_dpy))
4744 maxfd = ConnectionNumber(xterm_dpy);
4745 }
4746# endif
4747# ifdef FEAT_MOUSE_GPM
4748 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4749 {
4750 FD_SET(gpm_fd, &rfds);
4751 FD_SET(gpm_fd, &efds);
4752 if (maxfd < gpm_fd)
4753 maxfd = gpm_fd;
4754 }
4755# endif
4756# ifdef USE_XSMP
4757 if (xsmp_icefd != -1)
4758 {
4759 FD_SET(xsmp_icefd, &rfds);
4760 FD_SET(xsmp_icefd, &efds);
4761 if (maxfd < xsmp_icefd)
4762 maxfd = xsmp_icefd;
4763 }
4764# endif
4765
4766# ifdef OLD_VMS
4767 /* Old VMS as v6.2 and older have broken select(). It waits more than
4768 * required. Should not be used */
4769 ret = 0;
4770# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004771 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4772# endif
4773# ifdef FEAT_MZSCHEME
4774 if (ret == 0 && mzquantum_used)
4775 /* loop if MzThreads must be scheduled and timeout occured */
4776 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004777# endif
4778
4779# ifdef FEAT_SNIFF
4780 if (ret < 0 )
4781 sniff_disconnect(1);
4782 else if (ret > 0 && want_sniff_request)
4783 {
4784 if (FD_ISSET(fd_from_sniff, &efds))
4785 sniff_disconnect(1);
4786 if (FD_ISSET(fd_from_sniff, &rfds))
4787 sniff_request_waiting = 1;
4788 }
4789# endif
4790# ifdef FEAT_XCLIPBOARD
4791 if (ret > 0 && xterm_Shell != (Widget)0
4792 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4793 {
4794 xterm_update(); /* Maybe we should hand out clipboard */
4795 /* continue looping when we only got the X event and the input
4796 * buffer is empty */
4797 if (--ret == 0 && !input_available())
4798 {
4799 /* Try again */
4800 finished = FALSE;
4801 }
4802 }
4803# endif
4804# ifdef FEAT_MOUSE_GPM
4805 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4806 {
4807 if (FD_ISSET(gpm_fd, &efds))
4808 gpm_close();
4809 else if (FD_ISSET(gpm_fd, &rfds))
4810 *check_for_gpm = 1;
4811 }
4812# endif
4813# ifdef USE_XSMP
4814 if (ret > 0 && xsmp_icefd != -1)
4815 {
4816 if (FD_ISSET(xsmp_icefd, &efds))
4817 {
4818 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00004819 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004820 xsmp_close();
4821 if (--ret == 0)
4822 finished = FALSE; /* keep going if event was only one */
4823 }
4824 else if (FD_ISSET(xsmp_icefd, &rfds))
4825 {
4826 busy = TRUE;
4827 xsmp_handle_requests();
4828 busy = FALSE;
4829 if (--ret == 0)
4830 finished = FALSE; /* keep going if event was only one */
4831 }
4832 }
4833# endif
4834
4835#endif /* HAVE_SELECT */
4836
4837#ifdef MAY_LOOP
4838 if (finished || msec == 0)
4839 break;
4840
4841 /* We're going to loop around again, find out for how long */
4842 if (msec > 0)
4843 {
4844# ifdef USE_START_TV
4845 struct timeval mtv;
4846
4847 /* Compute remaining wait time. */
4848 gettimeofday(&mtv, NULL);
4849 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
4850 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
4851# else
4852 /* Guess we got interrupted halfway. */
4853 msec = msec / 2;
4854# endif
4855 if (msec <= 0)
4856 break; /* waited long enough */
4857 }
4858#endif
4859 }
4860
4861 return (ret > 0);
4862}
4863
4864#ifndef VMS
4865
4866#ifndef NO_EXPANDPATH
Bram Moolenaar071d4272004-06-13 20:20:40 +00004867/*
Bram Moolenaar02743632005-07-25 20:42:36 +00004868 * Expand a path into all matching files and/or directories. Handles "*",
4869 * "?", "[a-z]", "**", etc.
4870 * "path" has backslashes before chars that are not to be expanded.
4871 * Returns the number of matches found.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004872 */
4873 int
4874mch_expandpath(gap, path, flags)
4875 garray_T *gap;
4876 char_u *path;
4877 int flags; /* EW_* flags */
4878{
Bram Moolenaar02743632005-07-25 20:42:36 +00004879 return unix_expandpath(gap, path, 0, flags, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004880}
4881#endif
4882
4883/*
4884 * mch_expand_wildcards() - this code does wild-card pattern matching using
4885 * the shell
4886 *
4887 * return OK for success, FAIL for error (you may lose some memory) and put
4888 * an error message in *file.
4889 *
4890 * num_pat is number of input patterns
4891 * pat is array of pointers to input patterns
4892 * num_file is pointer to number of matched file names
4893 * file is pointer to array of pointers to matched file names
4894 */
4895
4896#ifndef SEEK_SET
4897# define SEEK_SET 0
4898#endif
4899#ifndef SEEK_END
4900# define SEEK_END 2
4901#endif
4902
Bram Moolenaar5555acc2006-04-07 21:33:12 +00004903#define SHELL_SPECIAL (char_u *)"\t \"&'$;<>()\\|"
Bram Moolenaar316059c2006-01-14 21:18:42 +00004904
Bram Moolenaar071d4272004-06-13 20:20:40 +00004905/* ARGSUSED */
4906 int
4907mch_expand_wildcards(num_pat, pat, num_file, file, flags)
4908 int num_pat;
4909 char_u **pat;
4910 int *num_file;
4911 char_u ***file;
4912 int flags; /* EW_* flags */
4913{
4914 int i;
4915 size_t len;
4916 char_u *p;
4917 int dir;
4918#ifdef __EMX__
4919# define EXPL_ALLOC_INC 16
4920 char_u **expl_files;
4921 size_t files_alloced, files_free;
4922 char_u *buf;
4923 int has_wildcard;
4924
4925 *num_file = 0; /* default: no files found */
4926 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
4927 files_free = EXPL_ALLOC_INC; /* how much space is not used */
4928 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
4929 if (*file == NULL)
4930 return FAIL;
4931
4932 for (; num_pat > 0; num_pat--, pat++)
4933 {
4934 expl_files = NULL;
4935 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
4936 /* expand environment var or home dir */
4937 buf = expand_env_save(*pat);
4938 else
4939 buf = vim_strsave(*pat);
4940 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00004941 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004942 if (has_wildcard) /* yes, so expand them */
4943 expl_files = (char_u **)_fnexplode(buf);
4944
4945 /*
4946 * return value of buf if no wildcards left,
4947 * OR if no match AND EW_NOTFOUND is set.
4948 */
4949 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
4950 || (expl_files == NULL && (flags & EW_NOTFOUND)))
4951 { /* simply save the current contents of *buf */
4952 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
4953 if (expl_files != NULL)
4954 {
4955 expl_files[0] = vim_strsave(buf);
4956 expl_files[1] = NULL;
4957 }
4958 }
4959 vim_free(buf);
4960
4961 /*
4962 * Count number of names resulting from expansion,
4963 * At the same time add a backslash to the end of names that happen to
4964 * be directories, and replace slashes with backslashes.
4965 */
4966 if (expl_files)
4967 {
4968 for (i = 0; (p = expl_files[i]) != NULL; i++)
4969 {
4970 dir = mch_isdir(p);
4971 /* If we don't want dirs and this is one, skip it */
4972 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
4973 continue;
4974
Bram Moolenaara2031822006-03-07 22:29:51 +00004975 /* Skip files that are not executable if we check for that. */
4976 if (!dir && (flags & EW_EXEC) && !mch_can_exe(p))
4977 continue;
4978
Bram Moolenaar071d4272004-06-13 20:20:40 +00004979 if (--files_free == 0)
4980 {
4981 /* need more room in table of pointers */
4982 files_alloced += EXPL_ALLOC_INC;
4983 *file = (char_u **)vim_realloc(*file,
4984 sizeof(char_u **) * files_alloced);
4985 if (*file == NULL)
4986 {
4987 EMSG(_(e_outofmem));
4988 *num_file = 0;
4989 return FAIL;
4990 }
4991 files_free = EXPL_ALLOC_INC;
4992 }
4993 slash_adjust(p);
4994 if (dir)
4995 {
4996 /* For a directory we add a '/', unless it's already
4997 * there. */
4998 len = STRLEN(p);
4999 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5000 {
5001 STRCPY((*file)[*num_file], p);
Bram Moolenaar654b5b52006-06-22 17:47:10 +00005002 if (!after_pathsep((*file)[*num_file],
5003 (*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005004 {
5005 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005006 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005007 }
5008 }
5009 }
5010 else
5011 {
5012 (*file)[*num_file] = vim_strsave(p);
5013 }
5014
5015 /*
5016 * Error message already given by either alloc or vim_strsave.
5017 * Should return FAIL, but returning OK works also.
5018 */
5019 if ((*file)[*num_file] == NULL)
5020 break;
5021 (*num_file)++;
5022 }
5023 _fnexplodefree((char **)expl_files);
5024 }
5025 }
5026 return OK;
5027
5028#else /* __EMX__ */
5029
5030 int j;
5031 char_u *tempname;
5032 char_u *command;
5033 FILE *fd;
5034 char_u *buffer;
5035#define STYLE_ECHO 0 /* use "echo" to expand */
5036#define STYLE_GLOB 1 /* use "glob" to expand, for csh */
5037#define STYLE_PRINT 2 /* use "print -N" to expand, for zsh */
5038#define STYLE_BT 3 /* `cmd` expansion, execute the pattern directly */
5039 int shell_style = STYLE_ECHO;
5040 int check_spaces;
5041 static int did_find_nul = FALSE;
5042 int ampersent = FALSE;
5043
5044 *num_file = 0; /* default: no files found */
5045 *file = NULL;
5046
5047 /*
5048 * If there are no wildcards, just copy the names to allocated memory.
5049 * Saves a lot of time, because we don't have to start a new shell.
5050 */
5051 if (!have_wildcard(num_pat, pat))
5052 return save_patterns(num_pat, pat, num_file, file);
5053
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005054# ifdef HAVE_SANDBOX
5055 /* Don't allow any shell command in the sandbox. */
5056 if (sandbox != 0 && check_secure())
5057 return FAIL;
5058# endif
5059
Bram Moolenaar071d4272004-06-13 20:20:40 +00005060 /*
5061 * Don't allow the use of backticks in secure and restricted mode.
5062 */
Bram Moolenaar0e634da2005-07-20 21:57:28 +00005063 if (secure || restricted)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005064 for (i = 0; i < num_pat; ++i)
5065 if (vim_strchr(pat[i], '`') != NULL
5066 && (check_restricted() || check_secure()))
5067 return FAIL;
5068
5069 /*
5070 * get a name for the temp file
5071 */
5072 if ((tempname = vim_tempname('o')) == NULL)
5073 {
5074 EMSG(_(e_notmp));
5075 return FAIL;
5076 }
5077
5078 /*
5079 * Let the shell expand the patterns and write the result into the temp
5080 * file. if expanding `cmd` execute it directly.
5081 * If we use csh, glob will work better than echo.
5082 * If we use zsh, print -N will work better than glob.
5083 */
5084 if (num_pat == 1 && *pat[0] == '`'
5085 && (len = STRLEN(pat[0])) > 2
5086 && *(pat[0] + len - 1) == '`')
5087 shell_style = STYLE_BT;
5088 else if ((len = STRLEN(p_sh)) >= 3)
5089 {
5090 if (STRCMP(p_sh + len - 3, "csh") == 0)
5091 shell_style = STYLE_GLOB;
5092 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5093 shell_style = STYLE_PRINT;
5094 }
5095
5096 /* "unset nonomatch; print -N >" plus two is 29 */
5097 len = STRLEN(tempname) + 29;
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005098 for (i = 0; i < num_pat; ++i)
5099 {
5100 /* Count the length of the patterns in the same way as they are put in
5101 * "command" below. */
5102#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005103 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005104#else
5105 ++len; /* add space */
Bram Moolenaar316059c2006-01-14 21:18:42 +00005106 for (j = 0; pat[i][j] != NUL; ++j)
5107 {
5108 if (vim_strchr(SHELL_SPECIAL, pat[i][j]) != NULL)
5109 ++len; /* may add a backslash */
5110 ++len;
5111 }
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005112#endif
5113 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005114 command = alloc(len);
5115 if (command == NULL)
5116 {
5117 /* out of memory */
5118 vim_free(tempname);
5119 return FAIL;
5120 }
5121
5122 /*
5123 * Build the shell command:
5124 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5125 * recognizes this).
5126 * - Add the shell command to print the expanded names.
5127 * - Add the temp file name.
5128 * - Add the file name patterns.
5129 */
5130 if (shell_style == STYLE_BT)
5131 {
Bram Moolenaar316059c2006-01-14 21:18:42 +00005132 /* change `command; command& ` to (command; command ) */
5133 STRCPY(command, "(");
5134 STRCAT(command, pat[0] + 1); /* exclude first backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005135 p = command + STRLEN(command) - 1;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005136 *p-- = ')'; /* remove last backtick */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005137 while (p > command && vim_iswhite(*p))
5138 --p;
5139 if (*p == '&') /* remove trailing '&' */
5140 {
5141 ampersent = TRUE;
5142 *p = ' ';
5143 }
5144 STRCAT(command, ">");
5145 }
5146 else
5147 {
5148 if (flags & EW_NOTFOUND)
5149 STRCPY(command, "set nonomatch; ");
5150 else
5151 STRCPY(command, "unset nonomatch; ");
5152 if (shell_style == STYLE_GLOB)
5153 STRCAT(command, "glob >");
5154 else if (shell_style == STYLE_PRINT)
5155 STRCAT(command, "print -N >");
5156 else
5157 STRCAT(command, "echo >");
5158 }
5159 STRCAT(command, tempname);
5160 if (shell_style != STYLE_BT)
5161 for (i = 0; i < num_pat; ++i)
5162 {
5163 /* When using system() always add extra quotes, because the shell
Bram Moolenaar316059c2006-01-14 21:18:42 +00005164 * is started twice. Otherwise put a backslash before special
5165 * characters, except insice ``. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005166#ifdef USE_SYSTEM
5167 STRCAT(command, " \"");
5168 STRCAT(command, pat[i]);
5169 STRCAT(command, "\"");
5170#else
Bram Moolenaar582fd852005-03-28 20:58:01 +00005171 int intick = FALSE;
5172
Bram Moolenaar071d4272004-06-13 20:20:40 +00005173 p = command + STRLEN(command);
5174 *p++ = ' ';
Bram Moolenaar316059c2006-01-14 21:18:42 +00005175 for (j = 0; pat[i][j] != NUL; ++j)
Bram Moolenaar582fd852005-03-28 20:58:01 +00005176 {
5177 if (pat[i][j] == '`')
Bram Moolenaar582fd852005-03-28 20:58:01 +00005178 intick = !intick;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005179 else if (pat[i][j] == '\\' && pat[i][j + 1] != NUL)
5180 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005181 /* Remove a backslash, take char literally. But keep
Bram Moolenaar49315f62006-02-04 00:54:59 +00005182 * backslash inside backticks, before a special character
5183 * and before a backtick. */
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005184 if (intick
Bram Moolenaar49315f62006-02-04 00:54:59 +00005185 || vim_strchr(SHELL_SPECIAL, pat[i][j + 1]) != NULL
5186 || pat[i][j + 1] == '`')
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005187 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005188 ++j;
Bram Moolenaar316059c2006-01-14 21:18:42 +00005189 }
5190 else if (!intick && vim_strchr(SHELL_SPECIAL,
Bram Moolenaar582fd852005-03-28 20:58:01 +00005191 pat[i][j]) != NULL)
Bram Moolenaar316059c2006-01-14 21:18:42 +00005192 /* Put a backslash before a special character, but not
5193 * when inside ``. */
5194 *p++ = '\\';
Bram Moolenaar280f1262006-01-30 00:14:18 +00005195
5196 /* Copy one character. */
5197 *p++ = pat[i][j];
Bram Moolenaar582fd852005-03-28 20:58:01 +00005198 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005199 *p = NUL;
5200#endif
5201 }
5202 if (flags & EW_SILENT)
5203 show_shell_mess = FALSE;
5204 if (ampersent)
5205 STRCAT(command, "&"); /* put the '&' back after the
5206 redirection */
5207
5208 /*
5209 * Using zsh -G: If a pattern has no matches, it is just deleted from
5210 * the argument list, otherwise zsh gives an error message and doesn't
5211 * expand any other pattern.
5212 */
5213 if (shell_style == STYLE_PRINT)
5214 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5215
5216 /*
5217 * If we use -f then shell variables set in .cshrc won't get expanded.
5218 * vi can do it, so we will too, but it is only necessary if there is a "$"
5219 * in one of the patterns, otherwise we can still use the fast option.
5220 */
5221 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5222 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5223
5224 /*
5225 * execute the shell command
5226 */
5227 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5228
5229 /* When running in the background, give it some time to create the temp
5230 * file, but don't wait for it to finish. */
5231 if (ampersent)
5232 mch_delay(10L, TRUE);
5233
5234 extra_shell_arg = NULL; /* cleanup */
5235 show_shell_mess = TRUE;
5236 vim_free(command);
5237
5238 if (i) /* mch_call_shell() failed */
5239 {
5240 mch_remove(tempname);
5241 vim_free(tempname);
5242 /*
5243 * With interactive completion, the error message is not printed.
5244 * However with USE_SYSTEM, I don't know how to turn off error messages
5245 * from the shell, so screen may still get messed up -- webb.
5246 */
5247#ifndef USE_SYSTEM
5248 if (!(flags & EW_SILENT))
5249#endif
5250 {
5251 redraw_later_clear(); /* probably messed up screen */
5252 msg_putchar('\n'); /* clear bottom line quickly */
5253 cmdline_row = Rows - 1; /* continue on last line */
5254#ifdef USE_SYSTEM
5255 if (!(flags & EW_SILENT))
5256#endif
5257 {
5258 MSG(_(e_wildexpand));
5259 msg_start(); /* don't overwrite this message */
5260 }
5261 }
5262 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5263 * EW_NOTFOUND is given */
5264 if (shell_style == STYLE_BT)
5265 return FAIL;
5266 goto notfound;
5267 }
5268
5269 /*
5270 * read the names from the file into memory
5271 */
5272 fd = fopen((char *)tempname, READBIN);
5273 if (fd == NULL)
5274 {
5275 /* Something went wrong, perhaps a file name with a special char. */
5276 if (!(flags & EW_SILENT))
5277 {
5278 MSG(_(e_wildexpand));
5279 msg_start(); /* don't overwrite this message */
5280 }
5281 vim_free(tempname);
5282 goto notfound;
5283 }
5284 fseek(fd, 0L, SEEK_END);
5285 len = ftell(fd); /* get size of temp file */
5286 fseek(fd, 0L, SEEK_SET);
5287 buffer = alloc(len + 1);
5288 if (buffer == NULL)
5289 {
5290 /* out of memory */
5291 mch_remove(tempname);
5292 vim_free(tempname);
5293 fclose(fd);
5294 return FAIL;
5295 }
5296 i = fread((char *)buffer, 1, len, fd);
5297 fclose(fd);
5298 mch_remove(tempname);
5299 if (i != len)
5300 {
5301 /* unexpected read error */
5302 EMSG2(_(e_notread), tempname);
5303 vim_free(tempname);
5304 vim_free(buffer);
5305 return FAIL;
5306 }
5307 vim_free(tempname);
5308
5309#if defined(__CYGWIN__) || defined(__CYGWIN32__)
5310 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5311 p = buffer;
5312 for (i = 0; i < len; ++i)
5313 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5314 *p++ = buffer[i];
5315 len = p - buffer;
5316# endif
5317
5318
5319 /* file names are separated with Space */
5320 if (shell_style == STYLE_ECHO)
5321 {
5322 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5323 p = buffer;
5324 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5325 {
5326 while (*p != ' ' && *p != '\n')
5327 ++p;
5328 p = skipwhite(p); /* skip to next entry */
5329 }
5330 }
5331 /* file names are separated with NL */
5332 else if (shell_style == STYLE_BT)
5333 {
5334 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5335 p = buffer;
5336 for (i = 0; *p != NUL; ++i) /* count number of entries */
5337 {
5338 while (*p != '\n' && *p != NUL)
5339 ++p;
5340 if (*p != NUL)
5341 ++p;
5342 p = skipwhite(p); /* skip leading white space */
5343 }
5344 }
5345 /* file names are separated with NUL */
5346 else
5347 {
5348 /*
5349 * Some versions of zsh use spaces instead of NULs to separate
5350 * results. Only do this when there is no NUL before the end of the
5351 * buffer, otherwise we would never be able to use file names with
5352 * embedded spaces when zsh does use NULs.
5353 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5354 * don't check for spaces again.
5355 */
5356 check_spaces = FALSE;
5357 if (shell_style == STYLE_PRINT && !did_find_nul)
5358 {
5359 /* If there is a NUL, set did_find_nul, else set check_spaces */
5360 if (len && (int)STRLEN(buffer) < len - 1)
5361 did_find_nul = TRUE;
5362 else
5363 check_spaces = TRUE;
5364 }
5365
5366 /*
5367 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5368 * already is one, for STYLE_GLOB it needs to be added.
5369 */
5370 if (len && buffer[len - 1] == NUL)
5371 --len;
5372 else
5373 buffer[len] = NUL;
5374 i = 0;
5375 for (p = buffer; p < buffer + len; ++p)
5376 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5377 {
5378 ++i;
5379 *p = NUL;
5380 }
5381 if (len)
5382 ++i; /* count last entry */
5383 }
5384 if (i == 0)
5385 {
5386 /*
5387 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5388 * /bin/sh will happily expand it to nothing rather than returning an
5389 * error; and hey, it's good to check anyway -- webb.
5390 */
5391 vim_free(buffer);
5392 goto notfound;
5393 }
5394 *num_file = i;
5395 *file = (char_u **)alloc(sizeof(char_u *) * i);
5396 if (*file == NULL)
5397 {
5398 /* out of memory */
5399 vim_free(buffer);
5400 return FAIL;
5401 }
5402
5403 /*
5404 * Isolate the individual file names.
5405 */
5406 p = buffer;
5407 for (i = 0; i < *num_file; ++i)
5408 {
5409 (*file)[i] = p;
5410 /* Space or NL separates */
5411 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT)
5412 {
Bram Moolenaar49315f62006-02-04 00:54:59 +00005413 while (!(shell_style == STYLE_ECHO && *p == ' ')
5414 && *p != '\n' && *p != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005415 ++p;
5416 if (p == buffer + len) /* last entry */
5417 *p = NUL;
5418 else
5419 {
5420 *p++ = NUL;
5421 p = skipwhite(p); /* skip to next entry */
5422 }
5423 }
5424 else /* NUL separates */
5425 {
5426 while (*p && p < buffer + len) /* skip entry */
5427 ++p;
5428 ++p; /* skip NUL */
5429 }
5430 }
5431
5432 /*
5433 * Move the file names to allocated memory.
5434 */
5435 for (j = 0, i = 0; i < *num_file; ++i)
5436 {
5437 /* Require the files to exist. Helps when using /bin/sh */
5438 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5439 continue;
5440
5441 /* check if this entry should be included */
5442 dir = (mch_isdir((*file)[i]));
5443 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5444 continue;
5445
Bram Moolenaara2031822006-03-07 22:29:51 +00005446 /* Skip files that are not executable if we check for that. */
5447 if (!dir && (flags & EW_EXEC) && !mch_can_exe((*file)[i]))
5448 continue;
5449
Bram Moolenaar071d4272004-06-13 20:20:40 +00005450 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5451 if (p)
5452 {
5453 STRCPY(p, (*file)[i]);
5454 if (dir)
5455 STRCAT(p, "/"); /* add '/' to a directory name */
5456 (*file)[j++] = p;
5457 }
5458 }
5459 vim_free(buffer);
5460 *num_file = j;
5461
5462 if (*num_file == 0) /* rejected all entries */
5463 {
5464 vim_free(*file);
5465 *file = NULL;
5466 goto notfound;
5467 }
5468
5469 return OK;
5470
5471notfound:
5472 if (flags & EW_NOTFOUND)
5473 return save_patterns(num_pat, pat, num_file, file);
5474 return FAIL;
5475
5476#endif /* __EMX__ */
5477}
5478
5479#endif /* VMS */
5480
5481#ifndef __EMX__
5482 static int
5483save_patterns(num_pat, pat, num_file, file)
5484 int num_pat;
5485 char_u **pat;
5486 int *num_file;
5487 char_u ***file;
5488{
5489 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005490 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005491
5492 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5493 if (*file == NULL)
5494 return FAIL;
5495 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005496 {
5497 s = vim_strsave(pat[i]);
5498 if (s != NULL)
5499 /* Be compatible with expand_filename(): halve the number of
5500 * backslashes. */
5501 backslash_halve(s);
5502 (*file)[i] = s;
5503 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005504 *num_file = num_pat;
5505 return OK;
5506}
5507#endif
5508
5509
5510/*
5511 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5512 * expand.
5513 */
5514 int
5515mch_has_exp_wildcard(p)
5516 char_u *p;
5517{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005518 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005519 {
5520#ifndef OS2
5521 if (*p == '\\' && p[1] != NUL)
5522 ++p;
5523 else
5524#endif
5525 if (vim_strchr((char_u *)
5526#ifdef VMS
5527 "*?%"
5528#else
5529# ifdef OS2
5530 "*?"
5531# else
5532 "*?[{'"
5533# endif
5534#endif
5535 , *p) != NULL)
5536 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005537 }
5538 return FALSE;
5539}
5540
5541/*
5542 * Return TRUE if the string "p" contains a wildcard.
5543 * Don't recognize '~' at the end as a wildcard.
5544 */
5545 int
5546mch_has_wildcard(p)
5547 char_u *p;
5548{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005549 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005550 {
5551#ifndef OS2
5552 if (*p == '\\' && p[1] != NUL)
5553 ++p;
5554 else
5555#endif
5556 if (vim_strchr((char_u *)
5557#ifdef VMS
5558 "*?%$"
5559#else
5560# ifdef OS2
5561# ifdef VIM_BACKTICK
5562 "*?$`"
5563# else
5564 "*?$"
5565# endif
5566# else
5567 "*?[{`'$"
5568# endif
5569#endif
5570 , *p) != NULL
5571 || (*p == '~' && p[1] != NUL))
5572 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005573 }
5574 return FALSE;
5575}
5576
5577#ifndef __EMX__
5578 static int
5579have_wildcard(num, file)
5580 int num;
5581 char_u **file;
5582{
5583 int i;
5584
5585 for (i = 0; i < num; i++)
5586 if (mch_has_wildcard(file[i]))
5587 return 1;
5588 return 0;
5589}
5590
5591 static int
5592have_dollars(num, file)
5593 int num;
5594 char_u **file;
5595{
5596 int i;
5597
5598 for (i = 0; i < num; i++)
5599 if (vim_strchr(file[i], '$') != NULL)
5600 return TRUE;
5601 return FALSE;
5602}
5603#endif /* ifndef __EMX__ */
5604
5605#ifndef HAVE_RENAME
5606/*
5607 * Scaled-down version of rename(), which is missing in Xenix.
5608 * This version can only move regular files and will fail if the
5609 * destination exists.
5610 */
5611 int
5612mch_rename(src, dest)
5613 const char *src, *dest;
5614{
5615 struct stat st;
5616
5617 if (stat(dest, &st) >= 0) /* fail if destination exists */
5618 return -1;
5619 if (link(src, dest) != 0) /* link file to new name */
5620 return -1;
5621 if (mch_remove(src) == 0) /* delete link to old name */
5622 return 0;
5623 return -1;
5624}
5625#endif /* !HAVE_RENAME */
5626
5627#ifdef FEAT_MOUSE_GPM
5628/*
5629 * Initializes connection with gpm (if it isn't already opened)
5630 * Return 1 if succeeded (or connection already opened), 0 if failed
5631 */
5632 static int
5633gpm_open()
5634{
5635 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5636
5637 if (!gpm_flag)
5638 {
5639 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5640 gpm_connect.defaultMask = ~GPM_HARD;
5641 /* Default handling for mouse move*/
5642 gpm_connect.minMod = 0; /* Handle any modifier keys */
5643 gpm_connect.maxMod = 0xffff;
5644 if (Gpm_Open(&gpm_connect, 0) > 0)
5645 {
5646 /* gpm library tries to handling TSTP causes
5647 * problems. Anyways, we close connection to Gpm whenever
5648 * we are going to suspend or starting an external process
5649 * so we should'nt have problem with this
5650 */
5651 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5652 return 1; /* succeed */
5653 }
5654 if (gpm_fd == -2)
5655 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5656 return 0;
5657 }
5658 return 1; /* already open */
5659}
5660
5661/*
5662 * Closes connection to gpm
5663 * returns non-zero if connection succesfully closed
5664 */
5665 static void
5666gpm_close()
5667{
5668 if (gpm_flag && gpm_fd >= 0) /* if Open */
5669 Gpm_Close();
5670}
5671
5672/* Reads gpm event and adds special keys to input buf. Returns length of
5673 * generated key sequence.
5674 * This function is made after gui_send_mouse_event
5675 */
5676 static int
5677mch_gpm_process()
5678{
5679 int button;
5680 static Gpm_Event gpm_event;
5681 char_u string[6];
5682 int_u vim_modifiers;
5683 int row,col;
5684 unsigned char buttons_mask;
5685 unsigned char gpm_modifiers;
5686 static unsigned char old_buttons = 0;
5687
5688 Gpm_GetEvent(&gpm_event);
5689
5690#ifdef FEAT_GUI
5691 /* Don't put events in the input queue now. */
5692 if (hold_gui_events)
5693 return 0;
5694#endif
5695
5696 row = gpm_event.y - 1;
5697 col = gpm_event.x - 1;
5698
5699 string[0] = ESC; /* Our termcode */
5700 string[1] = 'M';
5701 string[2] = 'G';
5702 switch (GPM_BARE_EVENTS(gpm_event.type))
5703 {
5704 case GPM_DRAG:
5705 string[3] = MOUSE_DRAG;
5706 break;
5707 case GPM_DOWN:
5708 buttons_mask = gpm_event.buttons & ~old_buttons;
5709 old_buttons = gpm_event.buttons;
5710 switch (buttons_mask)
5711 {
5712 case GPM_B_LEFT:
5713 button = MOUSE_LEFT;
5714 break;
5715 case GPM_B_MIDDLE:
5716 button = MOUSE_MIDDLE;
5717 break;
5718 case GPM_B_RIGHT:
5719 button = MOUSE_RIGHT;
5720 break;
5721 default:
5722 return 0;
5723 /*Don't know what to do. Can more than one button be
5724 * reported in one event? */
5725 }
5726 string[3] = (char_u)(button | 0x20);
5727 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5728 break;
5729 case GPM_UP:
5730 string[3] = MOUSE_RELEASE;
5731 old_buttons &= ~gpm_event.buttons;
5732 break;
5733 default:
5734 return 0;
5735 }
5736 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5737 gpm_modifiers = gpm_event.modifiers;
5738 vim_modifiers = 0x0;
5739 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5740 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5741 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5742 */
5743 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5744 vim_modifiers |= MOUSE_SHIFT;
5745
5746 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5747 vim_modifiers |= MOUSE_CTRL;
5748 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5749 vim_modifiers |= MOUSE_ALT;
5750 string[3] |= vim_modifiers;
5751 string[4] = (char_u)(col + ' ' + 1);
5752 string[5] = (char_u)(row + ' ' + 1);
5753 add_to_input_buf(string, 6);
5754 return 6;
5755}
5756#endif /* FEAT_MOUSE_GPM */
5757
5758#if defined(FEAT_LIBCALL) || defined(PROTO)
5759typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
5760typedef char_u * (*INTPROCSTR)__ARGS((int));
5761typedef int (*STRPROCINT)__ARGS((char_u *));
5762typedef int (*INTPROCINT)__ARGS((int));
5763
5764/*
5765 * Call a DLL routine which takes either a string or int param
5766 * and returns an allocated string.
5767 */
5768 int
5769mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
5770 char_u *libname;
5771 char_u *funcname;
5772 char_u *argstring; /* NULL when using a argint */
5773 int argint;
5774 char_u **string_result;/* NULL when using number_result */
5775 int *number_result;
5776{
5777# if defined(USE_DLOPEN)
5778 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005779 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005780# else
5781 shl_t hinstLib;
5782# endif
5783 STRPROCSTR ProcAdd;
5784 INTPROCSTR ProcAddI;
5785 char_u *retval_str = NULL;
5786 int retval_int = 0;
5787 int success = FALSE;
5788
Bram Moolenaarb39ef122006-06-22 16:19:31 +00005789 /*
5790 * Get a handle to the DLL module.
5791 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005792# if defined(USE_DLOPEN)
Bram Moolenaarb39ef122006-06-22 16:19:31 +00005793 /* First clear any error, it's not cleared by the dlopen() call. */
5794 (void)dlerror();
5795
Bram Moolenaar071d4272004-06-13 20:20:40 +00005796 hinstLib = dlopen((char *)libname, RTLD_LAZY
5797# ifdef RTLD_LOCAL
5798 | RTLD_LOCAL
5799# endif
5800 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005801 if (hinstLib == NULL)
5802 {
5803 /* "dlerr" must be used before dlclose() */
5804 dlerr = (char *)dlerror();
5805 if (dlerr != NULL)
5806 EMSG2(_("dlerror = \"%s\""), dlerr);
5807 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005808# else
5809 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
5810# endif
5811
5812 /* If the handle is valid, try to get the function address. */
5813 if (hinstLib != NULL)
5814 {
5815# ifdef HAVE_SETJMP_H
5816 /*
5817 * Catch a crash when calling the library function. For example when
5818 * using a number where a string pointer is expected.
5819 */
5820 mch_startjmp();
5821 if (SETJMP(lc_jump_env) != 0)
5822 {
5823 success = FALSE;
Bram Moolenaard68071d2006-05-02 22:08:30 +00005824# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005825 dlerr = NULL;
Bram Moolenaard68071d2006-05-02 22:08:30 +00005826# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005827 mch_didjmp();
5828 }
5829 else
5830# endif
5831 {
5832 retval_str = NULL;
5833 retval_int = 0;
5834
5835 if (argstring != NULL)
5836 {
5837# if defined(USE_DLOPEN)
5838 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005839 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005840# else
5841 if (shl_findsym(&hinstLib, (const char *)funcname,
5842 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
5843 ProcAdd = NULL;
5844# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005845 if ((success = (ProcAdd != NULL
5846# if defined(USE_DLOPEN)
5847 && dlerr == NULL
5848# endif
5849 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005850 {
5851 if (string_result == NULL)
5852 retval_int = ((STRPROCINT)ProcAdd)(argstring);
5853 else
5854 retval_str = (ProcAdd)(argstring);
5855 }
5856 }
5857 else
5858 {
5859# if defined(USE_DLOPEN)
5860 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005861 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005862# else
5863 if (shl_findsym(&hinstLib, (const char *)funcname,
5864 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
5865 ProcAddI = NULL;
5866# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005867 if ((success = (ProcAddI != NULL
5868# if defined(USE_DLOPEN)
5869 && dlerr == NULL
5870# endif
5871 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005872 {
5873 if (string_result == NULL)
5874 retval_int = ((INTPROCINT)ProcAddI)(argint);
5875 else
5876 retval_str = (ProcAddI)(argint);
5877 }
5878 }
5879
5880 /* Save the string before we free the library. */
5881 /* Assume that a "1" or "-1" result is an illegal pointer. */
5882 if (string_result == NULL)
5883 *number_result = retval_int;
5884 else if (retval_str != NULL
5885 && retval_str != (char_u *)1
5886 && retval_str != (char_u *)-1)
5887 *string_result = vim_strsave(retval_str);
5888 }
5889
5890# ifdef HAVE_SETJMP_H
5891 mch_endjmp();
5892# ifdef SIGHASARG
5893 if (lc_signal != 0)
5894 {
5895 int i;
5896
5897 /* try to find the name of this signal */
5898 for (i = 0; signal_info[i].sig != -1; i++)
5899 if (lc_signal == signal_info[i].sig)
5900 break;
5901 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
5902 }
5903# endif
5904# endif
5905
Bram Moolenaar071d4272004-06-13 20:20:40 +00005906# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005907 /* "dlerr" must be used before dlclose() */
5908 if (dlerr != NULL)
5909 EMSG2(_("dlerror = \"%s\""), dlerr);
5910
5911 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005912 (void)dlclose(hinstLib);
5913# else
5914 (void)shl_unload(hinstLib);
5915# endif
5916 }
5917
5918 if (!success)
5919 {
5920 EMSG2(_(e_libcall), funcname);
5921 return FAIL;
5922 }
5923
5924 return OK;
5925}
5926#endif
5927
5928#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
5929static int xterm_trace = -1; /* default: disabled */
5930static int xterm_button;
5931
5932/*
5933 * Setup a dummy window for X selections in a terminal.
5934 */
5935 void
5936setup_term_clip()
5937{
5938 int z = 0;
5939 char *strp = "";
5940 Widget AppShell;
5941
5942 if (!x_connect_to_server())
5943 return;
5944
5945 open_app_context();
5946 if (app_context != NULL && xterm_Shell == (Widget)0)
5947 {
5948 int (*oldhandler)();
5949#if defined(HAVE_SETJMP_H)
5950 int (*oldIOhandler)();
5951#endif
5952# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5953 struct timeval start_tv;
5954
5955 if (p_verbose > 0)
5956 gettimeofday(&start_tv, NULL);
5957# endif
5958
5959 /* Ignore X errors while opening the display */
5960 oldhandler = XSetErrorHandler(x_error_check);
5961
5962#if defined(HAVE_SETJMP_H)
5963 /* Ignore X IO errors while opening the display */
5964 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
5965 mch_startjmp();
5966 if (SETJMP(lc_jump_env) != 0)
5967 {
5968 mch_didjmp();
5969 xterm_dpy = NULL;
5970 }
5971 else
5972#endif
5973 {
5974 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
5975 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
5976#if defined(HAVE_SETJMP_H)
5977 mch_endjmp();
5978#endif
5979 }
5980
5981#if defined(HAVE_SETJMP_H)
5982 /* Now handle X IO errors normally. */
5983 (void)XSetIOErrorHandler(oldIOhandler);
5984#endif
5985 /* Now handle X errors normally. */
5986 (void)XSetErrorHandler(oldhandler);
5987
5988 if (xterm_dpy == NULL)
5989 {
5990 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00005991 verb_msg((char_u *)_("Opening the X display failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00005992 return;
5993 }
5994
5995 /* Catch terminating error of the X server connection. */
5996 (void)XSetIOErrorHandler(x_IOerror_handler);
5997
5998# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5999 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006000 {
6001 verbose_enter();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006002 xopen_message(&start_tv);
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006003 verbose_leave();
6004 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006005# endif
6006
6007 /* Create a Shell to make converters work. */
6008 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
6009 applicationShellWidgetClass, xterm_dpy,
6010 NULL);
6011 if (AppShell == (Widget)0)
6012 return;
6013 xterm_Shell = XtVaCreatePopupShell("VIM",
6014 topLevelShellWidgetClass, AppShell,
6015 XtNmappedWhenManaged, 0,
6016 XtNwidth, 1,
6017 XtNheight, 1,
6018 NULL);
6019 if (xterm_Shell == (Widget)0)
6020 return;
6021
6022 x11_setup_atoms(xterm_dpy);
6023 if (x11_display == NULL)
6024 x11_display = xterm_dpy;
6025
6026 XtRealizeWidget(xterm_Shell);
6027 XSync(xterm_dpy, False);
6028 xterm_update();
6029 }
6030 if (xterm_Shell != (Widget)0)
6031 {
6032 clip_init(TRUE);
6033 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6034 x11_window = (Window)atol(strp);
6035 /* Check if $WINDOWID is valid. */
6036 if (test_x11_window(xterm_dpy) == FAIL)
6037 x11_window = 0;
6038 if (x11_window != 0)
6039 xterm_trace = 0;
6040 }
6041}
6042
6043 void
6044start_xterm_trace(button)
6045 int button;
6046{
6047 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6048 return;
6049 xterm_trace = 1;
6050 xterm_button = button;
6051 do_xterm_trace();
6052}
6053
6054
6055 void
6056stop_xterm_trace()
6057{
6058 if (xterm_trace < 0)
6059 return;
6060 xterm_trace = 0;
6061}
6062
6063/*
6064 * Query the xterm pointer and generate mouse termcodes if necessary
6065 * return TRUE if dragging is active, else FALSE
6066 */
6067 static int
6068do_xterm_trace()
6069{
6070 Window root, child;
6071 int root_x, root_y;
6072 int win_x, win_y;
6073 int row, col;
6074 int_u mask_return;
6075 char_u buf[50];
6076 char_u *strp;
6077 long got_hints;
6078 static char_u *mouse_code;
6079 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6080 static int prev_row = 0, prev_col = 0;
6081 static XSizeHints xterm_hints;
6082
6083 if (xterm_trace <= 0)
6084 return FALSE;
6085
6086 if (xterm_trace == 1)
6087 {
6088 /* Get the hints just before tracking starts. The font size might
6089 * have changed recently */
6090 XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints);
6091 if (!(got_hints & PResizeInc)
6092 || xterm_hints.width_inc <= 1
6093 || xterm_hints.height_inc <= 1)
6094 {
6095 xterm_trace = -1; /* Not enough data -- disable tracing */
6096 return FALSE;
6097 }
6098
6099 /* Rely on the same mouse code for the duration of this */
6100 mouse_code = find_termcode(mouse_name);
6101 prev_row = mouse_row;
6102 prev_row = mouse_col;
6103 xterm_trace = 2;
6104
6105 /* Find the offset of the chars, there might be a scrollbar on the
6106 * left of the window and/or a menu on the top (eterm etc.) */
6107 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6108 &win_x, &win_y, &mask_return);
6109 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6110 - (xterm_hints.height_inc / 2);
6111 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6112 xterm_hints.y = 2;
6113 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6114 - (xterm_hints.width_inc / 2);
6115 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6116 xterm_hints.x = 2;
6117 return TRUE;
6118 }
6119 if (mouse_code == NULL)
6120 {
6121 xterm_trace = 0;
6122 return FALSE;
6123 }
6124
6125 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6126 &win_x, &win_y, &mask_return);
6127
6128 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6129 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6130 if (row == prev_row && col == prev_col)
6131 return TRUE;
6132
6133 STRCPY(buf, mouse_code);
6134 strp = buf + STRLEN(buf);
6135 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6136 *strp++ = (char_u)(col + ' ' + 1);
6137 *strp++ = (char_u)(row + ' ' + 1);
6138 *strp = 0;
6139 add_to_input_buf(buf, STRLEN(buf));
6140
6141 prev_row = row;
6142 prev_col = col;
6143 return TRUE;
6144}
6145
6146# if defined(FEAT_GUI) || defined(PROTO)
6147/*
6148 * Destroy the display, window and app_context. Required for GTK.
6149 */
6150 void
6151clear_xterm_clip()
6152{
6153 if (xterm_Shell != (Widget)0)
6154 {
6155 XtDestroyWidget(xterm_Shell);
6156 xterm_Shell = (Widget)0;
6157 }
6158 if (xterm_dpy != NULL)
6159 {
6160#if 0
6161 /* Lesstif and Solaris crash here, lose some memory */
6162 XtCloseDisplay(xterm_dpy);
6163#endif
6164 if (x11_display == xterm_dpy)
6165 x11_display = NULL;
6166 xterm_dpy = NULL;
6167 }
6168#if 0
6169 if (app_context != (XtAppContext)NULL)
6170 {
6171 /* Lesstif and Solaris crash here, lose some memory */
6172 XtDestroyApplicationContext(app_context);
6173 app_context = (XtAppContext)NULL;
6174 }
6175#endif
6176}
6177# endif
6178
6179/*
6180 * Catch up with any queued X events. This may put keyboard input into the
6181 * input buffer, call resize call-backs, trigger timers etc. If there is
6182 * nothing in the X event queue (& no timers pending), then we return
6183 * immediately.
6184 */
6185 static void
6186xterm_update()
6187{
6188 XEvent event;
6189
6190 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6191 {
6192 XtAppNextEvent(app_context, &event);
6193#ifdef FEAT_CLIENTSERVER
6194 {
6195 XPropertyEvent *e = (XPropertyEvent *)&event;
6196
6197 if (e->type == PropertyNotify && e->window == commWindow
6198 && e->atom == commProperty && e->state == PropertyNewValue)
6199 serverEventProc(xterm_dpy, &event);
6200 }
6201#endif
6202 XtDispatchEvent(&event);
6203 }
6204}
6205
6206 int
6207clip_xterm_own_selection(cbd)
6208 VimClipboard *cbd;
6209{
6210 if (xterm_Shell != (Widget)0)
6211 return clip_x11_own_selection(xterm_Shell, cbd);
6212 return FAIL;
6213}
6214
6215 void
6216clip_xterm_lose_selection(cbd)
6217 VimClipboard *cbd;
6218{
6219 if (xterm_Shell != (Widget)0)
6220 clip_x11_lose_selection(xterm_Shell, cbd);
6221}
6222
6223 void
6224clip_xterm_request_selection(cbd)
6225 VimClipboard *cbd;
6226{
6227 if (xterm_Shell != (Widget)0)
6228 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6229}
6230
6231 void
6232clip_xterm_set_selection(cbd)
6233 VimClipboard *cbd;
6234{
6235 clip_x11_set_selection(cbd);
6236}
6237#endif
6238
6239
6240#if defined(USE_XSMP) || defined(PROTO)
6241/*
6242 * Code for X Session Management Protocol.
6243 */
6244static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6245static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6246static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6247static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6248static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6249
6250
6251# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6252static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6253
6254/*
6255 * This is our chance to ask the user if they want to save,
6256 * or abort the logout
6257 */
6258/*ARGSUSED*/
6259 static void
6260xsmp_handle_interaction(smc_conn, client_data)
6261 SmcConn smc_conn;
6262 SmPointer client_data;
6263{
6264 cmdmod_T save_cmdmod;
6265 int cancel_shutdown = False;
6266
6267 save_cmdmod = cmdmod;
6268 cmdmod.confirm = TRUE;
6269 if (check_changed_any(FALSE))
6270 /* Mustn't logout */
6271 cancel_shutdown = True;
6272 cmdmod = save_cmdmod;
6273 setcursor(); /* position cursor */
6274 out_flush();
6275
6276 /* Done interaction */
6277 SmcInteractDone(smc_conn, cancel_shutdown);
6278
6279 /* Finish off
6280 * Only end save-yourself here if we're not cancelling shutdown;
6281 * we'll get a cancelled callback later in which we'll end it.
6282 * Hopefully get around glitchy SMs (like GNOME-1)
6283 */
6284 if (!cancel_shutdown)
6285 {
6286 xsmp.save_yourself = False;
6287 SmcSaveYourselfDone(smc_conn, True);
6288 }
6289}
6290# endif
6291
6292/*
6293 * Callback that starts save-yourself.
6294 */
6295/*ARGSUSED*/
6296 static void
6297xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6298 shutdown, interact_style, fast)
6299 SmcConn smc_conn;
6300 SmPointer client_data;
6301 int save_type;
6302 Bool shutdown;
6303 int interact_style;
6304 Bool fast;
6305{
6306 /* Handle already being in saveyourself */
6307 if (xsmp.save_yourself)
6308 SmcSaveYourselfDone(smc_conn, True);
6309 xsmp.save_yourself = True;
6310 xsmp.shutdown = shutdown;
6311
6312 /* First up, preserve all files */
6313 out_flush();
6314 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6315
6316 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006317 verb_msg((char_u *)_("XSMP handling save-yourself request"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006318
6319# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6320 /* Now see if we can ask about unsaved files */
6321 if (shutdown && !fast && gui.in_use)
6322 /* Need to interact with user, but need SM's permission */
6323 SmcInteractRequest(smc_conn, SmDialogError,
6324 xsmp_handle_interaction, client_data);
6325 else
6326# endif
6327 {
6328 /* Can stop the cycle here */
6329 SmcSaveYourselfDone(smc_conn, True);
6330 xsmp.save_yourself = False;
6331 }
6332}
6333
6334
6335/*
6336 * Callback to warn us of imminent death.
6337 */
6338/*ARGSUSED*/
6339 static void
6340xsmp_die(smc_conn, client_data)
6341 SmcConn smc_conn;
6342 SmPointer client_data;
6343{
6344 xsmp_close();
6345
6346 /* quit quickly leaving swapfiles for modified buffers behind */
6347 getout_preserve_modified(0);
6348}
6349
6350
6351/*
6352 * Callback to tell us that save-yourself has completed.
6353 */
6354/*ARGSUSED*/
6355 static void
6356xsmp_save_complete(smc_conn, client_data)
6357 SmcConn smc_conn;
6358 SmPointer client_data;
6359{
6360 xsmp.save_yourself = False;
6361}
6362
6363
6364/*
6365 * Callback to tell us that an instigated shutdown was cancelled
6366 * (maybe even by us)
6367 */
6368/*ARGSUSED*/
6369 static void
6370xsmp_shutdown_cancelled(smc_conn, client_data)
6371 SmcConn smc_conn;
6372 SmPointer client_data;
6373{
6374 if (xsmp.save_yourself)
6375 SmcSaveYourselfDone(smc_conn, True);
6376 xsmp.save_yourself = False;
6377 xsmp.shutdown = False;
6378}
6379
6380
6381/*
6382 * Callback to tell us that a new ICE connection has been established.
6383 */
6384/*ARGSUSED*/
6385 static void
6386xsmp_ice_connection(iceConn, clientData, opening, watchData)
6387 IceConn iceConn;
6388 IcePointer clientData;
6389 Bool opening;
6390 IcePointer *watchData;
6391{
6392 /* Intercept creation of ICE connection fd */
6393 if (opening)
6394 {
6395 xsmp_icefd = IceConnectionNumber(iceConn);
6396 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6397 }
6398}
6399
6400
6401/* Handle any ICE processing that's required; return FAIL if SM lost */
6402 int
6403xsmp_handle_requests()
6404{
6405 Bool rep;
6406
6407 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6408 == IceProcessMessagesIOError)
6409 {
6410 /* Lost ICE */
6411 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006412 verb_msg((char_u *)_("XSMP lost ICE connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006413 xsmp_close();
6414 return FAIL;
6415 }
6416 else
6417 return OK;
6418}
6419
6420static int dummy;
6421
6422/* Set up X Session Management Protocol */
6423 void
6424xsmp_init(void)
6425{
6426 char errorstring[80];
6427 char *clientid;
6428 SmcCallbacks smcallbacks;
6429#if 0
6430 SmPropValue smname;
6431 SmProp smnameprop;
6432 SmProp *smprops[1];
6433#endif
6434
6435 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006436 verb_msg((char_u *)_("XSMP opening connection"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006437
6438 xsmp.save_yourself = xsmp.shutdown = False;
6439
6440 /* Set up SM callbacks - must have all, even if they're not used */
6441 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6442 smcallbacks.save_yourself.client_data = NULL;
6443 smcallbacks.die.callback = xsmp_die;
6444 smcallbacks.die.client_data = NULL;
6445 smcallbacks.save_complete.callback = xsmp_save_complete;
6446 smcallbacks.save_complete.client_data = NULL;
6447 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6448 smcallbacks.shutdown_cancelled.client_data = NULL;
6449
6450 /* Set up a watch on ICE connection creations. The "dummy" argument is
6451 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6452 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6453 {
6454 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006455 verb_msg((char_u *)_("XSMP ICE connection watch failed"));
Bram Moolenaar071d4272004-06-13 20:20:40 +00006456 return;
6457 }
6458
6459 /* Create an SM connection */
6460 xsmp.smcconn = SmcOpenConnection(
6461 NULL,
6462 NULL,
6463 SmProtoMajor,
6464 SmProtoMinor,
6465 SmcSaveYourselfProcMask | SmcDieProcMask
6466 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6467 &smcallbacks,
6468 NULL,
6469 &clientid,
6470 sizeof(errorstring),
6471 errorstring);
6472 if (xsmp.smcconn == NULL)
6473 {
6474 char errorreport[132];
Bram Moolenaar051b7822005-05-19 21:00:46 +00006475
Bram Moolenaar071d4272004-06-13 20:20:40 +00006476 if (p_verbose > 0)
Bram Moolenaara04f10b2005-05-31 22:09:46 +00006477 {
6478 vim_snprintf(errorreport, sizeof(errorreport),
6479 _("XSMP SmcOpenConnection failed: %s"), errorstring);
6480 verb_msg((char_u *)errorreport);
6481 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006482 return;
6483 }
6484 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6485
6486#if 0
6487 /* ID ourselves */
6488 smname.value = "vim";
6489 smname.length = 3;
6490 smnameprop.name = "SmProgram";
6491 smnameprop.type = "SmARRAY8";
6492 smnameprop.num_vals = 1;
6493 smnameprop.vals = &smname;
6494
6495 smprops[0] = &smnameprop;
6496 SmcSetProperties(xsmp.smcconn, 1, smprops);
6497#endif
6498}
6499
6500
6501/* Shut down XSMP comms. */
6502 void
6503xsmp_close()
6504{
6505 if (xsmp_icefd != -1)
6506 {
6507 SmcCloseConnection(xsmp.smcconn, 0, NULL);
6508 xsmp_icefd = -1;
6509 }
6510}
6511#endif /* USE_XSMP */
6512
6513
6514#ifdef EBCDIC
6515/* Translate character to its CTRL- value */
6516char CtrlTable[] =
6517{
6518/* 00 - 5E */
6519 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6520 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6521 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6522 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6523 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6524 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6525/* ^ */ 0x1E,
6526/* - */ 0x1F,
6527/* 61 - 6C */
6528 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6529/* _ */ 0x1F,
6530/* 6E - 80 */
6531 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6532/* a */ 0x01,
6533/* b */ 0x02,
6534/* c */ 0x03,
6535/* d */ 0x37,
6536/* e */ 0x2D,
6537/* f */ 0x2E,
6538/* g */ 0x2F,
6539/* h */ 0x16,
6540/* i */ 0x05,
6541/* 8A - 90 */
6542 0, 0, 0, 0, 0, 0, 0,
6543/* j */ 0x15,
6544/* k */ 0x0B,
6545/* l */ 0x0C,
6546/* m */ 0x0D,
6547/* n */ 0x0E,
6548/* o */ 0x0F,
6549/* p */ 0x10,
6550/* q */ 0x11,
6551/* r */ 0x12,
6552/* 9A - A1 */
6553 0, 0, 0, 0, 0, 0, 0, 0,
6554/* s */ 0x13,
6555/* t */ 0x3C,
6556/* u */ 0x3D,
6557/* v */ 0x32,
6558/* w */ 0x26,
6559/* x */ 0x18,
6560/* y */ 0x19,
6561/* z */ 0x3F,
6562/* AA - AC */
6563 0, 0, 0,
6564/* [ */ 0x27,
6565/* AE - BC */
6566 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6567/* ] */ 0x1D,
6568/* BE - C0 */ 0, 0, 0,
6569/* A */ 0x01,
6570/* B */ 0x02,
6571/* C */ 0x03,
6572/* D */ 0x37,
6573/* E */ 0x2D,
6574/* F */ 0x2E,
6575/* G */ 0x2F,
6576/* H */ 0x16,
6577/* I */ 0x05,
6578/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6579/* J */ 0x15,
6580/* K */ 0x0B,
6581/* L */ 0x0C,
6582/* M */ 0x0D,
6583/* N */ 0x0E,
6584/* O */ 0x0F,
6585/* P */ 0x10,
6586/* Q */ 0x11,
6587/* R */ 0x12,
6588/* DA - DF */ 0, 0, 0, 0, 0, 0,
6589/* \ */ 0x1C,
6590/* E1 */ 0,
6591/* S */ 0x13,
6592/* T */ 0x3C,
6593/* U */ 0x3D,
6594/* V */ 0x32,
6595/* W */ 0x26,
6596/* X */ 0x18,
6597/* Y */ 0x19,
6598/* Z */ 0x3F,
6599/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6600 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6601};
6602
6603char MetaCharTable[]=
6604{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6605 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6606 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6607 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6608 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6609};
6610
6611
6612/* TODO: Use characters NOT numbers!!! */
6613char CtrlCharTable[]=
6614{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6615 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6616 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6617 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6618 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6619};
6620
6621
6622#endif