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