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