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