blob: 5df0d35f23bec86e444cdb0d9ed1ddfdd29b4804 [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
844#if defined(HAVE_SETJMP_H) || defined(PROTO)
845/*
846 * A simplistic version of setjmp() that only allows one level of using.
847 * Don't call twice before calling mch_endjmp()!.
848 * Usage:
849 * mch_startjmp();
850 * if (SETJMP(lc_jump_env) != 0)
851 * {
852 * mch_didjmp();
853 * EMSG("crash!");
854 * }
855 * else
856 * {
857 * do_the_work;
858 * mch_endjmp();
859 * }
860 * Note: Can't move SETJMP() here, because a function calling setjmp() must
861 * not return before the saved environment is used.
862 * Returns OK for normal return, FAIL when the protected code caused a
863 * problem and LONGJMP() was used.
864 */
865 void
866mch_startjmp()
867{
868#ifdef SIGHASARG
869 lc_signal = 0;
870#endif
871 lc_active = TRUE;
872}
873
874 void
875mch_endjmp()
876{
877 lc_active = FALSE;
878}
879
880 void
881mch_didjmp()
882{
883# if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
884 /* On FreeBSD the signal stack has to be reset after using siglongjmp(),
885 * otherwise catching the signal only works once. */
886 init_signal_stack();
887# endif
888}
889#endif
890
891/*
892 * This function handles deadly signals.
893 * It tries to preserve any swap file and exit properly.
894 * (partly from Elvis).
895 */
896 static RETSIGTYPE
897deathtrap SIGDEFARG(sigarg)
898{
899 static int entered = 0; /* count the number of times we got here.
900 Note: when memory has been corrupted
901 this may get an arbitrary value! */
902#ifdef SIGHASARG
903 int i;
904#endif
905
906#if defined(HAVE_SETJMP_H)
907 /*
908 * Catch a crash in protected code.
909 * Restores the environment saved in lc_jump_env, which looks like
910 * SETJMP() returns 1.
911 */
912 if (lc_active)
913 {
914# if defined(SIGHASARG)
915 lc_signal = sigarg;
916# endif
917 lc_active = FALSE; /* don't jump again */
918 LONGJMP(lc_jump_env, 1);
919 /* NOTREACHED */
920 }
921#endif
922
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000923#ifdef SIGHASARG
Bram Moolenaard8b0cf12004-12-12 11:33:30 +0000924 /* When SIGHUP, SIGQUIT, etc. are blocked: postpone the effect and return
925 * here. This avoids that a non-reentrant function is interrupted, e.g.,
926 * free(). Calling free() again may then cause a crash. */
927 if (entered == 0
928 && (0
929# ifdef SIGHUP
930 || sigarg == SIGHUP
931# endif
932# ifdef SIGQUIT
933 || sigarg == SIGQUIT
934# endif
935# ifdef SIGTERM
936 || sigarg == SIGTERM
937# endif
938# ifdef SIGPWR
939 || sigarg == SIGPWR
940# endif
941# ifdef SIGUSR1
942 || sigarg == SIGUSR1
943# endif
944# ifdef SIGUSR2
945 || sigarg == SIGUSR2
946# endif
947 )
948 && !handle_signal(sigarg))
Bram Moolenaar293ee4d2004-12-09 21:34:53 +0000949 SIGRETURN;
950#endif
951
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952 /* Remember how often we have been called. */
953 ++entered;
954
955#ifdef FEAT_EVAL
956 /* Set the v:dying variable. */
957 set_vim_var_nr(VV_DYING, (long)entered);
958#endif
959
Bram Moolenaarbc7aa852005-03-06 23:38:09 +0000960#ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +0000961 /* Since we are now using the signal stack, need to reset the stack
962 * limit. Otherwise using a regexp will fail. */
963 get_stack_limit();
964#endif
965
966#ifdef SIGHASARG
967 /* try to find the name of this signal */
968 for (i = 0; signal_info[i].sig != -1; i++)
969 if (sigarg == signal_info[i].sig)
970 break;
971 deadly_signal = sigarg;
972#endif
973
974 full_screen = FALSE; /* don't write message to the GUI, it might be
975 * part of the problem... */
976 /*
977 * If something goes wrong after entering here, we may get here again.
978 * When this happens, give a message and try to exit nicely (resetting the
979 * terminal mode, etc.)
980 * When this happens twice, just exit, don't even try to give a message,
981 * stack may be corrupt or something weird.
982 * When this still happens again (or memory was corrupted in such a way
983 * that "entered" was clobbered) use _exit(), don't try freeing resources.
984 */
985 if (entered >= 3)
986 {
987 reset_signals(); /* don't catch any signals anymore */
988 may_core_dump();
989 if (entered >= 4)
990 _exit(8);
991 exit(7);
992 }
993 if (entered == 2)
994 {
995 OUT_STR(_("Vim: Double signal, exiting\n"));
996 out_flush();
997 getout(1);
998 }
999
1000#ifdef SIGHASARG
1001 sprintf((char *)IObuff, _("Vim: Caught deadly signal %s\n"),
1002 signal_info[i].name);
1003#else
1004 sprintf((char *)IObuff, _("Vim: Caught deadly signal\n"));
1005#endif
1006 preserve_exit(); /* preserve files and exit */
1007
Bram Moolenaar009b2592004-10-24 19:18:58 +00001008#ifdef NBDEBUG
1009 reset_signals();
1010 may_core_dump();
1011 abort();
1012#endif
1013
Bram Moolenaar071d4272004-06-13 20:20:40 +00001014 SIGRETURN;
1015}
1016
1017#ifdef _REENTRANT
1018/*
1019 * On Solaris with multi-threading, suspending might not work immediately.
1020 * Catch the SIGCONT signal, which will be used as an indication whether the
1021 * suspending has been done or not.
1022 */
1023static int sigcont_received;
1024static RETSIGTYPE sigcont_handler __ARGS(SIGPROTOARG);
1025
1026/*
1027 * signal handler for SIGCONT
1028 */
1029/* ARGSUSED */
1030 static RETSIGTYPE
1031sigcont_handler SIGDEFARG(sigarg)
1032{
1033 sigcont_received = TRUE;
1034 SIGRETURN;
1035}
1036#endif
1037
1038/*
1039 * If the machine has job control, use it to suspend the program,
1040 * otherwise fake it by starting a new shell.
1041 */
1042 void
1043mch_suspend()
1044{
1045 /* BeOS does have SIGTSTP, but it doesn't work. */
1046#if defined(SIGTSTP) && !defined(__BEOS__)
1047 out_flush(); /* needed to make cursor visible on some systems */
1048 settmode(TMODE_COOK);
1049 out_flush(); /* needed to disable mouse on some systems */
1050
1051# if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
1052 /* Since we are going to sleep, we can't respond to requests for the X
1053 * selections. Lose them, otherwise other applications will hang. But
1054 * first copy the text to cut buffer 0. */
1055 if (clip_star.owned || clip_plus.owned)
1056 {
1057 x11_export_final_selection();
1058 if (clip_star.owned)
1059 clip_lose_selection(&clip_star);
1060 if (clip_plus.owned)
1061 clip_lose_selection(&clip_plus);
1062 if (x11_display != NULL)
1063 XFlush(x11_display);
1064 }
1065# endif
1066
1067# ifdef _REENTRANT
1068 sigcont_received = FALSE;
1069# endif
1070 kill(0, SIGTSTP); /* send ourselves a STOP signal */
1071# ifdef _REENTRANT
1072 /* When we didn't suspend immediately in the kill(), do it now. Happens
1073 * on multi-threaded Solaris. */
1074 if (!sigcont_received)
1075 pause();
1076# endif
1077
1078# ifdef FEAT_TITLE
1079 /*
1080 * Set oldtitle to NULL, so the current title is obtained again.
1081 */
1082 vim_free(oldtitle);
1083 oldtitle = NULL;
1084# endif
1085 settmode(TMODE_RAW);
1086 need_check_timestamps = TRUE;
1087 did_check_timestamps = FALSE;
1088#else
1089 suspend_shell();
1090#endif
1091}
1092
1093 void
1094mch_init()
1095{
1096 Columns = 80;
1097 Rows = 24;
1098
1099 out_flush();
1100 set_signals();
Bram Moolenaardf177f62005-02-22 08:39:57 +00001101
1102#if defined(MACOS_X) && defined(FEAT_MBYTE)
1103 mac_conv_init();
1104#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001105}
1106
1107 static void
1108set_signals()
1109{
1110#if defined(SIGWINCH)
1111 /*
1112 * WINDOW CHANGE signal is handled with sig_winch().
1113 */
1114 signal(SIGWINCH, (RETSIGTYPE (*)())sig_winch);
1115#endif
1116
1117 /*
1118 * We want the STOP signal to work, to make mch_suspend() work.
1119 * For "rvim" the STOP signal is ignored.
1120 */
1121#ifdef SIGTSTP
1122 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
1123#endif
1124#ifdef _REENTRANT
1125 signal(SIGCONT, sigcont_handler);
1126#endif
1127
1128 /*
1129 * We want to ignore breaking of PIPEs.
1130 */
1131#ifdef SIGPIPE
1132 signal(SIGPIPE, SIG_IGN);
1133#endif
1134
Bram Moolenaar071d4272004-06-13 20:20:40 +00001135#ifdef SIGINT
Bram Moolenaardf177f62005-02-22 08:39:57 +00001136 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001137#endif
1138
1139 /*
1140 * Ignore alarm signals (Perl's alarm() generates it).
1141 */
1142#ifdef SIGALRM
1143 signal(SIGALRM, SIG_IGN);
1144#endif
1145
1146 /*
1147 * Catch SIGPWR (power failure?) to preserve the swap files, so that no
1148 * work will be lost.
1149 */
1150#ifdef SIGPWR
1151 signal(SIGPWR, (RETSIGTYPE (*)())catch_sigpwr);
1152#endif
1153
1154 /*
1155 * Arrange for other signals to gracefully shutdown Vim.
1156 */
1157 catch_signals(deathtrap, SIG_ERR);
1158
1159#if defined(FEAT_GUI) && defined(SIGHUP)
1160 /*
1161 * When the GUI is running, ignore the hangup signal.
1162 */
1163 if (gui.in_use)
1164 signal(SIGHUP, SIG_IGN);
1165#endif
1166}
1167
Bram Moolenaardf177f62005-02-22 08:39:57 +00001168#if defined(SIGINT) || defined(PROTO)
1169/*
1170 * Catch CTRL-C (only works while in Cooked mode).
1171 */
1172 static void
1173catch_int_signal()
1174{
1175 signal(SIGINT, (RETSIGTYPE (*)())catch_sigint);
1176}
1177#endif
1178
Bram Moolenaar071d4272004-06-13 20:20:40 +00001179 void
1180reset_signals()
1181{
1182 catch_signals(SIG_DFL, SIG_DFL);
1183#ifdef _REENTRANT
1184 /* SIGCONT isn't in the list, because its default action is ignore */
1185 signal(SIGCONT, SIG_DFL);
1186#endif
1187}
1188
1189 static void
1190catch_signals(func_deadly, func_other)
1191 RETSIGTYPE (*func_deadly)();
1192 RETSIGTYPE (*func_other)();
1193{
1194 int i;
1195
1196 for (i = 0; signal_info[i].sig != -1; i++)
1197 if (signal_info[i].deadly)
1198 {
1199#if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
1200 struct sigaction sa;
1201
1202 /* Setup to use the alternate stack for the signal function. */
1203 sa.sa_handler = func_deadly;
1204 sigemptyset(&sa.sa_mask);
1205# if defined(__linux__) && defined(_REENTRANT)
1206 /* On Linux, with glibc compiled for kernel 2.2, there is a bug in
1207 * thread handling in combination with using the alternate stack:
1208 * pthread library functions try to use the stack pointer to
1209 * identify the current thread, causing a SEGV signal, which
1210 * recursively calls deathtrap() and hangs. */
1211 sa.sa_flags = 0;
1212# else
1213 sa.sa_flags = SA_ONSTACK;
1214# endif
1215 sigaction(signal_info[i].sig, &sa, NULL);
1216#else
1217# if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGVEC)
1218 struct sigvec sv;
1219
1220 /* Setup to use the alternate stack for the signal function. */
1221 sv.sv_handler = func_deadly;
1222 sv.sv_mask = 0;
1223 sv.sv_flags = SV_ONSTACK;
1224 sigvec(signal_info[i].sig, &sv, NULL);
1225# else
1226 signal(signal_info[i].sig, func_deadly);
1227# endif
1228#endif
1229 }
1230 else if (func_other != SIG_ERR)
1231 signal(signal_info[i].sig, func_other);
1232}
1233
1234/*
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001235 * Handling of SIGHUP, SIGQUIT and SIGTERM:
1236 * "when" == a signal: when busy, postpone, otherwise return TRUE
1237 * "when" == SIGNAL_BLOCK: Going to be busy, block signals
1238 * "when" == SIGNAL_UNBLOCK: Going wait, unblock signals
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001239 * Returns TRUE when Vim should exit.
1240 */
1241 int
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001242handle_signal(sig)
1243 int sig;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001244{
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001245 static int got_signal = 0;
1246 static int blocked = TRUE;
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001247
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001248 switch (sig)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001249 {
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001250 case SIGNAL_BLOCK: blocked = TRUE;
1251 break;
1252
1253 case SIGNAL_UNBLOCK: blocked = FALSE;
1254 if (got_signal != 0)
1255 {
1256 kill(getpid(), got_signal);
1257 got_signal = 0;
1258 }
1259 break;
1260
1261 default: if (!blocked)
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001262 return TRUE; /* exit! */
Bram Moolenaard8b0cf12004-12-12 11:33:30 +00001263 got_signal = sig;
1264#ifdef SIGPWR
1265 if (sig != SIGPWR)
1266#endif
1267 got_int = TRUE; /* break any loops */
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001268 break;
1269 }
1270 return FALSE;
1271}
1272
1273/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001274 * Check_win checks whether we have an interactive stdout.
1275 */
1276/* ARGSUSED */
1277 int
1278mch_check_win(argc, argv)
1279 int argc;
1280 char **argv;
1281{
1282#ifdef OS2
1283 /*
1284 * Store argv[0], may be used for $VIM. Only use it if it is an absolute
1285 * name, mostly it's just "vim" and found in the path, which is unusable.
1286 */
1287 if (mch_isFullName(argv[0]))
1288 exe_name = vim_strsave((char_u *)argv[0]);
1289#endif
1290 if (isatty(1))
1291 return OK;
1292 return FAIL;
1293}
1294
1295/*
1296 * Return TRUE if the input comes from a terminal, FALSE otherwise.
1297 */
1298 int
1299mch_input_isatty()
1300{
1301 if (isatty(read_cmd_fd))
1302 return TRUE;
1303 return FALSE;
1304}
1305
1306#ifdef FEAT_X11
1307
1308# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H) \
1309 && (defined(FEAT_XCLIPBOARD) || defined(FEAT_TITLE))
1310
1311static void xopen_message __ARGS((struct timeval *tvp));
1312
1313/*
1314 * Give a message about the elapsed time for opening the X window.
1315 */
1316 static void
1317xopen_message(tvp)
1318 struct timeval *tvp; /* must contain start time */
1319{
1320 struct timeval end_tv;
1321
1322 /* Compute elapsed time. */
1323 gettimeofday(&end_tv, NULL);
1324 smsg((char_u *)_("Opening the X display took %ld msec"),
1325 (end_tv.tv_sec - tvp->tv_sec) * 1000L
1326 + (end_tv.tv_usec - tvp->tv_usec) / 1000L);
1327}
1328# endif
1329#endif
1330
1331#if defined(FEAT_X11) && (defined(FEAT_TITLE) || defined(FEAT_XCLIPBOARD))
1332/*
1333 * A few functions shared by X11 title and clipboard code.
1334 */
1335static int x_error_handler __ARGS((Display *dpy, XErrorEvent *error_event));
1336static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event));
1337static int x_connect_to_server __ARGS((void));
1338static int test_x11_window __ARGS((Display *dpy));
1339
1340static int got_x_error = FALSE;
1341
1342/*
1343 * X Error handler, otherwise X just exits! (very rude) -- webb
1344 */
1345 static int
1346x_error_handler(dpy, error_event)
1347 Display *dpy;
1348 XErrorEvent *error_event;
1349{
Bram Moolenaar843ee412004-06-30 16:16:41 +00001350 XGetErrorText(dpy, error_event->error_code, (char *)IObuff, IOSIZE);
Bram Moolenaar81695252004-12-29 20:58:21 +00001351#if defined(FEAT_GUI_KDE)
1352 /* KDE sometimes produces X error that we want to ignore */
1353 STRCAT(IObuff, _("\nVim: Got X error but we continue...\n"));
1354 mch_errmsg((char *)IObuff);
Bram Moolenaar843ee412004-06-30 16:16:41 +00001355 return 0;
1356#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001357 STRCAT(IObuff, _("\nVim: Got X error\n"));
1358
1359 /* We cannot print a message and continue, because no X calls are allowed
1360 * here (causes my system to hang). Silently continuing might be an
1361 * alternative... */
1362 preserve_exit(); /* preserve files and exit */
1363
1364 return 0; /* NOTREACHED */
Bram Moolenaar843ee412004-06-30 16:16:41 +00001365#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001366}
1367
1368/*
1369 * Another X Error handler, just used to check for errors.
1370 */
1371/* ARGSUSED */
1372 static int
1373x_error_check(dpy, error_event)
1374 Display *dpy;
1375 XErrorEvent *error_event;
1376{
1377 got_x_error = TRUE;
1378 return 0;
1379}
1380
1381#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)
1382# if defined(HAVE_SETJMP_H)
1383/*
1384 * An X IO Error handler, used to catch error while opening the display.
1385 */
1386static int x_IOerror_check __ARGS((Display *dpy));
1387
1388/* ARGSUSED */
1389 static int
1390x_IOerror_check(dpy)
1391 Display *dpy;
1392{
1393 /* This function should not return, it causes exit(). Longjump instead. */
1394 LONGJMP(lc_jump_env, 1);
1395 /*NOTREACHED*/
1396 return 0;
1397}
1398# endif
1399
1400/*
1401 * An X IO Error handler, used to catch terminal errors.
1402 */
1403static int x_IOerror_handler __ARGS((Display *dpy));
1404
1405/* ARGSUSED */
1406 static int
1407x_IOerror_handler(dpy)
1408 Display *dpy;
1409{
1410 xterm_dpy = NULL;
1411 x11_window = 0;
1412 x11_display = NULL;
1413 xterm_Shell = (Widget)0;
1414
1415 /* This function should not return, it causes exit(). Longjump instead. */
1416 LONGJMP(x_jump_env, 1);
1417 /*NOTREACHED*/
1418 return 0;
1419}
1420#endif
1421
1422/*
1423 * Return TRUE when connection to the X server is desired.
1424 */
1425 static int
1426x_connect_to_server()
1427{
1428 regmatch_T regmatch;
1429
1430#if defined(FEAT_CLIENTSERVER)
1431 if (x_force_connect)
1432 return TRUE;
1433#endif
1434 if (x_no_connect)
1435 return FALSE;
1436
1437 /* Check for a match with "exclude:" from 'clipboard'. */
1438 if (clip_exclude_prog != NULL)
1439 {
1440 regmatch.rm_ic = FALSE; /* Don't ignore case */
1441 regmatch.regprog = clip_exclude_prog;
1442 if (vim_regexec(&regmatch, T_NAME, (colnr_T)0))
1443 return FALSE;
1444 }
1445 return TRUE;
1446}
1447
1448/*
1449 * Test if "dpy" and x11_window are valid by getting the window title.
1450 * I don't actually want it yet, so there may be a simpler call to use, but
1451 * this will cause the error handler x_error_check() to be called if anything
1452 * is wrong, such as the window pointer being invalid (as can happen when the
1453 * user changes his DISPLAY, but not his WINDOWID) -- webb
1454 */
1455 static int
1456test_x11_window(dpy)
1457 Display *dpy;
1458{
1459 int (*old_handler)();
1460 XTextProperty text_prop;
1461
1462 old_handler = XSetErrorHandler(x_error_check);
1463 got_x_error = FALSE;
1464 if (XGetWMName(dpy, x11_window, &text_prop))
1465 XFree((void *)text_prop.value);
1466 XSync(dpy, False);
1467 (void)XSetErrorHandler(old_handler);
1468
1469 if (p_verbose > 0 && got_x_error)
1470 MSG(_("Testing the X display failed"));
1471
1472 return (got_x_error ? FAIL : OK);
1473}
1474#endif
1475
1476#ifdef FEAT_TITLE
1477
1478#ifdef FEAT_X11
1479
1480static int get_x11_thing __ARGS((int get_title, int test_only));
1481
1482/*
1483 * try to get x11 window and display
1484 *
1485 * return FAIL for failure, OK otherwise
1486 */
1487 static int
1488get_x11_windis()
1489{
1490 char *winid;
1491 static int result = -1;
1492#define XD_NONE 0 /* x11_display not set here */
1493#define XD_HERE 1 /* x11_display opened here */
1494#define XD_GUI 2 /* x11_display used from gui.dpy */
1495#define XD_XTERM 3 /* x11_display used from xterm_dpy */
1496 static int x11_display_from = XD_NONE;
1497 static int did_set_error_handler = FALSE;
1498
1499 if (!did_set_error_handler)
1500 {
1501 /* X just exits if it finds an error otherwise! */
1502 (void)XSetErrorHandler(x_error_handler);
1503 did_set_error_handler = TRUE;
1504 }
1505
Bram Moolenaar843ee412004-06-30 16:16:41 +00001506#if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_KDE)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001507 if (gui.in_use)
1508 {
1509 /*
1510 * If the X11 display was opened here before, for the window where Vim
1511 * was started, close that one now to avoid a memory leak.
1512 */
1513 if (x11_display_from == XD_HERE && x11_display != NULL)
1514 {
1515 XCloseDisplay(x11_display);
1516 x11_display_from = XD_NONE;
1517 }
1518 if (gui_get_x11_windis(&x11_window, &x11_display) == OK)
1519 {
1520 x11_display_from = XD_GUI;
1521 return OK;
1522 }
1523 x11_display = NULL;
1524 return FAIL;
1525 }
1526 else if (x11_display_from == XD_GUI)
1527 {
1528 /* GUI must have stopped somehow, clear x11_display */
1529 x11_window = 0;
1530 x11_display = NULL;
1531 x11_display_from = XD_NONE;
1532 }
1533#endif
1534
1535 /* When started with the "-X" argument, don't try connecting. */
1536 if (!x_connect_to_server())
1537 return FAIL;
1538
1539 /*
1540 * If WINDOWID not set, should try another method to find out
1541 * what the current window number is. The only code I know for
1542 * this is very complicated.
1543 * We assume that zero is invalid for WINDOWID.
1544 */
1545 if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL)
1546 x11_window = (Window)atol(winid);
1547
1548#ifdef FEAT_XCLIPBOARD
1549 if (xterm_dpy != NULL && x11_window != 0)
1550 {
1551 /* Checked it already. */
1552 if (x11_display_from == XD_XTERM)
1553 return OK;
1554
1555 /*
1556 * If the X11 display was opened here before, for the window where Vim
1557 * was started, close that one now to avoid a memory leak.
1558 */
1559 if (x11_display_from == XD_HERE && x11_display != NULL)
1560 XCloseDisplay(x11_display);
1561 x11_display = xterm_dpy;
1562 x11_display_from = XD_XTERM;
1563 if (test_x11_window(x11_display) == FAIL)
1564 {
1565 /* probably bad $WINDOWID */
1566 x11_window = 0;
1567 x11_display = NULL;
1568 x11_display_from = XD_NONE;
1569 return FAIL;
1570 }
1571 return OK;
1572 }
1573#endif
1574
1575 if (x11_window == 0 || x11_display == NULL)
1576 result = -1;
1577
1578 if (result != -1) /* Have already been here and set this */
1579 return result; /* Don't do all these X calls again */
1580
1581 if (x11_window != 0 && x11_display == NULL)
1582 {
1583#ifdef SET_SIG_ALARM
1584 RETSIGTYPE (*sig_save)();
1585#endif
1586#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1587 struct timeval start_tv;
1588
1589 if (p_verbose > 0)
1590 gettimeofday(&start_tv, NULL);
1591#endif
1592
1593#ifdef SET_SIG_ALARM
1594 /*
1595 * Opening the Display may hang if the DISPLAY setting is wrong, or
1596 * the network connection is bad. Set an alarm timer to get out.
1597 */
1598 sig_alarm_called = FALSE;
1599 sig_save = (RETSIGTYPE (*)())signal(SIGALRM,
1600 (RETSIGTYPE (*)())sig_alarm);
1601 alarm(2);
1602#endif
1603 x11_display = XOpenDisplay(NULL);
1604
1605#ifdef SET_SIG_ALARM
1606 alarm(0);
1607 signal(SIGALRM, (RETSIGTYPE (*)())sig_save);
1608 if (p_verbose > 0 && sig_alarm_called)
1609 MSG(_("Opening the X display timed out"));
1610#endif
1611 if (x11_display != NULL)
1612 {
1613# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
1614 if (p_verbose > 0)
1615 xopen_message(&start_tv);
1616# endif
1617 if (test_x11_window(x11_display) == FAIL)
1618 {
1619 /* Maybe window id is bad */
1620 x11_window = 0;
1621 XCloseDisplay(x11_display);
1622 x11_display = NULL;
1623 }
1624 else
1625 x11_display_from = XD_HERE;
1626 }
1627 }
1628 if (x11_window == 0 || x11_display == NULL)
1629 return (result = FAIL);
1630 return (result = OK);
1631}
1632
1633/*
1634 * Determine original x11 Window Title
1635 */
1636 static int
1637get_x11_title(test_only)
1638 int test_only;
1639{
Bram Moolenaar47136d72004-10-12 20:02:24 +00001640 return get_x11_thing(TRUE, test_only);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001641}
1642
1643/*
1644 * Determine original x11 Window icon
1645 */
1646 static int
1647get_x11_icon(test_only)
1648 int test_only;
1649{
1650 int retval = FALSE;
1651
1652 retval = get_x11_thing(FALSE, test_only);
1653
1654 /* could not get old icon, use terminal name */
1655 if (oldicon == NULL && !test_only)
1656 {
1657 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1658 oldicon = T_NAME + 8;
1659 else
1660 oldicon = T_NAME;
1661 }
1662
1663 return retval;
1664}
1665
1666 static int
1667get_x11_thing(get_title, test_only)
1668 int get_title; /* get title string */
1669 int test_only;
1670{
1671 XTextProperty text_prop;
1672 int retval = FALSE;
1673 Status status;
1674
1675 if (get_x11_windis() == OK)
1676 {
1677 /* Get window/icon name if any */
1678 if (get_title)
1679 status = XGetWMName(x11_display, x11_window, &text_prop);
1680 else
1681 status = XGetWMIconName(x11_display, x11_window, &text_prop);
1682
1683 /*
1684 * If terminal is xterm, then x11_window may be a child window of the
1685 * outer xterm window that actually contains the window/icon name, so
1686 * keep traversing up the tree until a window with a title/icon is
1687 * found.
1688 */
1689 /* Previously this was only done for xterm and alikes. I don't see a
1690 * reason why it would fail for other terminal emulators.
1691 * if (term_is_xterm) */
1692 {
1693 Window root;
1694 Window parent;
1695 Window win = x11_window;
1696 Window *children;
1697 unsigned int num_children;
1698
1699 while (!status || text_prop.value == NULL)
1700 {
1701 if (!XQueryTree(x11_display, win, &root, &parent, &children,
1702 &num_children))
1703 break;
1704 if (children)
1705 XFree((void *)children);
1706 if (parent == root || parent == 0)
1707 break;
1708
1709 win = parent;
1710 if (get_title)
1711 status = XGetWMName(x11_display, win, &text_prop);
1712 else
1713 status = XGetWMIconName(x11_display, win, &text_prop);
1714 }
1715 }
1716 if (status && text_prop.value != NULL)
1717 {
1718 retval = TRUE;
1719 if (!test_only)
1720 {
1721#ifdef FEAT_XFONTSET
1722 if (text_prop.encoding == XA_STRING)
1723 {
1724#endif
1725 if (get_title)
1726 oldtitle = vim_strsave((char_u *)text_prop.value);
1727 else
1728 oldicon = vim_strsave((char_u *)text_prop.value);
1729#ifdef FEAT_XFONTSET
1730 }
1731 else
1732 {
1733 char **cl;
1734 Status transform_status;
1735 int n = 0;
1736
1737 transform_status = XmbTextPropertyToTextList(x11_display,
1738 &text_prop,
1739 &cl, &n);
1740 if (transform_status >= Success && n > 0 && cl[0])
1741 {
1742 if (get_title)
1743 oldtitle = vim_strsave((char_u *) cl[0]);
1744 else
1745 oldicon = vim_strsave((char_u *) cl[0]);
1746 XFreeStringList(cl);
1747 }
1748 else
1749 {
1750 if (get_title)
1751 oldtitle = vim_strsave((char_u *)text_prop.value);
1752 else
1753 oldicon = vim_strsave((char_u *)text_prop.value);
1754 }
1755 }
1756#endif
1757 }
1758 XFree((void *)text_prop.value);
1759 }
1760 }
1761 return retval;
1762}
1763
1764/* Are Xutf8 functions available? Avoid error from old compilers. */
1765#if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
1766# if X_HAVE_UTF8_STRING
1767# define USE_UTF8_STRING
1768# endif
1769#endif
1770
1771/*
1772 * Set x11 Window Title
1773 *
1774 * get_x11_windis() must be called before this and have returned OK
1775 */
1776 static void
1777set_x11_title(title)
1778 char_u *title;
1779{
1780 /* XmbSetWMProperties() and Xutf8SetWMProperties() should use a STRING
1781 * when possible, COMPOUND_TEXT otherwise. COMPOUND_TEXT isn't
1782 * supported everywhere and STRING doesn't work for multi-byte titles.
1783 */
1784#ifdef USE_UTF8_STRING
1785 if (enc_utf8)
1786 Xutf8SetWMProperties(x11_display, x11_window, (const char *)title,
1787 NULL, NULL, 0, NULL, NULL, NULL);
1788 else
1789#endif
1790 {
1791#if XtSpecificationRelease >= 4
1792# ifdef FEAT_XFONTSET
1793 XmbSetWMProperties(x11_display, x11_window, (const char *)title,
1794 NULL, NULL, 0, NULL, NULL, NULL);
1795# else
1796 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001797 char *c_title = (char *)title;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001798
1799 /* directly from example 3-18 "basicwin" of Xlib Programming Manual */
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001800 (void)XStringListToTextProperty(&c_title, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001801 XSetWMProperties(x11_display, x11_window, &text_prop,
1802 NULL, NULL, 0, NULL, NULL, NULL);
1803# endif
1804#else
1805 XStoreName(x11_display, x11_window, (char *)title);
1806#endif
1807 }
1808 XFlush(x11_display);
1809}
1810
1811/*
1812 * Set x11 Window icon
1813 *
1814 * get_x11_windis() must be called before this and have returned OK
1815 */
1816 static void
1817set_x11_icon(icon)
1818 char_u *icon;
1819{
1820 /* See above for comments about using X*SetWMProperties(). */
1821#ifdef USE_UTF8_STRING
1822 if (enc_utf8)
1823 Xutf8SetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1824 NULL, 0, NULL, NULL, NULL);
1825 else
1826#endif
1827 {
1828#if XtSpecificationRelease >= 4
1829# ifdef FEAT_XFONTSET
1830 XmbSetWMProperties(x11_display, x11_window, NULL, (const char *)icon,
1831 NULL, 0, NULL, NULL, NULL);
1832# else
1833 XTextProperty text_prop;
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001834 char *c_icon = (char *)icon;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001835
Bram Moolenaar9d75c832005-01-25 21:57:23 +00001836 (void)XStringListToTextProperty(&c_icon, 1, &text_prop);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001837 XSetWMProperties(x11_display, x11_window, NULL, &text_prop,
1838 NULL, 0, NULL, NULL, NULL);
1839# endif
1840#else
1841 XSetIconName(x11_display, x11_window, (char *)icon);
1842#endif
1843 }
1844 XFlush(x11_display);
1845}
1846
1847#else /* FEAT_X11 */
1848
1849/*ARGSUSED*/
1850 static int
1851get_x11_title(test_only)
1852 int test_only;
1853{
1854 return FALSE;
1855}
1856
1857 static int
1858get_x11_icon(test_only)
1859 int test_only;
1860{
1861 if (!test_only)
1862 {
1863 if (STRNCMP(T_NAME, "builtin_", 8) == 0)
1864 oldicon = T_NAME + 8;
1865 else
1866 oldicon = T_NAME;
1867 }
1868 return FALSE;
1869}
1870
1871#endif /* FEAT_X11 */
1872
1873 int
1874mch_can_restore_title()
1875{
1876 return get_x11_title(TRUE);
1877}
1878
1879 int
1880mch_can_restore_icon()
1881{
1882 return get_x11_icon(TRUE);
1883}
1884
1885/*
1886 * Set the window title and icon.
1887 */
1888 void
1889mch_settitle(title, icon)
1890 char_u *title;
1891 char_u *icon;
1892{
1893 int type = 0;
1894 static int recursive = 0;
1895
1896 if (T_NAME == NULL) /* no terminal name (yet) */
1897 return;
1898 if (title == NULL && icon == NULL) /* nothing to do */
1899 return;
1900
1901 /* When one of the X11 functions causes a deadly signal, we get here again
1902 * recursively. Avoid hanging then (something is probably locked). */
1903 if (recursive)
1904 return;
1905 ++recursive;
1906
1907 /*
1908 * if the window ID and the display is known, we may use X11 calls
1909 */
1910#ifdef FEAT_X11
1911 if (get_x11_windis() == OK)
1912 type = 1;
1913#else
1914# if defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK)
1915 if (gui.in_use)
1916 type = 1;
1917# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001918#endif
1919
1920 /*
1921 * Note: if "t_TS" is set, title is set with escape sequence rather
1922 * than x11 calls, because the x11 calls don't always work
1923 */
Bram Moolenaar843ee412004-06-30 16:16:41 +00001924#ifdef FEAT_GUI_KDE
Bram Moolenaar47136d72004-10-12 20:02:24 +00001925 /* dont know why but KDE needs this one as we don't go through the next
1926 * function... */
Bram Moolenaar843ee412004-06-30 16:16:41 +00001927 gui_mch_settitle(title, icon);
1928#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001929 if ((type || *T_TS != NUL) && title != NULL)
1930 {
1931 if (oldtitle == NULL
1932#ifdef FEAT_GUI
1933 && !gui.in_use
1934#endif
1935 ) /* first call but not in GUI, save title */
1936 (void)get_x11_title(FALSE);
1937
1938 if (*T_TS != NUL) /* it's OK if t_fs is empty */
1939 term_settitle(title);
1940#ifdef FEAT_X11
1941 else
1942# ifdef FEAT_GUI_GTK
1943 if (!gui.in_use) /* don't do this if GTK+ is running */
1944# endif
1945 set_x11_title(title); /* x11 */
1946#endif
Bram Moolenaar2fa15e62005-01-04 21:23:48 +00001947#if defined(FEAT_GUI_GTK) \
Bram Moolenaar071d4272004-06-13 20:20:40 +00001948 || defined(FEAT_GUI_PHOTON) || defined(FEAT_GUI_MAC)
1949 else
1950 gui_mch_settitle(title, icon);
1951#endif
1952 did_set_title = TRUE;
1953 }
1954
1955 if ((type || *T_CIS != NUL) && icon != NULL)
1956 {
1957 if (oldicon == NULL
1958#ifdef FEAT_GUI
1959 && !gui.in_use
1960#endif
1961 ) /* first call, save icon */
1962 get_x11_icon(FALSE);
1963
1964 if (*T_CIS != NUL)
1965 {
1966 out_str(T_CIS); /* set icon start */
1967 out_str_nf(icon);
1968 out_str(T_CIE); /* set icon end */
1969 out_flush();
1970 }
1971#ifdef FEAT_X11
1972 else
1973# ifdef FEAT_GUI_GTK
1974 if (!gui.in_use) /* don't do this if GTK+ is running */
1975# endif
1976 set_x11_icon(icon); /* x11 */
1977#endif
1978 did_set_icon = TRUE;
1979 }
1980 --recursive;
1981}
1982
1983/*
1984 * Restore the window/icon title.
1985 * "which" is one of:
1986 * 1 only restore title
1987 * 2 only restore icon
1988 * 3 restore title and icon
1989 */
1990 void
1991mch_restore_title(which)
1992 int which;
1993{
1994 /* only restore the title or icon when it has been set */
1995 mch_settitle(((which & 1) && did_set_title) ?
1996 (oldtitle ? oldtitle : p_titleold) : NULL,
1997 ((which & 2) && did_set_icon) ? oldicon : NULL);
1998}
1999
2000#endif /* FEAT_TITLE */
2001
2002/*
2003 * Return TRUE if "name" looks like some xterm name.
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002004 * Seiichi Sato mentioned that "mlterm" works like xterm.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002005 */
2006 int
2007vim_is_xterm(name)
2008 char_u *name;
2009{
2010 if (name == NULL)
2011 return FALSE;
2012 return (STRNICMP(name, "xterm", 5) == 0
2013 || STRNICMP(name, "nxterm", 6) == 0
2014 || STRNICMP(name, "kterm", 5) == 0
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002015 || STRNICMP(name, "mlterm", 6) == 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00002016 || STRNICMP(name, "rxvt", 4) == 0
2017 || STRCMP(name, "builtin_xterm") == 0);
2018}
2019
2020#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2021/*
2022 * Return non-zero when using an xterm mouse, according to 'ttymouse'.
2023 * Return 1 for "xterm".
2024 * Return 2 for "xterm2".
2025 */
2026 int
2027use_xterm_mouse()
2028{
2029 if (ttym_flags == TTYM_XTERM2)
2030 return 2;
2031 if (ttym_flags == TTYM_XTERM)
2032 return 1;
2033 return 0;
2034}
2035#endif
2036
2037 int
2038vim_is_iris(name)
2039 char_u *name;
2040{
2041 if (name == NULL)
2042 return FALSE;
2043 return (STRNICMP(name, "iris-ansi", 9) == 0
2044 || STRCMP(name, "builtin_iris-ansi") == 0);
2045}
2046
2047 int
2048vim_is_vt300(name)
2049 char_u *name;
2050{
2051 if (name == NULL)
2052 return FALSE; /* actually all ANSI comp. terminals should be here */
Bram Moolenaard4755bb2004-09-02 19:12:26 +00002053 /* catch VT100 - VT5xx */
2054 return ((STRNICMP(name, "vt", 2) == 0
2055 && vim_strchr((char_u *)"12345", name[2]) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002056 || STRCMP(name, "builtin_vt320") == 0);
2057}
2058
2059/*
2060 * Return TRUE if "name" is a terminal for which 'ttyfast' should be set.
2061 * This should include all windowed terminal emulators.
2062 */
2063 int
2064vim_is_fastterm(name)
2065 char_u *name;
2066{
2067 if (name == NULL)
2068 return FALSE;
2069 if (vim_is_xterm(name) || vim_is_vt300(name) || vim_is_iris(name))
2070 return TRUE;
2071 return ( STRNICMP(name, "hpterm", 6) == 0
2072 || STRNICMP(name, "sun-cmd", 7) == 0
2073 || STRNICMP(name, "screen", 6) == 0
2074 || STRNICMP(name, "dtterm", 6) == 0);
2075}
2076
2077/*
2078 * Insert user name in s[len].
2079 * Return OK if a name found.
2080 */
2081 int
2082mch_get_user_name(s, len)
2083 char_u *s;
2084 int len;
2085{
2086#ifdef VMS
2087 STRNCPY((char *)s, cuserid(NULL), len);
2088 return OK;
2089#else
2090 return mch_get_uname(getuid(), s, len);
2091#endif
2092}
2093
2094/*
2095 * Insert user name for "uid" in s[len].
2096 * Return OK if a name found.
2097 */
2098 int
2099mch_get_uname(uid, s, len)
2100 uid_t uid;
2101 char_u *s;
2102 int len;
2103{
2104#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
2105 struct passwd *pw;
2106
2107 if ((pw = getpwuid(uid)) != NULL
2108 && pw->pw_name != NULL && *(pw->pw_name) != NUL)
2109 {
2110 STRNCPY(s, pw->pw_name, len);
2111 return OK;
2112 }
2113#endif
2114 sprintf((char *)s, "%d", (int)uid); /* assumes s is long enough */
2115 return FAIL; /* a number is not a name */
2116}
2117
2118/*
2119 * Insert host name is s[len].
2120 */
2121
2122#ifdef HAVE_SYS_UTSNAME_H
2123 void
2124mch_get_host_name(s, len)
2125 char_u *s;
2126 int len;
2127{
2128 struct utsname vutsname;
2129
2130 if (uname(&vutsname) < 0)
2131 *s = NUL;
2132 else
2133 STRNCPY(s, vutsname.nodename, len);
2134 s[len - 1] = NUL; /* make sure it's terminated */
2135}
2136#else /* HAVE_SYS_UTSNAME_H */
2137
2138# ifdef HAVE_SYS_SYSTEMINFO_H
2139# define gethostname(nam, len) sysinfo(SI_HOSTNAME, nam, len)
2140# endif
2141
2142 void
2143mch_get_host_name(s, len)
2144 char_u *s;
2145 int len;
2146{
2147# ifdef VAXC
2148 vaxc$gethostname((char *)s, len);
2149# else
2150 gethostname((char *)s, len);
2151# endif
2152 s[len - 1] = NUL; /* make sure it's terminated */
2153}
2154#endif /* HAVE_SYS_UTSNAME_H */
2155
2156/*
2157 * return process ID
2158 */
2159 long
2160mch_get_pid()
2161{
2162 return (long)getpid();
2163}
2164
2165#if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
2166static char *strerror __ARGS((int));
2167
2168 static char *
2169strerror(err)
2170 int err;
2171{
2172 extern int sys_nerr;
2173 extern char *sys_errlist[];
2174 static char er[20];
2175
2176 if (err > 0 && err < sys_nerr)
2177 return (sys_errlist[err]);
2178 sprintf(er, "Error %d", err);
2179 return er;
2180}
2181#endif
2182
2183/*
2184 * Get name of current directory into buffer 'buf' of length 'len' bytes.
2185 * Return OK for success, FAIL for failure.
2186 */
2187 int
2188mch_dirname(buf, len)
2189 char_u *buf;
2190 int len;
2191{
2192#if defined(USE_GETCWD)
2193 if (getcwd((char *)buf, len) == NULL)
2194 {
2195 STRCPY(buf, strerror(errno));
2196 return FAIL;
2197 }
2198 return OK;
2199#else
2200 return (getwd((char *)buf) != NULL ? OK : FAIL);
2201#endif
2202}
2203
2204#if defined(OS2) || defined(PROTO)
2205/*
2206 * Replace all slashes by backslashes.
2207 * When 'shellslash' set do it the other way around.
2208 */
2209 void
2210slash_adjust(p)
2211 char_u *p;
2212{
2213 while (*p)
2214 {
2215 if (*p == psepcN)
2216 *p = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00002217 mb_ptr_adv(p);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002218 }
2219}
2220#endif
2221
2222/*
2223 * Get absolute file name into buffer 'buf' of length 'len' bytes.
2224 *
2225 * return FAIL for failure, OK for success
2226 */
2227 int
2228mch_FullName(fname, buf, len, force)
2229 char_u *fname, *buf;
2230 int len;
2231 int force; /* also expand when already absolute path */
2232{
2233 int l;
2234#ifdef OS2
2235 int only_drive; /* file name is only a drive letter */
2236#endif
2237#ifdef HAVE_FCHDIR
2238 int fd = -1;
2239 static int dont_fchdir = FALSE; /* TRUE when fchdir() doesn't work */
2240#endif
2241 char_u olddir[MAXPATHL];
2242 char_u *p;
2243 int retval = OK;
2244
2245#ifdef VMS
2246 fname = vms_fixfilename(fname);
2247#endif
2248
2249 /* expand it if forced or not an absolute path */
2250 if (force || !mch_isFullName(fname))
2251 {
2252 /*
2253 * If the file name has a path, change to that directory for a moment,
2254 * and then do the getwd() (and get back to where we were).
2255 * This will get the correct path name with "../" things.
2256 */
2257#ifdef OS2
2258 only_drive = 0;
2259 if (((p = vim_strrchr(fname, '/')) != NULL)
2260 || ((p = vim_strrchr(fname, '\\')) != NULL)
2261 || (((p = vim_strchr(fname, ':')) != NULL) && ++only_drive))
2262#else
2263 if ((p = vim_strrchr(fname, '/')) != NULL)
2264#endif
2265 {
2266#ifdef HAVE_FCHDIR
2267 /*
2268 * Use fchdir() if possible, it's said to be faster and more
2269 * reliable. But on SunOS 4 it might not work. Check this by
2270 * doing a fchdir() right now.
2271 */
2272 if (!dont_fchdir)
2273 {
2274 fd = open(".", O_RDONLY | O_EXTRA, 0);
2275 if (fd >= 0 && fchdir(fd) < 0)
2276 {
2277 close(fd);
2278 fd = -1;
2279 dont_fchdir = TRUE; /* don't try again */
2280 }
2281 }
2282#endif
2283
2284 /* Only change directory when we are sure we can return to where
2285 * we are now. After doing "su" chdir(".") might not work. */
2286 if (
2287#ifdef HAVE_FCHDIR
2288 fd < 0 &&
2289#endif
2290 (mch_dirname(olddir, MAXPATHL) == FAIL
2291 || mch_chdir((char *)olddir) != 0))
2292 {
2293 p = NULL; /* can't get current dir: don't chdir */
2294 retval = FAIL;
2295 }
2296 else
2297 {
2298#ifdef OS2
2299 /*
2300 * compensate for case where ':' from "D:" was the only
2301 * path separator detected in the file name; the _next_
2302 * character has to be removed, and then restored later.
2303 */
2304 if (only_drive)
2305 p++;
2306#endif
2307 /* The directory is copied into buf[], to be able to remove
2308 * the file name without changing it (could be a string in
2309 * read-only memory) */
2310 if (p - fname >= len)
2311 retval = FAIL;
2312 else
2313 {
2314 STRNCPY(buf, fname, p - fname);
2315 buf[p - fname] = NUL;
2316 if (mch_chdir((char *)buf))
2317 retval = FAIL;
2318 else
2319 fname = p + 1;
2320 *buf = NUL;
2321 }
2322#ifdef OS2
2323 if (only_drive)
2324 {
2325 p--;
2326 if (retval != FAIL)
2327 fname--;
2328 }
2329#endif
2330 }
2331 }
2332 if (mch_dirname(buf, len) == FAIL)
2333 {
2334 retval = FAIL;
2335 *buf = NUL;
2336 }
2337 if (p != NULL)
2338 {
2339#ifdef HAVE_FCHDIR
2340 if (fd >= 0)
2341 {
2342 l = fchdir(fd);
2343 close(fd);
2344 }
2345 else
2346#endif
2347 l = mch_chdir((char *)olddir);
2348 if (l != 0)
2349 EMSG(_(e_prev_dir));
2350 }
2351
2352 l = STRLEN(buf);
2353 if (l >= len)
2354 retval = FAIL;
2355#ifndef VMS
2356 else
2357 {
2358 if (l > 0 && buf[l - 1] != '/' && *fname != NUL
2359 && STRCMP(fname, ".") != 0)
2360 STRCAT(buf, "/");
2361 }
2362#endif
2363 }
2364 /* Catch file names which are too long. */
2365 if (retval == FAIL || STRLEN(buf) + STRLEN(fname) >= len)
2366 return FAIL;
2367
2368 /* Do not append ".", "/dir/." is equal to "/dir". */
2369 if (STRCMP(fname, ".") != 0)
2370 STRCAT(buf, fname);
2371
2372 return OK;
2373}
2374
2375/*
2376 * Return TRUE if "fname" does not depend on the current directory.
2377 */
2378 int
2379mch_isFullName(fname)
2380 char_u *fname;
2381{
2382#ifdef __EMX__
2383 return _fnisabs(fname);
2384#else
2385# ifdef VMS
2386 return ( fname[0] == '/' || fname[0] == '.' ||
2387 strchr((char *)fname,':') || strchr((char *)fname,'"') ||
2388 (strchr((char *)fname,'[') && strchr((char *)fname,']'))||
2389 (strchr((char *)fname,'<') && strchr((char *)fname,'>')) );
2390# else
2391 return (*fname == '/' || *fname == '~');
2392# endif
2393#endif
2394}
2395
2396/*
2397 * Get file permissions for 'name'.
2398 * Returns -1 when it doesn't exist.
2399 */
2400 long
2401mch_getperm(name)
2402 char_u *name;
2403{
2404 struct stat statb;
2405
2406 /* Keep the #ifdef outside of stat(), it may be a macro. */
2407#ifdef VMS
2408 if (stat((char *)vms_fixfilename(name), &statb))
2409#else
2410 if (stat((char *)name, &statb))
2411#endif
2412 return -1;
2413 return statb.st_mode;
2414}
2415
2416/*
2417 * set file permission for 'name' to 'perm'
2418 *
2419 * return FAIL for failure, OK otherwise
2420 */
2421 int
2422mch_setperm(name, perm)
2423 char_u *name;
2424 long perm;
2425{
2426 return (chmod((char *)
2427#ifdef VMS
2428 vms_fixfilename(name),
2429#else
2430 name,
2431#endif
2432 (mode_t)perm) == 0 ? OK : FAIL);
2433}
2434
2435#if defined(HAVE_ACL) || defined(PROTO)
2436# ifdef HAVE_SYS_ACL_H
2437# include <sys/acl.h>
2438# endif
2439# ifdef HAVE_SYS_ACCESS_H
2440# include <sys/access.h>
2441# endif
2442
2443# ifdef HAVE_SOLARIS_ACL
2444typedef struct vim_acl_solaris_T {
2445 int acl_cnt;
2446 aclent_t *acl_entry;
2447} vim_acl_solaris_T;
2448# endif
2449
2450/*
2451 * Return a pointer to the ACL of file "fname" in allocated memory.
2452 * Return NULL if the ACL is not available for whatever reason.
2453 */
2454 vim_acl_T
2455mch_get_acl(fname)
2456 char_u *fname;
2457{
2458 vim_acl_T ret = NULL;
2459#ifdef HAVE_POSIX_ACL
2460 ret = (vim_acl_T)acl_get_file((char *)fname, ACL_TYPE_ACCESS);
2461#else
2462#ifdef HAVE_SOLARIS_ACL
2463 vim_acl_solaris_T *aclent;
2464
2465 aclent = malloc(sizeof(vim_acl_solaris_T));
2466 if ((aclent->acl_cnt = acl((char *)fname, GETACLCNT, 0, NULL)) < 0)
2467 {
2468 free(aclent);
2469 return NULL;
2470 }
2471 aclent->acl_entry = malloc(aclent->acl_cnt * sizeof(aclent_t));
2472 if (acl((char *)fname, GETACL, aclent->acl_cnt, aclent->acl_entry) < 0)
2473 {
2474 free(aclent->acl_entry);
2475 free(aclent);
2476 return NULL;
2477 }
2478 ret = (vim_acl_T)aclent;
2479#else
2480#if defined(HAVE_AIX_ACL)
2481 int aclsize;
2482 struct acl *aclent;
2483
2484 aclsize = sizeof(struct acl);
2485 aclent = malloc(aclsize);
2486 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2487 {
2488 if (errno == ENOSPC)
2489 {
2490 aclsize = aclent->acl_len;
2491 aclent = realloc(aclent, aclsize);
2492 if (statacl((char *)fname, STX_NORMAL, aclent, aclsize) < 0)
2493 {
2494 free(aclent);
2495 return NULL;
2496 }
2497 }
2498 else
2499 {
2500 free(aclent);
2501 return NULL;
2502 }
2503 }
2504 ret = (vim_acl_T)aclent;
2505#endif /* HAVE_AIX_ACL */
2506#endif /* HAVE_SOLARIS_ACL */
2507#endif /* HAVE_POSIX_ACL */
2508 return ret;
2509}
2510
2511/*
2512 * Set the ACL of file "fname" to "acl" (unless it's NULL).
2513 */
2514 void
2515mch_set_acl(fname, aclent)
2516 char_u *fname;
2517 vim_acl_T aclent;
2518{
2519 if (aclent == NULL)
2520 return;
2521#ifdef HAVE_POSIX_ACL
2522 acl_set_file((char *)fname, ACL_TYPE_ACCESS, (acl_t)aclent);
2523#else
2524#ifdef HAVE_SOLARIS_ACL
2525 acl((char *)fname, SETACL, ((vim_acl_solaris_T *)aclent)->acl_cnt,
2526 ((vim_acl_solaris_T *)aclent)->acl_entry);
2527#else
2528#ifdef HAVE_AIX_ACL
2529 chacl((char *)fname, aclent, ((struct acl *)aclent)->acl_len);
2530#endif /* HAVE_AIX_ACL */
2531#endif /* HAVE_SOLARIS_ACL */
2532#endif /* HAVE_POSIX_ACL */
2533}
2534
2535 void
2536mch_free_acl(aclent)
2537 vim_acl_T aclent;
2538{
2539 if (aclent == NULL)
2540 return;
2541#ifdef HAVE_POSIX_ACL
2542 acl_free((acl_t)aclent);
2543#else
2544#ifdef HAVE_SOLARIS_ACL
2545 free(((vim_acl_solaris_T *)aclent)->acl_entry);
2546 free(aclent);
2547#else
2548#ifdef HAVE_AIX_ACL
2549 free(aclent);
2550#endif /* HAVE_AIX_ACL */
2551#endif /* HAVE_SOLARIS_ACL */
2552#endif /* HAVE_POSIX_ACL */
2553}
2554#endif
2555
2556/*
2557 * Set hidden flag for "name".
2558 */
2559/* ARGSUSED */
2560 void
2561mch_hide(name)
2562 char_u *name;
2563{
2564 /* can't hide a file */
2565}
2566
2567/*
2568 * return TRUE if "name" is a directory
2569 * return FALSE if "name" is not a directory
2570 * return FALSE for error
2571 */
2572 int
2573mch_isdir(name)
2574 char_u *name;
2575{
2576 struct stat statb;
2577
2578 if (*name == NUL) /* Some stat()s don't flag "" as an error. */
2579 return FALSE;
2580 if (stat((char *)name, &statb))
2581 return FALSE;
2582#ifdef _POSIX_SOURCE
2583 return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
2584#else
2585 return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
2586#endif
2587}
2588
2589#if defined(FEAT_EVAL) || defined(PROTO)
2590
2591static int executable_file __ARGS((char_u *name));
2592
2593/*
2594 * Return 1 if "name" is an executable file, 0 if not or it doesn't exist.
2595 */
2596 static int
2597executable_file(name)
2598 char_u *name;
2599{
2600 struct stat st;
2601
2602 if (stat((char *)name, &st))
2603 return 0;
2604 return S_ISREG(st.st_mode) && mch_access((char *)name, X_OK) == 0;
2605}
2606
2607/*
2608 * Return 1 if "name" can be found in $PATH and executed, 0 if not.
2609 * Return -1 if unknown.
2610 */
2611 int
2612mch_can_exe(name)
2613 char_u *name;
2614{
2615 char_u *buf;
2616 char_u *p, *e;
2617 int retval;
2618
2619 /* If it's an absolute or relative path don't need to use $PATH. */
2620 if (mch_isFullName(name) || (name[0] == '.' && (name[1] == '/'
2621 || (name[1] == '.' && name[2] == '/'))))
2622 return executable_file(name);
2623
2624 p = (char_u *)getenv("PATH");
2625 if (p == NULL || *p == NUL)
2626 return -1;
2627 buf = alloc((unsigned)(STRLEN(name) + STRLEN(p) + 2));
2628 if (buf == NULL)
2629 return -1;
2630
2631 /*
2632 * Walk through all entries in $PATH to check if "name" exists there and
2633 * is an executable file.
2634 */
2635 for (;;)
2636 {
2637 e = (char_u *)strchr((char *)p, ':');
2638 if (e == NULL)
2639 e = p + STRLEN(p);
2640 if (e - p <= 1) /* empty entry means current dir */
2641 STRCPY(buf, "./");
2642 else
2643 {
2644 STRNCPY(buf, p, e - p);
2645 buf[e - p] = NUL;
2646 add_pathsep(buf);
2647 }
2648 STRCAT(buf, name);
2649 retval = executable_file(buf);
2650 if (retval == 1)
2651 break;
2652
2653 if (*e != ':')
2654 break;
2655 p = e + 1;
2656 }
2657
2658 vim_free(buf);
2659 return retval;
2660}
2661#endif
2662
2663/*
2664 * Check what "name" is:
2665 * NODE_NORMAL: file or directory (or doesn't exist)
2666 * NODE_WRITABLE: writable device, socket, fifo, etc.
2667 * NODE_OTHER: non-writable things
2668 */
2669 int
2670mch_nodetype(name)
2671 char_u *name;
2672{
2673 struct stat st;
2674
2675 if (stat((char *)name, &st))
2676 return NODE_NORMAL;
2677 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
2678 return NODE_NORMAL;
2679#ifndef OS2
2680 if (S_ISBLK(st.st_mode)) /* block device isn't writable */
2681 return NODE_OTHER;
2682#endif
2683 /* Everything else is writable? */
2684 return NODE_WRITABLE;
2685}
2686
2687 void
2688mch_early_init()
2689{
2690#ifdef HAVE_CHECK_STACK_GROWTH
2691 int i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002692
Bram Moolenaar071d4272004-06-13 20:20:40 +00002693 check_stack_growth((char *)&i);
2694
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00002695# ifdef HAVE_STACK_LIMIT
Bram Moolenaar071d4272004-06-13 20:20:40 +00002696 get_stack_limit();
2697# endif
2698
2699#endif
2700
2701 /*
2702 * Setup an alternative stack for signals. Helps to catch signals when
2703 * running out of stack space.
2704 * Use of sigaltstack() is preferred, it's more portable.
2705 * Ignore any errors.
2706 */
2707#if defined(HAVE_SIGALTSTACK) || defined(HAVE_SIGSTACK)
2708 signal_stack = malloc(SIGSTKSZ);
2709 init_signal_stack();
2710#endif
2711}
2712
2713static void exit_scroll __ARGS((void));
2714
2715/*
2716 * Output a newline when exiting.
2717 * Make sure the newline goes to the same stream as the text.
2718 */
2719 static void
2720exit_scroll()
2721{
Bram Moolenaardf177f62005-02-22 08:39:57 +00002722 if (silent_mode)
2723 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002724 if (newline_on_exit || msg_didout)
2725 {
2726 if (msg_use_printf())
2727 {
2728 if (info_message)
2729 mch_msg("\n");
2730 else
2731 mch_errmsg("\r\n");
2732 }
2733 else
2734 out_char('\n');
2735 }
2736 else
2737 {
2738 restore_cterm_colors(); /* get original colors back */
2739 msg_clr_eos_force(); /* clear the rest of the display */
2740 windgoto((int)Rows - 1, 0); /* may have moved the cursor */
2741 }
2742}
2743
2744 void
2745mch_exit(r)
2746 int r;
2747{
2748 exiting = TRUE;
2749
2750#if defined(FEAT_X11) && defined(FEAT_CLIPBOARD)
2751 x11_export_final_selection();
2752#endif
2753
2754#ifdef FEAT_GUI
2755 if (!gui.in_use)
2756#endif
2757 {
2758 settmode(TMODE_COOK);
2759#ifdef FEAT_TITLE
2760 mch_restore_title(3); /* restore xterm title and icon name */
2761#endif
2762 /*
2763 * When t_ti is not empty but it doesn't cause swapping terminal
2764 * pages, need to output a newline when msg_didout is set. But when
2765 * t_ti does swap pages it should not go to the shell page. Do this
2766 * before stoptermcap().
2767 */
2768 if (swapping_screen() && !newline_on_exit)
2769 exit_scroll();
2770
2771 /* Stop termcap: May need to check for T_CRV response, which
2772 * requires RAW mode. */
2773 stoptermcap();
2774
2775 /*
2776 * A newline is only required after a message in the alternate screen.
2777 * This is set to TRUE by wait_return().
2778 */
2779 if (!swapping_screen() || newline_on_exit)
2780 exit_scroll();
2781
2782 /* Cursor may have been switched off without calling starttermcap()
2783 * when doing "vim -u vimrc" and vimrc contains ":q". */
2784 if (full_screen)
2785 cursor_on();
2786 }
2787 out_flush();
2788 ml_close_all(TRUE); /* remove all memfiles */
2789 may_core_dump();
2790#ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00002791 if (gui.in_use)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002792 gui_exit(r);
2793#endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00002794
2795#if defined(MACOS_X) && defined(FEAT_MBYTE)
2796 mac_conv_cleanup();
2797#endif
2798
Bram Moolenaar071d4272004-06-13 20:20:40 +00002799#ifdef __QNX__
2800 /* A core dump won't be created if the signal handler
2801 * doesn't return, so we can't call exit() */
2802 if (deadly_signal != 0)
2803 return;
2804#endif
2805
Bram Moolenaar009b2592004-10-24 19:18:58 +00002806#ifdef FEAT_NETBEANS_INTG
2807 if (usingNetbeans)
2808 netbeans_send_disconnect();
2809#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002810 exit(r);
2811}
2812
2813 static void
2814may_core_dump()
2815{
2816 if (deadly_signal != 0)
2817 {
2818 signal(deadly_signal, SIG_DFL);
2819 kill(getpid(), deadly_signal); /* Die using the signal we caught */
2820 }
2821}
2822
2823#ifndef VMS
2824
2825 void
2826mch_settmode(tmode)
2827 int tmode;
2828{
2829 static int first = TRUE;
2830
2831 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2832#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2833 /*
2834 * for "new" tty systems
2835 */
2836# ifdef HAVE_TERMIOS_H
2837 static struct termios told;
2838 struct termios tnew;
2839# else
2840 static struct termio told;
2841 struct termio tnew;
2842# endif
2843
2844 if (first)
2845 {
2846 first = FALSE;
2847# if defined(HAVE_TERMIOS_H)
2848 tcgetattr(read_cmd_fd, &told);
2849# else
2850 ioctl(read_cmd_fd, TCGETA, &told);
2851# endif
2852 }
2853
2854 tnew = told;
2855 if (tmode == TMODE_RAW)
2856 {
2857 /*
2858 * ~ICRNL enables typing ^V^M
2859 */
2860 tnew.c_iflag &= ~ICRNL;
2861 tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
2862# if defined(IEXTEN) && !defined(__MINT__)
2863 | IEXTEN /* IEXTEN enables typing ^V on SOLARIS */
2864 /* but it breaks function keys on MINT */
2865# endif
2866 );
2867# ifdef ONLCR /* don't map NL -> CR NL, we do it ourselves */
2868 tnew.c_oflag &= ~ONLCR;
2869# endif
2870 tnew.c_cc[VMIN] = 1; /* return after 1 char */
2871 tnew.c_cc[VTIME] = 0; /* don't wait */
2872 }
2873 else if (tmode == TMODE_SLEEP)
2874 tnew.c_lflag &= ~(ECHO);
2875
2876# if defined(HAVE_TERMIOS_H)
2877 {
2878 int n = 10;
2879
2880 /* A signal may cause tcsetattr() to fail (e.g., SIGCONT). Retry a
2881 * few times. */
2882 while (tcsetattr(read_cmd_fd, TCSANOW, &tnew) == -1
2883 && errno == EINTR && n > 0)
2884 --n;
2885 }
2886# else
2887 ioctl(read_cmd_fd, TCSETA, &tnew);
2888# endif
2889
2890#else
2891
2892 /*
2893 * for "old" tty systems
2894 */
2895# ifndef TIOCSETN
2896# define TIOCSETN TIOCSETP /* for hpux 9.0 */
2897# endif
2898 static struct sgttyb ttybold;
2899 struct sgttyb ttybnew;
2900
2901 if (first)
2902 {
2903 first = FALSE;
2904 ioctl(read_cmd_fd, TIOCGETP, &ttybold);
2905 }
2906
2907 ttybnew = ttybold;
2908 if (tmode == TMODE_RAW)
2909 {
2910 ttybnew.sg_flags &= ~(CRMOD | ECHO);
2911 ttybnew.sg_flags |= RAW;
2912 }
2913 else if (tmode == TMODE_SLEEP)
2914 ttybnew.sg_flags &= ~(ECHO);
2915 ioctl(read_cmd_fd, TIOCSETN, &ttybnew);
2916#endif
2917 curr_tmode = tmode;
2918}
2919
2920/*
2921 * Try to get the code for "t_kb" from the stty setting
2922 *
2923 * Even if termcap claims a backspace key, the user's setting *should*
2924 * prevail. stty knows more about reality than termcap does, and if
2925 * somebody's usual erase key is DEL (which, for most BSD users, it will
2926 * be), they're going to get really annoyed if their erase key starts
2927 * doing forward deletes for no reason. (Eric Fischer)
2928 */
2929 void
2930get_stty()
2931{
2932 char_u buf[2];
2933 char_u *p;
2934
2935 /* Why is NeXT excluded here (and not in os_unixx.h)? */
2936#if defined(ECHOE) && defined(ICANON) && (defined(HAVE_TERMIO_H) || defined(HAVE_TERMIOS_H)) && !defined(__NeXT__)
2937 /* for "new" tty systems */
2938# ifdef HAVE_TERMIOS_H
2939 struct termios keys;
2940# else
2941 struct termio keys;
2942# endif
2943
2944# if defined(HAVE_TERMIOS_H)
2945 if (tcgetattr(read_cmd_fd, &keys) != -1)
2946# else
2947 if (ioctl(read_cmd_fd, TCGETA, &keys) != -1)
2948# endif
2949 {
2950 buf[0] = keys.c_cc[VERASE];
2951 intr_char = keys.c_cc[VINTR];
2952#else
2953 /* for "old" tty systems */
2954 struct sgttyb keys;
2955
2956 if (ioctl(read_cmd_fd, TIOCGETP, &keys) != -1)
2957 {
2958 buf[0] = keys.sg_erase;
2959 intr_char = keys.sg_kill;
2960#endif
2961 buf[1] = NUL;
2962 add_termcode((char_u *)"kb", buf, FALSE);
2963
2964 /*
2965 * If <BS> and <DEL> are now the same, redefine <DEL>.
2966 */
2967 p = find_termcode((char_u *)"kD");
2968 if (p != NULL && p[0] == buf[0] && p[1] == buf[1])
2969 do_fixdel(NULL);
2970 }
2971#if 0
2972 } /* to keep cindent happy */
2973#endif
2974}
2975
2976#endif /* VMS */
2977
2978#if defined(FEAT_MOUSE_TTY) || defined(PROTO)
2979/*
2980 * Set mouse clicks on or off.
2981 */
2982 void
2983mch_setmouse(on)
2984 int on;
2985{
2986 static int ison = FALSE;
2987 int xterm_mouse_vers;
2988
2989 if (on == ison) /* return quickly if nothing to do */
2990 return;
2991
2992 xterm_mouse_vers = use_xterm_mouse();
2993 if (xterm_mouse_vers > 0)
2994 {
2995 if (on) /* enable mouse events, use mouse tracking if available */
2996 out_str_nf((char_u *)
2997 (xterm_mouse_vers > 1
2998 ? IF_EB("\033[?1002h", ESC_STR "[?1002h")
2999 : IF_EB("\033[?1000h", ESC_STR "[?1000h")));
3000 else /* disable mouse events, could probably always send the same */
3001 out_str_nf((char_u *)
3002 (xterm_mouse_vers > 1
3003 ? IF_EB("\033[?1002l", ESC_STR "[?1002l")
3004 : IF_EB("\033[?1000l", ESC_STR "[?1000l")));
3005 ison = on;
3006 }
3007
3008# ifdef FEAT_MOUSE_DEC
3009 else if (ttym_flags == TTYM_DEC)
3010 {
3011 if (on) /* enable mouse events */
3012 out_str_nf((char_u *)"\033[1;2'z\033[1;3'{");
3013 else /* disable mouse events */
3014 out_str_nf((char_u *)"\033['z");
3015 ison = on;
3016 }
3017# endif
3018
3019# ifdef FEAT_MOUSE_GPM
3020 else
3021 {
3022 if (on)
3023 {
3024 if (gpm_open())
3025 ison = TRUE;
3026 }
3027 else
3028 {
3029 gpm_close();
3030 ison = FALSE;
3031 }
3032 }
3033# endif
3034
3035# ifdef FEAT_MOUSE_JSB
3036 else
3037 {
3038 if (on)
3039 {
3040 /* D - Enable Mouse up/down messages
3041 * L - Enable Left Button Reporting
3042 * M - Enable Middle Button Reporting
3043 * R - Enable Right Button Reporting
3044 * K - Enable SHIFT and CTRL key Reporting
3045 * + - Enable Advanced messaging of mouse moves and up/down messages
3046 * Q - Quiet No Ack
3047 * # - Numeric value of mouse pointer required
3048 * 0 = Multiview 2000 cursor, used as standard
3049 * 1 = Windows Arrow
3050 * 2 = Windows I Beam
3051 * 3 = Windows Hour Glass
3052 * 4 = Windows Cross Hair
3053 * 5 = Windows UP Arrow
3054 */
3055#ifdef JSBTERM_MOUSE_NONADVANCED /* Disables full feedback of pointer movements */
3056 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK1Q\033\\",
3057 ESC_STR "[0~ZwLMRK1Q" ESC_STR "\\"));
3058#else
3059 out_str_nf((char_u *)IF_EB("\033[0~ZwLMRK+1Q\033\\",
3060 ESC_STR "[0~ZwLMRK+1Q" ESC_STR "\\"));
3061#endif
3062 ison = TRUE;
3063 }
3064 else
3065 {
3066 out_str_nf((char_u *)IF_EB("\033[0~ZwQ\033\\",
3067 ESC_STR "[0~ZwQ" ESC_STR "\\"));
3068 ison = FALSE;
3069 }
3070 }
3071# endif
3072# ifdef FEAT_MOUSE_PTERM
3073 else
3074 {
3075 /* 1 = button press, 6 = release, 7 = drag, 1h...9l = right button */
3076 if (on)
3077 out_str_nf("\033[>1h\033[>6h\033[>7h\033[>1h\033[>9l");
3078 else
3079 out_str_nf("\033[>1l\033[>6l\033[>7l\033[>1l\033[>9h");
3080 ison = on;
3081 }
3082# endif
3083}
3084
3085/*
3086 * Set the mouse termcode, depending on the 'term' and 'ttymouse' options.
3087 */
3088 void
3089check_mouse_termcode()
3090{
3091# ifdef FEAT_MOUSE_XTERM
3092 if (use_xterm_mouse()
3093# ifdef FEAT_GUI
3094 && !gui.in_use
3095# endif
3096 )
3097 {
3098 set_mouse_termcode(KS_MOUSE, (char_u *)(term_is_8bit(T_NAME)
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003099 ? IF_EB("\233M", CSI_STR "M")
3100 : IF_EB("\033[M", ESC_STR "[M")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003101 if (*p_mouse != NUL)
3102 {
3103 /* force mouse off and maybe on to send possibly new mouse
3104 * activation sequence to the xterm, with(out) drag tracing. */
3105 mch_setmouse(FALSE);
3106 setmouse();
3107 }
3108 }
3109 else
3110 del_mouse_termcode(KS_MOUSE);
3111# endif
3112
3113# ifdef FEAT_MOUSE_GPM
3114 if (!use_xterm_mouse()
3115# ifdef FEAT_GUI
3116 && !gui.in_use
3117# endif
3118 )
3119 set_mouse_termcode(KS_MOUSE, (char_u *)IF_EB("\033MG", ESC_STR "MG"));
3120# endif
3121
3122# ifdef FEAT_MOUSE_JSB
3123 /* conflicts with xterm mouse: "\033[" and "\033[M" ??? */
3124 if (!use_xterm_mouse()
3125# ifdef FEAT_GUI
3126 && !gui.in_use
3127# endif
3128 )
3129 set_mouse_termcode(KS_JSBTERM_MOUSE,
3130 (char_u *)IF_EB("\033[0~zw", ESC_STR "[0~zw"));
3131 else
3132 del_mouse_termcode(KS_JSBTERM_MOUSE);
3133# endif
3134
3135# ifdef FEAT_MOUSE_NET
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003136 /* There is no conflict, but one may type "ESC }" from Insert mode. Don't
Bram Moolenaar071d4272004-06-13 20:20:40 +00003137 * define it in the GUI or when using an xterm. */
3138 if (!use_xterm_mouse()
3139# ifdef FEAT_GUI
3140 && !gui.in_use
3141# endif
3142 )
3143 set_mouse_termcode(KS_NETTERM_MOUSE,
3144 (char_u *)IF_EB("\033}", ESC_STR "}"));
3145 else
3146 del_mouse_termcode(KS_NETTERM_MOUSE);
3147# endif
3148
3149# ifdef FEAT_MOUSE_DEC
3150 /* conflicts with xterm mouse: "\033[" and "\033[M" */
3151 if (!use_xterm_mouse()
3152# ifdef FEAT_GUI
3153 && !gui.in_use
3154# endif
3155 )
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00003156 set_mouse_termcode(KS_DEC_MOUSE, (char_u *)(term_is_8bit(T_NAME)
3157 ? IF_EB("\233", CSI_STR) : IF_EB("\033[", ESC_STR "[")));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003158 else
3159 del_mouse_termcode(KS_DEC_MOUSE);
3160# endif
3161# ifdef FEAT_MOUSE_PTERM
3162 /* same as the dec mouse */
3163 if (!use_xterm_mouse()
3164# ifdef FEAT_GUI
3165 && !gui.in_use
3166# endif
3167 )
3168 set_mouse_termcode(KS_PTERM_MOUSE,
3169 (char_u *) IF_EB("\033[", ESC_STR "["));
3170 else
3171 del_mouse_termcode(KS_PTERM_MOUSE);
3172# endif
3173}
3174#endif
3175
3176/*
3177 * set screen mode, always fails.
3178 */
3179/* ARGSUSED */
3180 int
3181mch_screenmode(arg)
3182 char_u *arg;
3183{
3184 EMSG(_(e_screenmode));
3185 return FAIL;
3186}
3187
3188#ifndef VMS
3189
3190/*
3191 * Try to get the current window size:
3192 * 1. with an ioctl(), most accurate method
3193 * 2. from the environment variables LINES and COLUMNS
3194 * 3. from the termcap
3195 * 4. keep using the old values
3196 * Return OK when size could be determined, FAIL otherwise.
3197 */
3198 int
3199mch_get_shellsize()
3200{
3201 long rows = 0;
3202 long columns = 0;
3203 char_u *p;
3204
3205 /*
3206 * For OS/2 use _scrsize().
3207 */
3208# ifdef __EMX__
3209 {
3210 int s[2];
3211
3212 _scrsize(s);
3213 columns = s[0];
3214 rows = s[1];
3215 }
3216# endif
3217
3218 /*
3219 * 1. try using an ioctl. It is the most accurate method.
3220 *
3221 * Try using TIOCGWINSZ first, some systems that have it also define
3222 * TIOCGSIZE but don't have a struct ttysize.
3223 */
3224# ifdef TIOCGWINSZ
3225 {
3226 struct winsize ws;
3227 int fd = 1;
3228
3229 /* When stdout is not a tty, use stdin for the ioctl(). */
3230 if (!isatty(fd) && isatty(read_cmd_fd))
3231 fd = read_cmd_fd;
3232 if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
3233 {
3234 columns = ws.ws_col;
3235 rows = ws.ws_row;
3236 }
3237 }
3238# else /* TIOCGWINSZ */
3239# ifdef TIOCGSIZE
3240 {
3241 struct ttysize ts;
3242 int fd = 1;
3243
3244 /* When stdout is not a tty, use stdin for the ioctl(). */
3245 if (!isatty(fd) && isatty(read_cmd_fd))
3246 fd = read_cmd_fd;
3247 if (ioctl(fd, TIOCGSIZE, &ts) == 0)
3248 {
3249 columns = ts.ts_cols;
3250 rows = ts.ts_lines;
3251 }
3252 }
3253# endif /* TIOCGSIZE */
3254# endif /* TIOCGWINSZ */
3255
3256 /*
3257 * 2. get size from environment
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003258 * When being POSIX compliant ('|' flag in 'cpoptions') this overrules
3259 * the ioctl() values!
Bram Moolenaar071d4272004-06-13 20:20:40 +00003260 */
Bram Moolenaar4399ef42005-02-12 14:29:27 +00003261 if (columns == 0 || rows == 0 || vim_strchr(p_cpo, CPO_TSIZE) != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003262 {
3263 if ((p = (char_u *)getenv("LINES")))
3264 rows = atoi((char *)p);
3265 if ((p = (char_u *)getenv("COLUMNS")))
3266 columns = atoi((char *)p);
3267 }
3268
3269#ifdef HAVE_TGETENT
3270 /*
3271 * 3. try reading "co" and "li" entries from termcap
3272 */
3273 if (columns == 0 || rows == 0)
3274 getlinecol(&columns, &rows);
3275#endif
3276
3277 /*
3278 * 4. If everything fails, use the old values
3279 */
3280 if (columns <= 0 || rows <= 0)
3281 return FAIL;
3282
3283 Rows = rows;
3284 Columns = columns;
3285 return OK;
3286}
3287
3288/*
3289 * Try to set the window size to Rows and Columns.
3290 */
3291 void
3292mch_set_shellsize()
3293{
3294 if (*T_CWS)
3295 {
3296 /*
3297 * NOTE: if you get an error here that term_set_winsize() is
3298 * undefined, check the output of configure. It could probably not
3299 * find a ncurses, termcap or termlib library.
3300 */
3301 term_set_winsize((int)Rows, (int)Columns);
3302 out_flush();
3303 screen_start(); /* don't know where cursor is now */
3304 }
3305}
3306
3307#endif /* VMS */
3308
3309/*
3310 * Rows and/or Columns has changed.
3311 */
3312 void
3313mch_new_shellsize()
3314{
3315 /* Nothing to do. */
3316}
3317
Bram Moolenaardf177f62005-02-22 08:39:57 +00003318#ifndef USE_SYSTEM
3319static void append_ga_line __ARGS((garray_T *gap));
3320
3321/*
3322 * Append the text in "gap" below the cursor line and clear "gap".
3323 */
3324 static void
3325append_ga_line(gap)
3326 garray_T *gap;
3327{
3328 /* Remove trailing CR. */
3329 if (gap->ga_len > 0
3330 && !curbuf->b_p_bin
3331 && ((char_u *)gap->ga_data)[gap->ga_len - 1] == CAR)
3332 --gap->ga_len;
3333 ga_append(gap, NUL);
3334 ml_append(curwin->w_cursor.lnum++, gap->ga_data, 0, FALSE);
3335 gap->ga_len = 0;
3336}
3337#endif
3338
Bram Moolenaar071d4272004-06-13 20:20:40 +00003339 int
3340mch_call_shell(cmd, options)
3341 char_u *cmd;
3342 int options; /* SHELL_*, see vim.h */
3343{
3344#ifdef VMS
3345 char *ifn = NULL;
3346 char *ofn = NULL;
3347#endif
3348 int tmode = cur_tmode;
3349#ifdef USE_SYSTEM /* use system() to start the shell: simple but slow */
3350 int x;
3351# ifndef __EMX__
3352 char_u *newcmd; /* only needed for unix */
3353# else
3354 /*
3355 * Set the preferred shell in the EMXSHELL environment variable (but
3356 * only if it is different from what is already in the environment).
3357 * Emx then takes care of whether to use "/c" or "-c" in an
3358 * intelligent way. Simply pass the whole thing to emx's system() call.
3359 * Emx also starts an interactive shell if system() is passed an empty
3360 * string.
3361 */
3362 char_u *p, *old;
3363
3364 if (((old = (char_u *)getenv("EMXSHELL")) == NULL) || STRCMP(old, p_sh))
3365 {
3366 /* should check HAVE_SETENV, but I know we don't have it. */
3367 p = alloc(10 + strlen(p_sh));
3368 if (p)
3369 {
3370 sprintf((char *)p, "EMXSHELL=%s", p_sh);
3371 putenv((char *)p); /* don't free the pointer! */
3372 }
3373 }
3374# endif
3375
3376 out_flush();
3377
3378 if (options & SHELL_COOKED)
3379 settmode(TMODE_COOK); /* set to normal mode */
3380
3381# ifdef __EMX__
3382 if (cmd == NULL)
3383 x = system(""); /* this starts an interactive shell in emx */
3384 else
3385 x = system((char *)cmd);
3386 /* system() returns -1 when error occurs in starting shell */
3387 if (x == -1 && !emsg_silent)
3388 {
3389 MSG_PUTS(_("\nCannot execute shell "));
3390 msg_outtrans(p_sh);
3391 msg_putchar('\n');
3392 }
3393# else /* not __EMX__ */
3394 if (cmd == NULL)
3395 x = system((char *)p_sh);
3396 else
3397 {
3398# ifdef VMS
3399 if (ofn = strchr((char *)cmd, '>'))
3400 *ofn++ = '\0';
3401 if (ifn = strchr((char *)cmd, '<'))
3402 {
3403 char *p;
3404
3405 *ifn++ = '\0';
3406 p = strchr(ifn,' '); /* chop off any trailing spaces */
3407 if (p)
3408 *p = '\0';
3409 }
3410 if (ofn)
3411 x = vms_sys((char *)cmd, ofn, ifn);
3412 else
3413 x = system((char *)cmd);
3414# else
3415 newcmd = lalloc(STRLEN(p_sh)
3416 + (extra_shell_arg == NULL ? 0 : STRLEN(extra_shell_arg))
3417 + STRLEN(p_shcf) + STRLEN(cmd) + 4, TRUE);
3418 if (newcmd == NULL)
3419 x = 0;
3420 else
3421 {
3422 sprintf((char *)newcmd, "%s %s %s %s", p_sh,
3423 extra_shell_arg == NULL ? "" : (char *)extra_shell_arg,
3424 (char *)p_shcf,
3425 (char *)cmd);
3426 x = system((char *)newcmd);
3427 vim_free(newcmd);
3428 }
3429# endif
3430 }
3431# ifdef VMS
3432 x = vms_sys_status(x);
3433# endif
3434 if (emsg_silent)
3435 ;
3436 else if (x == 127)
3437 MSG_PUTS(_("\nCannot execute shell sh\n"));
3438# endif /* __EMX__ */
3439 else if (x && !(options & SHELL_SILENT))
3440 {
3441 MSG_PUTS(_("\nshell returned "));
3442 msg_outnum((long)x);
3443 msg_putchar('\n');
3444 }
3445
3446 if (tmode == TMODE_RAW)
3447 settmode(TMODE_RAW); /* set to raw mode */
3448# ifdef FEAT_TITLE
3449 resettitle();
3450# endif
3451 return x;
3452
3453#else /* USE_SYSTEM */ /* don't use system(), use fork()/exec() */
3454
Bram Moolenaardf177f62005-02-22 08:39:57 +00003455# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
3456 127, some shells use that already */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003457
3458 char_u *newcmd = NULL;
3459 pid_t pid;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003460 pid_t wpid = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003461 pid_t wait_pid = 0;
3462# ifdef HAVE_UNION_WAIT
3463 union wait status;
3464# else
3465 int status = -1;
3466# endif
3467 int retval = -1;
3468 char **argv = NULL;
3469 int argc;
3470 int i;
3471 char_u *p;
3472 int inquote;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003473 int pty_master_fd = -1; /* for pty's */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003474# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003475 int pty_slave_fd = -1;
3476 char *tty_name;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003477# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003478 int fd_toshell[2]; /* for pipes */
3479 int fd_fromshell[2];
3480 int pipe_error = FALSE;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003481# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003482 char envbuf[50];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003483# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484 static char envbuf_Rows[20];
3485 static char envbuf_Columns[20];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003486# endif
3487 int did_settmode = FALSE; /* TRUE when settmode(TMODE_RAW) called */
3488
3489 out_flush();
3490 if (options & SHELL_COOKED)
3491 settmode(TMODE_COOK); /* set to normal mode */
3492
3493 /*
3494 * 1: find number of arguments
3495 * 2: separate them and built argv[]
3496 */
3497 newcmd = vim_strsave(p_sh);
3498 if (newcmd == NULL) /* out of memory */
3499 goto error;
3500 for (i = 0; i < 2; ++i)
3501 {
3502 p = newcmd;
3503 inquote = FALSE;
3504 argc = 0;
3505 for (;;)
3506 {
3507 if (i == 1)
3508 argv[argc] = (char *)p;
3509 ++argc;
3510 while (*p && (inquote || (*p != ' ' && *p != TAB)))
3511 {
3512 if (*p == '"')
3513 inquote = !inquote;
3514 ++p;
3515 }
3516 if (*p == NUL)
3517 break;
3518 if (i == 1)
3519 *p++ = NUL;
3520 p = skipwhite(p);
3521 }
3522 if (i == 0)
3523 {
3524 argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
3525 if (argv == NULL) /* out of memory */
3526 goto error;
3527 }
3528 }
3529 if (cmd != NULL)
3530 {
3531 if (extra_shell_arg != NULL)
3532 argv[argc++] = (char *)extra_shell_arg;
3533 argv[argc++] = (char *)p_shcf;
3534 argv[argc++] = (char *)cmd;
3535 }
3536 argv[argc] = NULL;
3537
Bram Moolenaar071d4272004-06-13 20:20:40 +00003538 /*
Bram Moolenaardf177f62005-02-22 08:39:57 +00003539 * For the GUI, when writing the output into the buffer and when reading
3540 * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
3541 * of the executed command into the Vim window. Or use a pipe.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003542 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003543 if ((options & (SHELL_READ|SHELL_WRITE))
3544# ifdef FEAT_GUI
3545 || (gui.in_use && show_shell_mess)
3546# endif
3547 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003549# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003550 /*
3551 * Try to open a master pty.
3552 * If this works, open the slave pty.
3553 * If the slave can't be opened, close the master pty.
3554 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003555 if (p_guipty && !(options & (SHELL_READ|SHELL_WRITE)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003556 {
3557 pty_master_fd = OpenPTY(&tty_name); /* open pty */
3558 if (pty_master_fd >= 0 && ((pty_slave_fd =
3559 open(tty_name, O_RDWR | O_EXTRA, 0)) < 0))
3560 {
3561 close(pty_master_fd);
3562 pty_master_fd = -1;
3563 }
3564 }
3565 /*
3566 * If not opening a pty or it didn't work, try using pipes.
3567 */
3568 if (pty_master_fd < 0)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003569# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003570 {
3571 pipe_error = (pipe(fd_toshell) < 0);
3572 if (!pipe_error) /* pipe create OK */
3573 {
3574 pipe_error = (pipe(fd_fromshell) < 0);
3575 if (pipe_error) /* pipe create failed */
3576 {
3577 close(fd_toshell[0]);
3578 close(fd_toshell[1]);
3579 }
3580 }
3581 if (pipe_error)
3582 {
3583 MSG_PUTS(_("\nCannot create pipes\n"));
3584 out_flush();
3585 }
3586 }
3587 }
3588
3589 if (!pipe_error) /* pty or pipe opened or not used */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590 {
3591# ifdef __BEOS__
3592 beos_cleanup_read_thread();
3593# endif
3594 if ((pid = fork()) == -1) /* maybe we should use vfork() */
3595 {
3596 MSG_PUTS(_("\nCannot fork\n"));
Bram Moolenaardf177f62005-02-22 08:39:57 +00003597 if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003598# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003599 || (gui.in_use && show_shell_mess)
3600# endif
3601 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003602 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003603# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003604 if (pty_master_fd >= 0) /* close the pseudo tty */
3605 {
3606 close(pty_master_fd);
3607 close(pty_slave_fd);
3608 }
3609 else /* close the pipes */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003610# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003611 {
3612 close(fd_toshell[0]);
3613 close(fd_toshell[1]);
3614 close(fd_fromshell[0]);
3615 close(fd_fromshell[1]);
3616 }
3617 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003618 }
3619 else if (pid == 0) /* child */
3620 {
3621 reset_signals(); /* handle signals normally */
3622
3623 if (!show_shell_mess || (options & SHELL_EXPAND))
3624 {
3625 int fd;
3626
3627 /*
3628 * Don't want to show any message from the shell. Can't just
3629 * close stdout and stderr though, because some systems will
3630 * break if you try to write to them after that, so we must
3631 * use dup() to replace them with something else -- webb
3632 * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
3633 * waiting for input.
3634 */
3635 fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
3636 fclose(stdin);
3637 fclose(stdout);
3638 fclose(stderr);
3639
3640 /*
3641 * If any of these open()'s and dup()'s fail, we just continue
3642 * anyway. It's not fatal, and on most systems it will make
3643 * no difference at all. On a few it will cause the execvp()
3644 * to exit with a non-zero status even when the completion
3645 * could be done, which is nothing too serious. If the open()
3646 * or dup() failed we'd just do the same thing ourselves
3647 * anyway -- webb
3648 */
3649 if (fd >= 0)
3650 {
3651 dup(fd); /* To replace stdin (file descriptor 0) */
3652 dup(fd); /* To replace stdout (file descriptor 1) */
3653 dup(fd); /* To replace stderr (file descriptor 2) */
3654
3655 /* Don't need this now that we've duplicated it */
3656 close(fd);
3657 }
3658 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003659 else if ((options & (SHELL_READ|SHELL_WRITE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003660# ifdef FEAT_GUI
Bram Moolenaardf177f62005-02-22 08:39:57 +00003661 || gui.in_use
3662# endif
3663 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003664 {
3665
Bram Moolenaardf177f62005-02-22 08:39:57 +00003666# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667 (void)setsid();
Bram Moolenaardf177f62005-02-22 08:39:57 +00003668# endif
3669# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003670 /* push stream discipline modules */
3671 if (options & SHELL_COOKED)
3672 SetupSlavePTY(pty_slave_fd);
3673# ifdef TIOCSCTTY
3674 /* try to become controlling tty (probably doesn't work,
3675 * unless run by root) */
3676 ioctl(pty_slave_fd, TIOCSCTTY, (char *)NULL);
3677# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003678# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003679 /* Simulate to have a dumb terminal (for now) */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003680# ifdef HAVE_SETENV
Bram Moolenaar071d4272004-06-13 20:20:40 +00003681 setenv("TERM", "dumb", 1);
3682 sprintf((char *)envbuf, "%ld", Rows);
3683 setenv("ROWS", (char *)envbuf, 1);
3684 sprintf((char *)envbuf, "%ld", Rows);
3685 setenv("LINES", (char *)envbuf, 1);
3686 sprintf((char *)envbuf, "%ld", Columns);
3687 setenv("COLUMNS", (char *)envbuf, 1);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003688# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003689 /*
3690 * Putenv does not copy the string, it has to remain valid.
3691 * Use a static array to avoid loosing allocated memory.
3692 */
3693 putenv("TERM=dumb");
3694 sprintf(envbuf_Rows, "ROWS=%ld", Rows);
3695 putenv(envbuf_Rows);
3696 sprintf(envbuf_Rows, "LINES=%ld", Rows);
3697 putenv(envbuf_Rows);
3698 sprintf(envbuf_Columns, "COLUMNS=%ld", Columns);
3699 putenv(envbuf_Columns);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003700# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003701
Bram Moolenaardf177f62005-02-22 08:39:57 +00003702# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003703 if (pty_master_fd >= 0)
3704 {
3705 close(pty_master_fd); /* close master side of pty */
3706
3707 /* set up stdin/stdout/stderr for the child */
3708 close(0);
3709 dup(pty_slave_fd);
3710 close(1);
3711 dup(pty_slave_fd);
3712 close(2);
3713 dup(pty_slave_fd);
3714
3715 close(pty_slave_fd); /* has been dupped, close it now */
3716 }
3717 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003718# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003719 {
3720 /* set up stdin for the child */
3721 close(fd_toshell[1]);
3722 close(0);
3723 dup(fd_toshell[0]);
3724 close(fd_toshell[0]);
3725
3726 /* set up stdout for the child */
3727 close(fd_fromshell[0]);
3728 close(1);
3729 dup(fd_fromshell[1]);
3730 close(fd_fromshell[1]);
3731
3732 /* set up stderr for the child */
3733 close(2);
3734 dup(1);
3735 }
3736 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003737
Bram Moolenaar071d4272004-06-13 20:20:40 +00003738 /*
3739 * There is no type cast for the argv, because the type may be
3740 * different on different machines. This may cause a warning
3741 * message with strict compilers, don't worry about it.
3742 * Call _exit() instead of exit() to avoid closing the connection
3743 * to the X server (esp. with GTK, which uses atexit()).
3744 */
3745 execvp(argv[0], argv);
3746 _exit(EXEC_FAILED); /* exec failed, return failure code */
3747 }
3748 else /* parent */
3749 {
3750 /*
3751 * While child is running, ignore terminating signals.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003752 * Do catch CTRL-C, so that "got_int" is set.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003753 */
3754 catch_signals(SIG_IGN, SIG_ERR);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003755 catch_int_signal();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003756
3757 /*
3758 * For the GUI we redirect stdin, stdout and stderr to our window.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003759 * This is also used to pipe stdin/stdout to/from the external
3760 * command.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003761 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003762 if ((options & (SHELL_READ|SHELL_WRITE))
3763# ifdef FEAT_GUI
3764 || (gui.in_use && show_shell_mess)
3765# endif
3766 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00003767 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003768# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003769 char_u buffer[BUFLEN + 1];
Bram Moolenaardf177f62005-02-22 08:39:57 +00003770# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003771 int buffer_off = 0; /* valid bytes in buffer[] */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003772# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003773 char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
3774 int ta_len = 0; /* valid bytes in ta_buf[] */
3775 int len;
3776 int p_more_save;
3777 int old_State;
3778 int c;
3779 int toshell_fd;
3780 int fromshell_fd;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003781 garray_T ga;
3782 int noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003783
Bram Moolenaardf177f62005-02-22 08:39:57 +00003784# ifdef FEAT_GUI
Bram Moolenaar071d4272004-06-13 20:20:40 +00003785 if (pty_master_fd >= 0)
3786 {
3787 close(pty_slave_fd); /* close slave side of pty */
3788 fromshell_fd = pty_master_fd;
3789 toshell_fd = dup(pty_master_fd);
3790 }
3791 else
Bram Moolenaardf177f62005-02-22 08:39:57 +00003792# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003793 {
3794 close(fd_toshell[0]);
3795 close(fd_fromshell[1]);
3796 toshell_fd = fd_toshell[1];
3797 fromshell_fd = fd_fromshell[0];
3798 }
3799
3800 /*
3801 * Write to the child if there are typed characters.
3802 * Read from the child if there are characters available.
3803 * Repeat the reading a few times if more characters are
3804 * available. Need to check for typed keys now and then, but
3805 * not too often (delays when no chars are available).
3806 * This loop is quit if no characters can be read from the pty
3807 * (WaitForChar detected special condition), or there are no
3808 * characters available and the child has exited.
3809 * Only check if the child has exited when there is no more
3810 * output. The child may exit before all the output has
3811 * been printed.
3812 *
3813 * Currently this busy loops!
3814 * This can probably dead-lock when the write blocks!
3815 */
3816 p_more_save = p_more;
3817 p_more = FALSE;
3818 old_State = State;
3819 State = EXTERNCMD; /* don't redraw at window resize */
3820
Bram Moolenaardf177f62005-02-22 08:39:57 +00003821 if (options & SHELL_WRITE && toshell_fd >= 0)
3822 {
3823 /* Fork a process that will write the lines to the
3824 * external program. */
3825 if ((wpid = fork()) == -1)
3826 {
3827 MSG_PUTS(_("\nCannot fork\n"));
3828 }
3829 else if (wpid == 0)
3830 {
3831 linenr_T lnum = curbuf->b_op_start.lnum;
3832 int written = 0;
3833 char_u *p = ml_get(lnum);
3834 char_u *s;
3835 size_t l;
3836
3837 /* child */
Bram Moolenaar8cd06ca2005-02-28 22:44:58 +00003838 close(fromshell_fd);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003839 for (;;)
3840 {
3841 l = STRLEN(p + written);
3842 if (l == 0)
3843 len = 0;
3844 else if (p[written] == NL)
3845 /* NL -> NUL translation */
3846 len = write(toshell_fd, "", (size_t)1);
3847 else
3848 {
3849 s = vim_strchr(p + written, NL);
3850 len = write(toshell_fd, (char *)p + written,
3851 s == NULL ? l : s - (p + written));
3852 }
3853 if (len == l)
3854 {
3855 /* Finished a line, add a NL, unless this line
3856 * should not have one. */
3857 if (lnum != curbuf->b_op_end.lnum
3858 || !curbuf->b_p_bin
3859 || (lnum != write_no_eol_lnum
3860 && (lnum !=
3861 curbuf->b_ml.ml_line_count
3862 || curbuf->b_p_eol)))
3863 write(toshell_fd, "\n", (size_t)1);
3864 ++lnum;
3865 if (lnum > curbuf->b_op_end.lnum)
3866 {
3867 /* finished all the lines, close pipe */
3868 close(toshell_fd);
3869 toshell_fd = -1;
3870 break;
3871 }
3872 p = ml_get(lnum);
3873 written = 0;
3874 }
3875 else if (len > 0)
3876 written += len;
3877 }
3878 _exit(0);
3879 }
3880 else
3881 {
3882 close(toshell_fd);
3883 toshell_fd = -1;
3884 }
3885 }
3886
3887 if (options & SHELL_READ)
3888 ga_init2(&ga, 1, BUFLEN);
3889
3890 noread_cnt = 0;
3891
Bram Moolenaar071d4272004-06-13 20:20:40 +00003892 for (;;)
3893 {
3894 /*
3895 * Check if keys have been typed, write them to the child
3896 * if there are any. Don't do this if we are expanding
3897 * wild cards (would eat typeahead). Don't get extra
3898 * characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003899 * Don't read characters unless we didn't get output for a
3900 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003901 */
3902 len = 0;
3903 if (!(options & SHELL_EXPAND)
3904 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00003905 || (noread_cnt > 4
3906 && (len = ui_inchar(ta_buf,
3907 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003908 {
3909 /*
3910 * For pipes:
3911 * Check for CTRL-C: send interrupt signal to child.
3912 * Check for CTRL-D: EOF, close pipe to child.
3913 */
3914 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
3915 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003916# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003917 /*
3918 * Send SIGINT to the child's group or all
3919 * processes in our group.
3920 */
3921 if (ta_buf[ta_len] == Ctrl_C
3922 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003923 {
3924# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00003925 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003926# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003928# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003929 if (wpid > 0)
3930 kill(wpid, SIGINT);
3931 }
3932# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003933 if (pty_master_fd < 0 && toshell_fd >= 0
3934 && ta_buf[ta_len] == Ctrl_D)
3935 {
3936 close(toshell_fd);
3937 toshell_fd = -1;
3938 }
3939 }
3940
3941 /* replace K_BS by <BS> and K_DEL by <DEL> */
3942 for (i = ta_len; i < ta_len + len; ++i)
3943 {
3944 if (ta_buf[i] == CSI && len - i > 2)
3945 {
3946 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
3947 if (c == K_DEL || c == K_KDEL || c == K_BS)
3948 {
3949 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
3950 (size_t)(len - i - 2));
3951 if (c == K_DEL || c == K_KDEL)
3952 ta_buf[i] = DEL;
3953 else
3954 ta_buf[i] = Ctrl_H;
3955 len -= 2;
3956 }
3957 }
3958 else if (ta_buf[i] == '\r')
3959 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00003960# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003961 if (has_mbyte)
3962 i += (*mb_ptr2len_check)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003963# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003964 }
3965
3966 /*
3967 * For pipes: echo the typed characters.
3968 * For a pty this does not seem to work.
3969 */
3970 if (pty_master_fd < 0)
3971 {
3972 for (i = ta_len; i < ta_len + len; ++i)
3973 {
3974 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
3975 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003976# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003977 else if (has_mbyte)
3978 {
3979 int l = (*mb_ptr2len_check)(ta_buf + i);
3980
3981 msg_outtrans_len(ta_buf + i, l);
3982 i += l - 1;
3983 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003984# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003985 else
3986 msg_outtrans_len(ta_buf + i, 1);
3987 }
3988 windgoto(msg_row, msg_col);
3989 out_flush();
3990 }
3991
3992 ta_len += len;
3993
3994 /*
3995 * Write the characters to the child, unless EOF has
3996 * been typed for pipes. Write one character at a
3997 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003998 * When writing buffer lines, drop the typed
3999 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00004000 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004001 if (options & SHELL_WRITE)
4002 ta_len = 0;
4003 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004004 {
4005 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4006 if (len > 0)
4007 {
4008 ta_len -= len;
4009 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004010 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004011 }
4012 }
4013 }
4014
Bram Moolenaardf177f62005-02-22 08:39:57 +00004015 if (got_int)
4016 {
4017 /* CTRL-C sends a signal to the child, we ignore it
4018 * ourselves */
4019# ifdef HAVE_SETSID
4020 kill(-pid, SIGINT);
4021# else
4022 kill(0, SIGINT);
4023# endif
4024 if (wpid > 0)
4025 kill(wpid, SIGINT);
4026 got_int = FALSE;
4027 }
4028
Bram Moolenaar071d4272004-06-13 20:20:40 +00004029 /*
4030 * Check if the child has any characters to be printed.
4031 * Read them and write them to our window. Repeat this as
4032 * long as there is something to do, avoid the 10ms wait
4033 * for mch_inchar(), or sending typeahead characters to
4034 * the external process.
4035 * TODO: This should handle escape sequences, compatible
4036 * to some terminal (vt52?).
4037 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004038 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004039 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4040 {
4041 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004042# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004043 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004044# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004045 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004046# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004047 );
4048 if (len <= 0) /* end of file or error */
4049 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004050
4051 noread_cnt = 0;
4052 if (options & SHELL_READ)
4053 {
4054 /* Do NUL -> NL translation, append NL separated
4055 * lines to the current buffer. */
4056 for (i = 0; i < len; ++i)
4057 {
4058 if (buffer[i] == NL)
4059 append_ga_line(&ga);
4060 else if (buffer[i] == NUL)
4061 ga_append(&ga, NL);
4062 else
4063 ga_append(&ga, buffer[i]);
4064 }
4065 }
4066# ifdef FEAT_MBYTE
4067 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004068 {
4069 int l;
4070
Bram Moolenaardf177f62005-02-22 08:39:57 +00004071 len += buffer_off;
4072 buffer[len] = NUL;
4073
Bram Moolenaar071d4272004-06-13 20:20:40 +00004074 /* Check if the last character in buffer[] is
4075 * incomplete, keep these bytes for the next
4076 * round. */
4077 for (p = buffer; p < buffer + len; p += l)
4078 {
4079 if (enc_utf8) /* exclude composing chars */
4080 l = utf_ptr2len_check(p);
4081 else
4082 l = (*mb_ptr2len_check)(p);
4083 if (l == 0)
4084 l = 1; /* NUL byte? */
4085 else if (MB_BYTE2LEN(*p) != l)
4086 break;
4087 }
4088 if (p == buffer) /* no complete character */
4089 {
4090 /* avoid getting stuck at an illegal byte */
4091 if (len >= 12)
4092 ++p;
4093 else
4094 {
4095 buffer_off = len;
4096 continue;
4097 }
4098 }
4099 c = *p;
4100 *p = NUL;
4101 msg_puts(buffer);
4102 if (p < buffer + len)
4103 {
4104 *p = c;
4105 buffer_off = (buffer + len) - p;
4106 mch_memmove(buffer, p, buffer_off);
4107 continue;
4108 }
4109 buffer_off = 0;
4110 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004111# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004112 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004113 {
4114 buffer[len] = NUL;
4115 msg_puts(buffer);
4116 }
4117
4118 windgoto(msg_row, msg_col);
4119 cursor_on();
4120 out_flush();
4121 if (got_int)
4122 break;
4123 }
4124
4125 /*
4126 * Check if the child still exists, before checking for
4127 * typed characters (otherwise we would loose typeahead).
4128 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004129# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004130 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004131# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004132 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004133# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004134 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4135 || (wait_pid == pid && WIFEXITED(status)))
4136 {
4137 wait_pid = pid;
4138 break;
4139 }
4140 wait_pid = 0;
4141 }
4142finished:
4143 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004144 if (options & SHELL_READ)
4145 {
4146 if (ga.ga_len > 0)
4147 {
4148 append_ga_line(&ga);
4149 /* remember that the NL was missing */
4150 write_no_eol_lnum = curwin->w_cursor.lnum;
4151 }
4152 else
4153 write_no_eol_lnum = 0;
4154 ga_clear(&ga);
4155 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004156
Bram Moolenaar071d4272004-06-13 20:20:40 +00004157 /*
4158 * Give all typeahead that wasn't used back to ui_inchar().
4159 */
4160 if (ta_len)
4161 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004162 State = old_State;
4163 if (toshell_fd >= 0)
4164 close(toshell_fd);
4165 close(fromshell_fd);
4166 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004167
4168 /*
4169 * Wait until our child has exited.
4170 * Ignore wait() returning pids of other children and returning
4171 * because of some signal like SIGWINCH.
4172 * Don't wait if wait_pid was already set above, indicating the
4173 * child already exited.
4174 */
4175 while (wait_pid != pid)
4176 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004177# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004178 /* Ugly hack: when compiled with Python threads are probably
4179 * used, in which case wait() sometimes hangs for no obvious
4180 * reason. Use waitpid() instead and loop (like the GUI). */
4181# ifdef __NeXT__
4182 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4183# else
4184 wait_pid = waitpid(pid, &status, WNOHANG);
4185# endif
4186 if (wait_pid == 0)
4187 {
4188 /* Wait for 1/100 sec before trying again. */
4189 mch_delay(10L, TRUE);
4190 continue;
4191 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004192# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004193 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004194# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004195 if (wait_pid <= 0
4196# ifdef ECHILD
4197 && errno == ECHILD
4198# endif
4199 )
4200 break;
4201 }
4202
Bram Moolenaardf177f62005-02-22 08:39:57 +00004203 /* Make sure the child that writes to the external program is
4204 * dead. */
4205 if (wpid > 0)
4206 kill(wpid, SIGKILL);
4207
Bram Moolenaar071d4272004-06-13 20:20:40 +00004208 /*
4209 * Set to raw mode right now, otherwise a CTRL-C after
4210 * catch_signals() will kill Vim.
4211 */
4212 if (tmode == TMODE_RAW)
4213 settmode(TMODE_RAW);
4214 did_settmode = TRUE;
4215 set_signals();
4216
4217 if (WIFEXITED(status))
4218 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004219 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004220 retval = WEXITSTATUS(status);
4221 if (retval && !emsg_silent)
4222 {
4223 if (retval == EXEC_FAILED)
4224 {
4225 MSG_PUTS(_("\nCannot execute shell "));
4226 msg_outtrans(p_sh);
4227 msg_putchar('\n');
4228 }
4229 else if (!(options & SHELL_SILENT))
4230 {
4231 MSG_PUTS(_("\nshell returned "));
4232 msg_outnum((long)retval);
4233 msg_putchar('\n');
4234 }
4235 }
4236 }
4237 else
4238 MSG_PUTS(_("\nCommand terminated\n"));
4239 }
4240 }
4241 vim_free(argv);
4242
4243error:
4244 if (!did_settmode)
4245 if (tmode == TMODE_RAW)
4246 settmode(TMODE_RAW); /* set to raw mode */
4247# ifdef FEAT_TITLE
4248 resettitle();
4249# endif
4250 vim_free(newcmd);
4251
4252 return retval;
4253
4254#endif /* USE_SYSTEM */
4255}
4256
4257/*
4258 * Check for CTRL-C typed by reading all available characters.
4259 * In cooked mode we should get SIGINT, no need to check.
4260 */
4261 void
4262mch_breakcheck()
4263{
4264 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4265 fill_input_buf(FALSE);
4266}
4267
4268/*
4269 * Wait "msec" msec until a character is available from the keyboard or from
4270 * inbuf[]. msec == -1 will block forever.
4271 * When a GUI is being used, this will never get called -- webb
4272 */
4273 static int
4274WaitForChar(msec)
4275 long msec;
4276{
4277#ifdef FEAT_MOUSE_GPM
4278 int gpm_process_wanted;
4279#endif
4280#ifdef FEAT_XCLIPBOARD
4281 int rest;
4282#endif
4283 int avail;
4284
4285 if (input_available()) /* something in inbuf[] */
4286 return 1;
4287
4288#if defined(FEAT_MOUSE_DEC)
4289 /* May need to query the mouse position. */
4290 if (WantQueryMouse)
4291 {
4292 WantQueryMouse = 0;
4293 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4294 }
4295#endif
4296
4297 /*
4298 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4299 * events. This is a bit complicated, because they might both be defined.
4300 */
4301#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4302# ifdef FEAT_XCLIPBOARD
4303 rest = 0;
4304 if (do_xterm_trace())
4305 rest = msec;
4306# endif
4307 do
4308 {
4309# ifdef FEAT_XCLIPBOARD
4310 if (rest != 0)
4311 {
4312 msec = XT_TRACE_DELAY;
4313 if (rest >= 0 && rest < XT_TRACE_DELAY)
4314 msec = rest;
4315 if (rest >= 0)
4316 rest -= msec;
4317 }
4318# endif
4319# ifdef FEAT_MOUSE_GPM
4320 gpm_process_wanted = 0;
4321 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4322# else
4323 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4324# endif
4325 if (!avail)
4326 {
4327 if (input_available())
4328 return 1;
4329# ifdef FEAT_XCLIPBOARD
4330 if (rest == 0 || !do_xterm_trace())
4331# endif
4332 break;
4333 }
4334 }
4335 while (FALSE
4336# ifdef FEAT_MOUSE_GPM
4337 || (gpm_process_wanted && mch_gpm_process() == 0)
4338# endif
4339# ifdef FEAT_XCLIPBOARD
4340 || (!avail && rest != 0)
4341# endif
4342 );
4343
4344#else
4345 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4346#endif
4347 return avail;
4348}
4349
4350/*
4351 * Wait "msec" msec until a character is available from file descriptor "fd".
4352 * Time == -1 will block forever.
4353 * When a GUI is being used, this will not be used for input -- webb
4354 * Returns also, when a request from Sniff is waiting -- toni.
4355 * Or when a Linux GPM mouse event is waiting.
4356 */
4357/* ARGSUSED */
4358#if defined(__BEOS__)
4359 int
4360#else
4361 static int
4362#endif
4363RealWaitForChar(fd, msec, check_for_gpm)
4364 int fd;
4365 long msec;
4366 int *check_for_gpm;
4367{
4368 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004369#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004370 static int busy = FALSE;
4371
4372 /* May retry getting characters after an event was handled. */
4373# define MAY_LOOP
4374
4375# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4376 /* Remember at what time we started, so that we know how much longer we
4377 * should wait after being interrupted. */
4378# define USE_START_TV
4379 struct timeval start_tv;
4380
4381 if (msec > 0 && (
4382# ifdef FEAT_XCLIPBOARD
4383 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004384# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004385 ||
4386# endif
4387# endif
4388# ifdef USE_XSMP
4389 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004390# ifdef FEAT_MZSCHEME
4391 ||
4392# endif
4393# endif
4394# ifdef FEAT_MZSCHEME
4395 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004396# endif
4397 ))
4398 gettimeofday(&start_tv, NULL);
4399# endif
4400
4401 /* Handle being called recursively. This may happen for the session
4402 * manager stuff, it may save the file, which does a breakcheck. */
4403 if (busy)
4404 return 0;
4405#endif
4406
4407#ifdef MAY_LOOP
4408 while (1)
4409#endif
4410 {
4411#ifdef MAY_LOOP
4412 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004413# ifdef FEAT_MZSCHEME
4414 int mzquantum_used = FALSE;
4415# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004416#endif
4417#ifndef HAVE_SELECT
4418 struct pollfd fds[5];
4419 int nfd;
4420# ifdef FEAT_XCLIPBOARD
4421 int xterm_idx = -1;
4422# endif
4423# ifdef FEAT_MOUSE_GPM
4424 int gpm_idx = -1;
4425# endif
4426# ifdef USE_XSMP
4427 int xsmp_idx = -1;
4428# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004429 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004430
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004431# ifdef FEAT_MZSCHEME
4432 mzvim_check_threads();
4433 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4434 {
4435 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4436 mzquantum_used = TRUE;
4437 }
4438# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004439 fds[0].fd = fd;
4440 fds[0].events = POLLIN;
4441 nfd = 1;
4442
4443# ifdef FEAT_SNIFF
4444# define SNIFF_IDX 1
4445 if (want_sniff_request)
4446 {
4447 fds[SNIFF_IDX].fd = fd_from_sniff;
4448 fds[SNIFF_IDX].events = POLLIN;
4449 nfd++;
4450 }
4451# endif
4452# ifdef FEAT_XCLIPBOARD
4453 if (xterm_Shell != (Widget)0)
4454 {
4455 xterm_idx = nfd;
4456 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4457 fds[nfd].events = POLLIN;
4458 nfd++;
4459 }
4460# endif
4461# ifdef FEAT_MOUSE_GPM
4462 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4463 {
4464 gpm_idx = nfd;
4465 fds[nfd].fd = gpm_fd;
4466 fds[nfd].events = POLLIN;
4467 nfd++;
4468 }
4469# endif
4470# ifdef USE_XSMP
4471 if (xsmp_icefd != -1)
4472 {
4473 xsmp_idx = nfd;
4474 fds[nfd].fd = xsmp_icefd;
4475 fds[nfd].events = POLLIN;
4476 nfd++;
4477 }
4478# endif
4479
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004480 ret = poll(fds, nfd, towait);
4481# ifdef FEAT_MZSCHEME
4482 if (ret == 0 && mzquantum_used)
4483 /* MzThreads scheduling is required and timeout occured */
4484 finished = FALSE;
4485# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004486
4487# ifdef FEAT_SNIFF
4488 if (ret < 0)
4489 sniff_disconnect(1);
4490 else if (want_sniff_request)
4491 {
4492 if (fds[SNIFF_IDX].revents & POLLHUP)
4493 sniff_disconnect(1);
4494 if (fds[SNIFF_IDX].revents & POLLIN)
4495 sniff_request_waiting = 1;
4496 }
4497# endif
4498# ifdef FEAT_XCLIPBOARD
4499 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4500 {
4501 xterm_update(); /* Maybe we should hand out clipboard */
4502 if (--ret == 0 && !input_available())
4503 /* Try again */
4504 finished = FALSE;
4505 }
4506# endif
4507# ifdef FEAT_MOUSE_GPM
4508 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4509 {
4510 *check_for_gpm = 1;
4511 }
4512# endif
4513# ifdef USE_XSMP
4514 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4515 {
4516 if (fds[xsmp_idx].revents & POLLIN)
4517 {
4518 busy = TRUE;
4519 xsmp_handle_requests();
4520 busy = FALSE;
4521 }
4522 else if (fds[xsmp_idx].revents & POLLHUP)
4523 {
4524 if (p_verbose > 0)
4525 MSG(_("XSMP lost ICE connection"));
4526 xsmp_close();
4527 }
4528 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004529 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004530 }
4531# endif
4532
4533
4534#else /* HAVE_SELECT */
4535
4536 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004537 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004538 fd_set rfds, efds;
4539 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004540 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004541
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004542# ifdef FEAT_MZSCHEME
4543 mzvim_check_threads();
4544 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4545 {
4546 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4547 mzquantum_used = TRUE;
4548 }
4549# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004550# ifdef __EMX__
4551 /* don't check for incoming chars if not in raw mode, because select()
4552 * always returns TRUE then (in some version of emx.dll) */
4553 if (curr_tmode != TMODE_RAW)
4554 return 0;
4555# endif
4556
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004557 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004558 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004559 tv.tv_sec = towait / 1000;
4560 tv.tv_usec = (towait % 1000) * (1000000/1000);
4561 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004562 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004563 else
4564 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004565
4566 /*
4567 * Select on ready for reading and exceptional condition (end of file).
4568 */
4569 FD_ZERO(&rfds); /* calls bzero() on a sun */
4570 FD_ZERO(&efds);
4571 FD_SET(fd, &rfds);
4572# if !defined(__QNX__) && !defined(__CYGWIN32__)
4573 /* For QNX select() always returns 1 if this is set. Why? */
4574 FD_SET(fd, &efds);
4575# endif
4576 maxfd = fd;
4577
4578# ifdef FEAT_SNIFF
4579 if (want_sniff_request)
4580 {
4581 FD_SET(fd_from_sniff, &rfds);
4582 FD_SET(fd_from_sniff, &efds);
4583 if (maxfd < fd_from_sniff)
4584 maxfd = fd_from_sniff;
4585 }
4586# endif
4587# ifdef FEAT_XCLIPBOARD
4588 if (xterm_Shell != (Widget)0)
4589 {
4590 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4591 if (maxfd < ConnectionNumber(xterm_dpy))
4592 maxfd = ConnectionNumber(xterm_dpy);
4593 }
4594# endif
4595# ifdef FEAT_MOUSE_GPM
4596 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4597 {
4598 FD_SET(gpm_fd, &rfds);
4599 FD_SET(gpm_fd, &efds);
4600 if (maxfd < gpm_fd)
4601 maxfd = gpm_fd;
4602 }
4603# endif
4604# ifdef USE_XSMP
4605 if (xsmp_icefd != -1)
4606 {
4607 FD_SET(xsmp_icefd, &rfds);
4608 FD_SET(xsmp_icefd, &efds);
4609 if (maxfd < xsmp_icefd)
4610 maxfd = xsmp_icefd;
4611 }
4612# endif
4613
4614# ifdef OLD_VMS
4615 /* Old VMS as v6.2 and older have broken select(). It waits more than
4616 * required. Should not be used */
4617 ret = 0;
4618# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004619 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4620# endif
4621# ifdef FEAT_MZSCHEME
4622 if (ret == 0 && mzquantum_used)
4623 /* loop if MzThreads must be scheduled and timeout occured */
4624 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004625# endif
4626
4627# ifdef FEAT_SNIFF
4628 if (ret < 0 )
4629 sniff_disconnect(1);
4630 else if (ret > 0 && want_sniff_request)
4631 {
4632 if (FD_ISSET(fd_from_sniff, &efds))
4633 sniff_disconnect(1);
4634 if (FD_ISSET(fd_from_sniff, &rfds))
4635 sniff_request_waiting = 1;
4636 }
4637# endif
4638# ifdef FEAT_XCLIPBOARD
4639 if (ret > 0 && xterm_Shell != (Widget)0
4640 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4641 {
4642 xterm_update(); /* Maybe we should hand out clipboard */
4643 /* continue looping when we only got the X event and the input
4644 * buffer is empty */
4645 if (--ret == 0 && !input_available())
4646 {
4647 /* Try again */
4648 finished = FALSE;
4649 }
4650 }
4651# endif
4652# ifdef FEAT_MOUSE_GPM
4653 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4654 {
4655 if (FD_ISSET(gpm_fd, &efds))
4656 gpm_close();
4657 else if (FD_ISSET(gpm_fd, &rfds))
4658 *check_for_gpm = 1;
4659 }
4660# endif
4661# ifdef USE_XSMP
4662 if (ret > 0 && xsmp_icefd != -1)
4663 {
4664 if (FD_ISSET(xsmp_icefd, &efds))
4665 {
4666 if (p_verbose > 0)
4667 MSG(_("XSMP lost ICE connection"));
4668 xsmp_close();
4669 if (--ret == 0)
4670 finished = FALSE; /* keep going if event was only one */
4671 }
4672 else if (FD_ISSET(xsmp_icefd, &rfds))
4673 {
4674 busy = TRUE;
4675 xsmp_handle_requests();
4676 busy = FALSE;
4677 if (--ret == 0)
4678 finished = FALSE; /* keep going if event was only one */
4679 }
4680 }
4681# endif
4682
4683#endif /* HAVE_SELECT */
4684
4685#ifdef MAY_LOOP
4686 if (finished || msec == 0)
4687 break;
4688
4689 /* We're going to loop around again, find out for how long */
4690 if (msec > 0)
4691 {
4692# ifdef USE_START_TV
4693 struct timeval mtv;
4694
4695 /* Compute remaining wait time. */
4696 gettimeofday(&mtv, NULL);
4697 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
4698 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
4699# else
4700 /* Guess we got interrupted halfway. */
4701 msec = msec / 2;
4702# endif
4703 if (msec <= 0)
4704 break; /* waited long enough */
4705 }
4706#endif
4707 }
4708
4709 return (ret > 0);
4710}
4711
4712#ifndef VMS
4713
4714#ifndef NO_EXPANDPATH
4715 static int
4716pstrcmp(a, b)
4717 const void *a, *b;
4718{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004719 return (pathcmp(*(char **)a, *(char **)b, -1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004720}
4721
4722/*
4723 * Recursively expand one path component into all matching files and/or
4724 * directories.
4725 * "path" has backslashes before chars that are not to be expanded, starting
4726 * at "path + wildoff".
4727 * Return the number of matches found.
4728 */
4729 int
4730mch_expandpath(gap, path, flags)
4731 garray_T *gap;
4732 char_u *path;
4733 int flags; /* EW_* flags */
4734{
4735 return unix_expandpath(gap, path, 0, flags);
4736}
4737
4738 static int
4739unix_expandpath(gap, path, wildoff, flags)
4740 garray_T *gap;
4741 char_u *path;
4742 int wildoff;
4743 int flags; /* EW_* flags */
4744{
4745 char_u *buf;
4746 char_u *path_end;
4747 char_u *p, *s, *e;
4748 int start_len, c;
4749 char_u *pat;
4750 DIR *dirp;
4751 regmatch_T regmatch;
4752 struct dirent *dp;
4753 int starts_with_dot;
4754 int matches;
4755 int len;
4756
4757 start_len = gap->ga_len;
4758 buf = alloc(STRLEN(path) + BASENAMELEN + 5);/* make room for file name */
4759 if (buf == NULL)
4760 return 0;
4761
4762/*
4763 * Find the first part in the path name that contains a wildcard.
4764 * Copy it into buf, including the preceding characters.
4765 */
4766 p = buf;
4767 s = buf;
4768 e = NULL;
4769 path_end = path;
4770 while (*path_end != NUL)
4771 {
4772 /* May ignore a wildcard that has a backslash before it; it will
4773 * be removed by rem_backslash() or file_pat_to_reg_pat() below. */
4774 if (path_end >= path + wildoff && rem_backslash(path_end))
4775 *p++ = *path_end++;
4776 else if (*path_end == '/')
4777 {
4778 if (e != NULL)
4779 break;
4780 s = p + 1;
4781 }
4782 else if (path_end >= path + wildoff
4783 && vim_strchr((char_u *)"*?[{~$", *path_end) != NULL)
4784 e = p;
4785#ifdef FEAT_MBYTE
4786 if (has_mbyte)
4787 {
4788 len = (*mb_ptr2len_check)(path_end);
4789 STRNCPY(p, path_end, len);
4790 p += len;
4791 path_end += len;
4792 }
4793 else
4794#endif
4795 *p++ = *path_end++;
4796 }
4797 e = p;
4798 *e = NUL;
4799
4800 /* now we have one wildcard component between s and e */
4801 /* Remove backslashes between "wildoff" and the start of the wildcard
4802 * component. */
4803 for (p = buf + wildoff; p < s; ++p)
4804 if (rem_backslash(p))
4805 {
4806 STRCPY(p, p + 1);
4807 --e;
4808 --s;
4809 }
4810
4811 /* convert the file pattern to a regexp pattern */
4812 starts_with_dot = (*s == '.');
4813 pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
4814 if (pat == NULL)
4815 {
4816 vim_free(buf);
4817 return 0;
4818 }
4819
4820 /* compile the regexp into a program */
4821#ifdef MACOS_X /* Can/Should we use CASE_INSENSITIVE_FILENAME instead ?*/
4822 regmatch.rm_ic = TRUE; /* Behave like Terminal.app */
4823#else
4824 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
4825#endif
4826 regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
4827 vim_free(pat);
4828
4829 if (regmatch.regprog == NULL)
4830 {
4831 vim_free(buf);
4832 return 0;
4833 }
4834
4835 /* open the directory for scanning */
4836 c = *s;
4837 *s = NUL;
4838 dirp = opendir(*buf == NUL ? "." : (char *)buf);
4839 *s = c;
4840
4841 /* Find all matching entries */
4842 if (dirp != NULL)
4843 {
4844 for (;;)
4845 {
4846 dp = readdir(dirp);
4847 if (dp == NULL)
4848 break;
4849 if ((dp->d_name[0] != '.' || starts_with_dot)
4850 && vim_regexec(&regmatch, (char_u *)dp->d_name, (colnr_T)0))
4851 {
4852 STRCPY(s, dp->d_name);
4853 len = STRLEN(buf);
4854 STRCPY(buf + len, path_end);
4855 if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */
4856 {
4857 /* need to expand another component of the path */
4858 /* remove backslashes for the remaining components only */
4859 (void)unix_expandpath(gap, buf, len + 1, flags);
4860 }
4861 else
4862 {
4863 /* no more wildcards, check if there is a match */
4864 /* remove backslashes for the remaining components only */
4865 if (*path_end != NUL)
4866 backslash_halve(buf + len + 1);
4867 if (mch_getperm(buf) >= 0) /* add existing file */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004868 {
4869#if defined(MACOS_X) && defined(FEAT_MBYTE)
4870 size_t precomp_len = STRLEN(buf)+1;
4871 char_u *precomp_buf =
4872 mac_precompose_path(buf, precomp_len, &precomp_len);
4873 if (precomp_buf)
4874 {
4875 mch_memmove(buf, precomp_buf, precomp_len);
4876 vim_free(precomp_buf);
4877 }
4878#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004879 addfile(gap, buf, flags);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004880 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004881 }
4882 }
4883 }
4884
4885 closedir(dirp);
4886 }
4887
4888 vim_free(buf);
4889 vim_free(regmatch.regprog);
4890
4891 matches = gap->ga_len - start_len;
4892 if (matches > 0)
4893 qsort(((char_u **)gap->ga_data) + start_len, matches,
4894 sizeof(char_u *), pstrcmp);
4895 return matches;
4896}
4897#endif
4898
4899/*
4900 * mch_expand_wildcards() - this code does wild-card pattern matching using
4901 * the shell
4902 *
4903 * return OK for success, FAIL for error (you may lose some memory) and put
4904 * an error message in *file.
4905 *
4906 * num_pat is number of input patterns
4907 * pat is array of pointers to input patterns
4908 * num_file is pointer to number of matched file names
4909 * file is pointer to array of pointers to matched file names
4910 */
4911
4912#ifndef SEEK_SET
4913# define SEEK_SET 0
4914#endif
4915#ifndef SEEK_END
4916# define SEEK_END 2
4917#endif
4918
4919/* ARGSUSED */
4920 int
4921mch_expand_wildcards(num_pat, pat, num_file, file, flags)
4922 int num_pat;
4923 char_u **pat;
4924 int *num_file;
4925 char_u ***file;
4926 int flags; /* EW_* flags */
4927{
4928 int i;
4929 size_t len;
4930 char_u *p;
4931 int dir;
4932#ifdef __EMX__
4933# define EXPL_ALLOC_INC 16
4934 char_u **expl_files;
4935 size_t files_alloced, files_free;
4936 char_u *buf;
4937 int has_wildcard;
4938
4939 *num_file = 0; /* default: no files found */
4940 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
4941 files_free = EXPL_ALLOC_INC; /* how much space is not used */
4942 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
4943 if (*file == NULL)
4944 return FAIL;
4945
4946 for (; num_pat > 0; num_pat--, pat++)
4947 {
4948 expl_files = NULL;
4949 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
4950 /* expand environment var or home dir */
4951 buf = expand_env_save(*pat);
4952 else
4953 buf = vim_strsave(*pat);
4954 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00004955 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004956 if (has_wildcard) /* yes, so expand them */
4957 expl_files = (char_u **)_fnexplode(buf);
4958
4959 /*
4960 * return value of buf if no wildcards left,
4961 * OR if no match AND EW_NOTFOUND is set.
4962 */
4963 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
4964 || (expl_files == NULL && (flags & EW_NOTFOUND)))
4965 { /* simply save the current contents of *buf */
4966 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
4967 if (expl_files != NULL)
4968 {
4969 expl_files[0] = vim_strsave(buf);
4970 expl_files[1] = NULL;
4971 }
4972 }
4973 vim_free(buf);
4974
4975 /*
4976 * Count number of names resulting from expansion,
4977 * At the same time add a backslash to the end of names that happen to
4978 * be directories, and replace slashes with backslashes.
4979 */
4980 if (expl_files)
4981 {
4982 for (i = 0; (p = expl_files[i]) != NULL; i++)
4983 {
4984 dir = mch_isdir(p);
4985 /* If we don't want dirs and this is one, skip it */
4986 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
4987 continue;
4988
4989 if (--files_free == 0)
4990 {
4991 /* need more room in table of pointers */
4992 files_alloced += EXPL_ALLOC_INC;
4993 *file = (char_u **)vim_realloc(*file,
4994 sizeof(char_u **) * files_alloced);
4995 if (*file == NULL)
4996 {
4997 EMSG(_(e_outofmem));
4998 *num_file = 0;
4999 return FAIL;
5000 }
5001 files_free = EXPL_ALLOC_INC;
5002 }
5003 slash_adjust(p);
5004 if (dir)
5005 {
5006 /* For a directory we add a '/', unless it's already
5007 * there. */
5008 len = STRLEN(p);
5009 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5010 {
5011 STRCPY((*file)[*num_file], p);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005012 if (!after_pathsep((*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005013 {
5014 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005015 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005016 }
5017 }
5018 }
5019 else
5020 {
5021 (*file)[*num_file] = vim_strsave(p);
5022 }
5023
5024 /*
5025 * Error message already given by either alloc or vim_strsave.
5026 * Should return FAIL, but returning OK works also.
5027 */
5028 if ((*file)[*num_file] == NULL)
5029 break;
5030 (*num_file)++;
5031 }
5032 _fnexplodefree((char **)expl_files);
5033 }
5034 }
5035 return OK;
5036
5037#else /* __EMX__ */
5038
5039 int j;
5040 char_u *tempname;
5041 char_u *command;
5042 FILE *fd;
5043 char_u *buffer;
5044#define STYLE_ECHO 0 /* use "echo" to expand */
5045#define STYLE_GLOB 1 /* use "glob" to expand, for csh */
5046#define STYLE_PRINT 2 /* use "print -N" to expand, for zsh */
5047#define STYLE_BT 3 /* `cmd` expansion, execute the pattern directly */
5048 int shell_style = STYLE_ECHO;
5049 int check_spaces;
5050 static int did_find_nul = FALSE;
5051 int ampersent = FALSE;
5052
5053 *num_file = 0; /* default: no files found */
5054 *file = NULL;
5055
5056 /*
5057 * If there are no wildcards, just copy the names to allocated memory.
5058 * Saves a lot of time, because we don't have to start a new shell.
5059 */
5060 if (!have_wildcard(num_pat, pat))
5061 return save_patterns(num_pat, pat, num_file, file);
5062
5063 /*
5064 * Don't allow the use of backticks in secure and restricted mode.
5065 */
5066 if (secure || restricted)
5067 for (i = 0; i < num_pat; ++i)
5068 if (vim_strchr(pat[i], '`') != NULL
5069 && (check_restricted() || check_secure()))
5070 return FAIL;
5071
5072 /*
5073 * get a name for the temp file
5074 */
5075 if ((tempname = vim_tempname('o')) == NULL)
5076 {
5077 EMSG(_(e_notmp));
5078 return FAIL;
5079 }
5080
5081 /*
5082 * Let the shell expand the patterns and write the result into the temp
5083 * file. if expanding `cmd` execute it directly.
5084 * If we use csh, glob will work better than echo.
5085 * If we use zsh, print -N will work better than glob.
5086 */
5087 if (num_pat == 1 && *pat[0] == '`'
5088 && (len = STRLEN(pat[0])) > 2
5089 && *(pat[0] + len - 1) == '`')
5090 shell_style = STYLE_BT;
5091 else if ((len = STRLEN(p_sh)) >= 3)
5092 {
5093 if (STRCMP(p_sh + len - 3, "csh") == 0)
5094 shell_style = STYLE_GLOB;
5095 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5096 shell_style = STYLE_PRINT;
5097 }
5098
5099 /* "unset nonomatch; print -N >" plus two is 29 */
5100 len = STRLEN(tempname) + 29;
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005101 for (i = 0; i < num_pat; ++i)
5102 {
5103 /* Count the length of the patterns in the same way as they are put in
5104 * "command" below. */
5105#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005106 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005107#else
5108 ++len; /* add space */
5109 for (j = 0; pat[i][j] != NUL; )
5110 if (vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5111 {
5112 len += 2; /* add two quotes */
5113 while (pat[i][j] != NUL
5114 && vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5115 {
5116 ++len;
5117 ++j;
5118 }
5119 }
5120 else
5121 {
5122 ++len;
5123 ++j;
5124 }
5125#endif
5126 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005127 command = alloc(len);
5128 if (command == NULL)
5129 {
5130 /* out of memory */
5131 vim_free(tempname);
5132 return FAIL;
5133 }
5134
5135 /*
5136 * Build the shell command:
5137 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5138 * recognizes this).
5139 * - Add the shell command to print the expanded names.
5140 * - Add the temp file name.
5141 * - Add the file name patterns.
5142 */
5143 if (shell_style == STYLE_BT)
5144 {
5145 STRCPY(command, pat[0] + 1); /* exclude first backtick */
5146 p = command + STRLEN(command) - 1;
5147 *p = ' '; /* remove last backtick */
5148 while (p > command && vim_iswhite(*p))
5149 --p;
5150 if (*p == '&') /* remove trailing '&' */
5151 {
5152 ampersent = TRUE;
5153 *p = ' ';
5154 }
5155 STRCAT(command, ">");
5156 }
5157 else
5158 {
5159 if (flags & EW_NOTFOUND)
5160 STRCPY(command, "set nonomatch; ");
5161 else
5162 STRCPY(command, "unset nonomatch; ");
5163 if (shell_style == STYLE_GLOB)
5164 STRCAT(command, "glob >");
5165 else if (shell_style == STYLE_PRINT)
5166 STRCAT(command, "print -N >");
5167 else
5168 STRCAT(command, "echo >");
5169 }
5170 STRCAT(command, tempname);
5171 if (shell_style != STYLE_BT)
5172 for (i = 0; i < num_pat; ++i)
5173 {
5174 /* When using system() always add extra quotes, because the shell
5175 * is started twice. Otherwise only put quotes around spaces and
5176 * single quotes. */
5177#ifdef USE_SYSTEM
5178 STRCAT(command, " \"");
5179 STRCAT(command, pat[i]);
5180 STRCAT(command, "\"");
5181#else
5182 p = command + STRLEN(command);
5183 *p++ = ' ';
5184 for (j = 0; pat[i][j] != NUL; )
5185 if (vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5186 {
5187 *p++ = '"';
5188 while (pat[i][j] != NUL
5189 && vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5190 *p++ = pat[i][j++];
5191 *p++ = '"';
5192 }
5193 else
Bram Moolenaar0cf6f542005-01-16 21:59:36 +00005194 {
5195 /* For a backslash also copy the next character, don't
5196 * want to put quotes around it. */
5197 if ((*p++ = pat[i][j++]) == '\\' && pat[i][j] != NUL)
5198 *p++ = pat[i][j++];
5199 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005200 *p = NUL;
5201#endif
5202 }
5203 if (flags & EW_SILENT)
5204 show_shell_mess = FALSE;
5205 if (ampersent)
5206 STRCAT(command, "&"); /* put the '&' back after the
5207 redirection */
5208
5209 /*
5210 * Using zsh -G: If a pattern has no matches, it is just deleted from
5211 * the argument list, otherwise zsh gives an error message and doesn't
5212 * expand any other pattern.
5213 */
5214 if (shell_style == STYLE_PRINT)
5215 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5216
5217 /*
5218 * If we use -f then shell variables set in .cshrc won't get expanded.
5219 * vi can do it, so we will too, but it is only necessary if there is a "$"
5220 * in one of the patterns, otherwise we can still use the fast option.
5221 */
5222 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5223 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5224
5225 /*
5226 * execute the shell command
5227 */
5228 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5229
5230 /* When running in the background, give it some time to create the temp
5231 * file, but don't wait for it to finish. */
5232 if (ampersent)
5233 mch_delay(10L, TRUE);
5234
5235 extra_shell_arg = NULL; /* cleanup */
5236 show_shell_mess = TRUE;
5237 vim_free(command);
5238
5239 if (i) /* mch_call_shell() failed */
5240 {
5241 mch_remove(tempname);
5242 vim_free(tempname);
5243 /*
5244 * With interactive completion, the error message is not printed.
5245 * However with USE_SYSTEM, I don't know how to turn off error messages
5246 * from the shell, so screen may still get messed up -- webb.
5247 */
5248#ifndef USE_SYSTEM
5249 if (!(flags & EW_SILENT))
5250#endif
5251 {
5252 redraw_later_clear(); /* probably messed up screen */
5253 msg_putchar('\n'); /* clear bottom line quickly */
5254 cmdline_row = Rows - 1; /* continue on last line */
5255#ifdef USE_SYSTEM
5256 if (!(flags & EW_SILENT))
5257#endif
5258 {
5259 MSG(_(e_wildexpand));
5260 msg_start(); /* don't overwrite this message */
5261 }
5262 }
5263 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5264 * EW_NOTFOUND is given */
5265 if (shell_style == STYLE_BT)
5266 return FAIL;
5267 goto notfound;
5268 }
5269
5270 /*
5271 * read the names from the file into memory
5272 */
5273 fd = fopen((char *)tempname, READBIN);
5274 if (fd == NULL)
5275 {
5276 /* Something went wrong, perhaps a file name with a special char. */
5277 if (!(flags & EW_SILENT))
5278 {
5279 MSG(_(e_wildexpand));
5280 msg_start(); /* don't overwrite this message */
5281 }
5282 vim_free(tempname);
5283 goto notfound;
5284 }
5285 fseek(fd, 0L, SEEK_END);
5286 len = ftell(fd); /* get size of temp file */
5287 fseek(fd, 0L, SEEK_SET);
5288 buffer = alloc(len + 1);
5289 if (buffer == NULL)
5290 {
5291 /* out of memory */
5292 mch_remove(tempname);
5293 vim_free(tempname);
5294 fclose(fd);
5295 return FAIL;
5296 }
5297 i = fread((char *)buffer, 1, len, fd);
5298 fclose(fd);
5299 mch_remove(tempname);
5300 if (i != len)
5301 {
5302 /* unexpected read error */
5303 EMSG2(_(e_notread), tempname);
5304 vim_free(tempname);
5305 vim_free(buffer);
5306 return FAIL;
5307 }
5308 vim_free(tempname);
5309
5310#if defined(__CYGWIN__) || defined(__CYGWIN32__)
5311 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5312 p = buffer;
5313 for (i = 0; i < len; ++i)
5314 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5315 *p++ = buffer[i];
5316 len = p - buffer;
5317# endif
5318
5319
5320 /* file names are separated with Space */
5321 if (shell_style == STYLE_ECHO)
5322 {
5323 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5324 p = buffer;
5325 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5326 {
5327 while (*p != ' ' && *p != '\n')
5328 ++p;
5329 p = skipwhite(p); /* skip to next entry */
5330 }
5331 }
5332 /* file names are separated with NL */
5333 else if (shell_style == STYLE_BT)
5334 {
5335 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5336 p = buffer;
5337 for (i = 0; *p != NUL; ++i) /* count number of entries */
5338 {
5339 while (*p != '\n' && *p != NUL)
5340 ++p;
5341 if (*p != NUL)
5342 ++p;
5343 p = skipwhite(p); /* skip leading white space */
5344 }
5345 }
5346 /* file names are separated with NUL */
5347 else
5348 {
5349 /*
5350 * Some versions of zsh use spaces instead of NULs to separate
5351 * results. Only do this when there is no NUL before the end of the
5352 * buffer, otherwise we would never be able to use file names with
5353 * embedded spaces when zsh does use NULs.
5354 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5355 * don't check for spaces again.
5356 */
5357 check_spaces = FALSE;
5358 if (shell_style == STYLE_PRINT && !did_find_nul)
5359 {
5360 /* If there is a NUL, set did_find_nul, else set check_spaces */
5361 if (len && (int)STRLEN(buffer) < len - 1)
5362 did_find_nul = TRUE;
5363 else
5364 check_spaces = TRUE;
5365 }
5366
5367 /*
5368 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5369 * already is one, for STYLE_GLOB it needs to be added.
5370 */
5371 if (len && buffer[len - 1] == NUL)
5372 --len;
5373 else
5374 buffer[len] = NUL;
5375 i = 0;
5376 for (p = buffer; p < buffer + len; ++p)
5377 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5378 {
5379 ++i;
5380 *p = NUL;
5381 }
5382 if (len)
5383 ++i; /* count last entry */
5384 }
5385 if (i == 0)
5386 {
5387 /*
5388 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5389 * /bin/sh will happily expand it to nothing rather than returning an
5390 * error; and hey, it's good to check anyway -- webb.
5391 */
5392 vim_free(buffer);
5393 goto notfound;
5394 }
5395 *num_file = i;
5396 *file = (char_u **)alloc(sizeof(char_u *) * i);
5397 if (*file == NULL)
5398 {
5399 /* out of memory */
5400 vim_free(buffer);
5401 return FAIL;
5402 }
5403
5404 /*
5405 * Isolate the individual file names.
5406 */
5407 p = buffer;
5408 for (i = 0; i < *num_file; ++i)
5409 {
5410 (*file)[i] = p;
5411 /* Space or NL separates */
5412 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT)
5413 {
5414 while (!(shell_style == STYLE_ECHO && *p == ' ') && *p != '\n')
5415 ++p;
5416 if (p == buffer + len) /* last entry */
5417 *p = NUL;
5418 else
5419 {
5420 *p++ = NUL;
5421 p = skipwhite(p); /* skip to next entry */
5422 }
5423 }
5424 else /* NUL separates */
5425 {
5426 while (*p && p < buffer + len) /* skip entry */
5427 ++p;
5428 ++p; /* skip NUL */
5429 }
5430 }
5431
5432 /*
5433 * Move the file names to allocated memory.
5434 */
5435 for (j = 0, i = 0; i < *num_file; ++i)
5436 {
5437 /* Require the files to exist. Helps when using /bin/sh */
5438 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5439 continue;
5440
5441 /* check if this entry should be included */
5442 dir = (mch_isdir((*file)[i]));
5443 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5444 continue;
5445
5446 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5447 if (p)
5448 {
5449 STRCPY(p, (*file)[i]);
5450 if (dir)
5451 STRCAT(p, "/"); /* add '/' to a directory name */
5452 (*file)[j++] = p;
5453 }
5454 }
5455 vim_free(buffer);
5456 *num_file = j;
5457
5458 if (*num_file == 0) /* rejected all entries */
5459 {
5460 vim_free(*file);
5461 *file = NULL;
5462 goto notfound;
5463 }
5464
5465 return OK;
5466
5467notfound:
5468 if (flags & EW_NOTFOUND)
5469 return save_patterns(num_pat, pat, num_file, file);
5470 return FAIL;
5471
5472#endif /* __EMX__ */
5473}
5474
5475#endif /* VMS */
5476
5477#ifndef __EMX__
5478 static int
5479save_patterns(num_pat, pat, num_file, file)
5480 int num_pat;
5481 char_u **pat;
5482 int *num_file;
5483 char_u ***file;
5484{
5485 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005486 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005487
5488 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5489 if (*file == NULL)
5490 return FAIL;
5491 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005492 {
5493 s = vim_strsave(pat[i]);
5494 if (s != NULL)
5495 /* Be compatible with expand_filename(): halve the number of
5496 * backslashes. */
5497 backslash_halve(s);
5498 (*file)[i] = s;
5499 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005500 *num_file = num_pat;
5501 return OK;
5502}
5503#endif
5504
5505
5506/*
5507 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5508 * expand.
5509 */
5510 int
5511mch_has_exp_wildcard(p)
5512 char_u *p;
5513{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005514 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005515 {
5516#ifndef OS2
5517 if (*p == '\\' && p[1] != NUL)
5518 ++p;
5519 else
5520#endif
5521 if (vim_strchr((char_u *)
5522#ifdef VMS
5523 "*?%"
5524#else
5525# ifdef OS2
5526 "*?"
5527# else
5528 "*?[{'"
5529# endif
5530#endif
5531 , *p) != NULL)
5532 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005533 }
5534 return FALSE;
5535}
5536
5537/*
5538 * Return TRUE if the string "p" contains a wildcard.
5539 * Don't recognize '~' at the end as a wildcard.
5540 */
5541 int
5542mch_has_wildcard(p)
5543 char_u *p;
5544{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005545 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005546 {
5547#ifndef OS2
5548 if (*p == '\\' && p[1] != NUL)
5549 ++p;
5550 else
5551#endif
5552 if (vim_strchr((char_u *)
5553#ifdef VMS
5554 "*?%$"
5555#else
5556# ifdef OS2
5557# ifdef VIM_BACKTICK
5558 "*?$`"
5559# else
5560 "*?$"
5561# endif
5562# else
5563 "*?[{`'$"
5564# endif
5565#endif
5566 , *p) != NULL
5567 || (*p == '~' && p[1] != NUL))
5568 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005569 }
5570 return FALSE;
5571}
5572
5573#ifndef __EMX__
5574 static int
5575have_wildcard(num, file)
5576 int num;
5577 char_u **file;
5578{
5579 int i;
5580
5581 for (i = 0; i < num; i++)
5582 if (mch_has_wildcard(file[i]))
5583 return 1;
5584 return 0;
5585}
5586
5587 static int
5588have_dollars(num, file)
5589 int num;
5590 char_u **file;
5591{
5592 int i;
5593
5594 for (i = 0; i < num; i++)
5595 if (vim_strchr(file[i], '$') != NULL)
5596 return TRUE;
5597 return FALSE;
5598}
5599#endif /* ifndef __EMX__ */
5600
5601#ifndef HAVE_RENAME
5602/*
5603 * Scaled-down version of rename(), which is missing in Xenix.
5604 * This version can only move regular files and will fail if the
5605 * destination exists.
5606 */
5607 int
5608mch_rename(src, dest)
5609 const char *src, *dest;
5610{
5611 struct stat st;
5612
5613 if (stat(dest, &st) >= 0) /* fail if destination exists */
5614 return -1;
5615 if (link(src, dest) != 0) /* link file to new name */
5616 return -1;
5617 if (mch_remove(src) == 0) /* delete link to old name */
5618 return 0;
5619 return -1;
5620}
5621#endif /* !HAVE_RENAME */
5622
5623#ifdef FEAT_MOUSE_GPM
5624/*
5625 * Initializes connection with gpm (if it isn't already opened)
5626 * Return 1 if succeeded (or connection already opened), 0 if failed
5627 */
5628 static int
5629gpm_open()
5630{
5631 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5632
5633 if (!gpm_flag)
5634 {
5635 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5636 gpm_connect.defaultMask = ~GPM_HARD;
5637 /* Default handling for mouse move*/
5638 gpm_connect.minMod = 0; /* Handle any modifier keys */
5639 gpm_connect.maxMod = 0xffff;
5640 if (Gpm_Open(&gpm_connect, 0) > 0)
5641 {
5642 /* gpm library tries to handling TSTP causes
5643 * problems. Anyways, we close connection to Gpm whenever
5644 * we are going to suspend or starting an external process
5645 * so we should'nt have problem with this
5646 */
5647 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5648 return 1; /* succeed */
5649 }
5650 if (gpm_fd == -2)
5651 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5652 return 0;
5653 }
5654 return 1; /* already open */
5655}
5656
5657/*
5658 * Closes connection to gpm
5659 * returns non-zero if connection succesfully closed
5660 */
5661 static void
5662gpm_close()
5663{
5664 if (gpm_flag && gpm_fd >= 0) /* if Open */
5665 Gpm_Close();
5666}
5667
5668/* Reads gpm event and adds special keys to input buf. Returns length of
5669 * generated key sequence.
5670 * This function is made after gui_send_mouse_event
5671 */
5672 static int
5673mch_gpm_process()
5674{
5675 int button;
5676 static Gpm_Event gpm_event;
5677 char_u string[6];
5678 int_u vim_modifiers;
5679 int row,col;
5680 unsigned char buttons_mask;
5681 unsigned char gpm_modifiers;
5682 static unsigned char old_buttons = 0;
5683
5684 Gpm_GetEvent(&gpm_event);
5685
5686#ifdef FEAT_GUI
5687 /* Don't put events in the input queue now. */
5688 if (hold_gui_events)
5689 return 0;
5690#endif
5691
5692 row = gpm_event.y - 1;
5693 col = gpm_event.x - 1;
5694
5695 string[0] = ESC; /* Our termcode */
5696 string[1] = 'M';
5697 string[2] = 'G';
5698 switch (GPM_BARE_EVENTS(gpm_event.type))
5699 {
5700 case GPM_DRAG:
5701 string[3] = MOUSE_DRAG;
5702 break;
5703 case GPM_DOWN:
5704 buttons_mask = gpm_event.buttons & ~old_buttons;
5705 old_buttons = gpm_event.buttons;
5706 switch (buttons_mask)
5707 {
5708 case GPM_B_LEFT:
5709 button = MOUSE_LEFT;
5710 break;
5711 case GPM_B_MIDDLE:
5712 button = MOUSE_MIDDLE;
5713 break;
5714 case GPM_B_RIGHT:
5715 button = MOUSE_RIGHT;
5716 break;
5717 default:
5718 return 0;
5719 /*Don't know what to do. Can more than one button be
5720 * reported in one event? */
5721 }
5722 string[3] = (char_u)(button | 0x20);
5723 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5724 break;
5725 case GPM_UP:
5726 string[3] = MOUSE_RELEASE;
5727 old_buttons &= ~gpm_event.buttons;
5728 break;
5729 default:
5730 return 0;
5731 }
5732 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5733 gpm_modifiers = gpm_event.modifiers;
5734 vim_modifiers = 0x0;
5735 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5736 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5737 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5738 */
5739 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5740 vim_modifiers |= MOUSE_SHIFT;
5741
5742 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5743 vim_modifiers |= MOUSE_CTRL;
5744 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5745 vim_modifiers |= MOUSE_ALT;
5746 string[3] |= vim_modifiers;
5747 string[4] = (char_u)(col + ' ' + 1);
5748 string[5] = (char_u)(row + ' ' + 1);
5749 add_to_input_buf(string, 6);
5750 return 6;
5751}
5752#endif /* FEAT_MOUSE_GPM */
5753
5754#if defined(FEAT_LIBCALL) || defined(PROTO)
5755typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
5756typedef char_u * (*INTPROCSTR)__ARGS((int));
5757typedef int (*STRPROCINT)__ARGS((char_u *));
5758typedef int (*INTPROCINT)__ARGS((int));
5759
5760/*
5761 * Call a DLL routine which takes either a string or int param
5762 * and returns an allocated string.
5763 */
5764 int
5765mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
5766 char_u *libname;
5767 char_u *funcname;
5768 char_u *argstring; /* NULL when using a argint */
5769 int argint;
5770 char_u **string_result;/* NULL when using number_result */
5771 int *number_result;
5772{
5773# if defined(USE_DLOPEN)
5774 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005775 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005776# else
5777 shl_t hinstLib;
5778# endif
5779 STRPROCSTR ProcAdd;
5780 INTPROCSTR ProcAddI;
5781 char_u *retval_str = NULL;
5782 int retval_int = 0;
5783 int success = FALSE;
5784
5785 /* Get a handle to the DLL module. */
5786# if defined(USE_DLOPEN)
5787 hinstLib = dlopen((char *)libname, RTLD_LAZY
5788# ifdef RTLD_LOCAL
5789 | RTLD_LOCAL
5790# endif
5791 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005792 if (hinstLib == NULL)
5793 {
5794 /* "dlerr" must be used before dlclose() */
5795 dlerr = (char *)dlerror();
5796 if (dlerr != NULL)
5797 EMSG2(_("dlerror = \"%s\""), dlerr);
5798 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005799# else
5800 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
5801# endif
5802
5803 /* If the handle is valid, try to get the function address. */
5804 if (hinstLib != NULL)
5805 {
5806# ifdef HAVE_SETJMP_H
5807 /*
5808 * Catch a crash when calling the library function. For example when
5809 * using a number where a string pointer is expected.
5810 */
5811 mch_startjmp();
5812 if (SETJMP(lc_jump_env) != 0)
5813 {
5814 success = FALSE;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005815 dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005816 mch_didjmp();
5817 }
5818 else
5819# endif
5820 {
5821 retval_str = NULL;
5822 retval_int = 0;
5823
5824 if (argstring != NULL)
5825 {
5826# if defined(USE_DLOPEN)
5827 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005828 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005829# else
5830 if (shl_findsym(&hinstLib, (const char *)funcname,
5831 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
5832 ProcAdd = NULL;
5833# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005834 if ((success = (ProcAdd != NULL
5835# if defined(USE_DLOPEN)
5836 && dlerr == NULL
5837# endif
5838 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005839 {
5840 if (string_result == NULL)
5841 retval_int = ((STRPROCINT)ProcAdd)(argstring);
5842 else
5843 retval_str = (ProcAdd)(argstring);
5844 }
5845 }
5846 else
5847 {
5848# if defined(USE_DLOPEN)
5849 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005850 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005851# else
5852 if (shl_findsym(&hinstLib, (const char *)funcname,
5853 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
5854 ProcAddI = NULL;
5855# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005856 if ((success = (ProcAddI != NULL
5857# if defined(USE_DLOPEN)
5858 && dlerr == NULL
5859# endif
5860 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005861 {
5862 if (string_result == NULL)
5863 retval_int = ((INTPROCINT)ProcAddI)(argint);
5864 else
5865 retval_str = (ProcAddI)(argint);
5866 }
5867 }
5868
5869 /* Save the string before we free the library. */
5870 /* Assume that a "1" or "-1" result is an illegal pointer. */
5871 if (string_result == NULL)
5872 *number_result = retval_int;
5873 else if (retval_str != NULL
5874 && retval_str != (char_u *)1
5875 && retval_str != (char_u *)-1)
5876 *string_result = vim_strsave(retval_str);
5877 }
5878
5879# ifdef HAVE_SETJMP_H
5880 mch_endjmp();
5881# ifdef SIGHASARG
5882 if (lc_signal != 0)
5883 {
5884 int i;
5885
5886 /* try to find the name of this signal */
5887 for (i = 0; signal_info[i].sig != -1; i++)
5888 if (lc_signal == signal_info[i].sig)
5889 break;
5890 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
5891 }
5892# endif
5893# endif
5894
Bram Moolenaar071d4272004-06-13 20:20:40 +00005895# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005896 /* "dlerr" must be used before dlclose() */
5897 if (dlerr != NULL)
5898 EMSG2(_("dlerror = \"%s\""), dlerr);
5899
5900 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005901 (void)dlclose(hinstLib);
5902# else
5903 (void)shl_unload(hinstLib);
5904# endif
5905 }
5906
5907 if (!success)
5908 {
5909 EMSG2(_(e_libcall), funcname);
5910 return FAIL;
5911 }
5912
5913 return OK;
5914}
5915#endif
5916
5917#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
5918static int xterm_trace = -1; /* default: disabled */
5919static int xterm_button;
5920
5921/*
5922 * Setup a dummy window for X selections in a terminal.
5923 */
5924 void
5925setup_term_clip()
5926{
5927 int z = 0;
5928 char *strp = "";
5929 Widget AppShell;
5930
5931 if (!x_connect_to_server())
5932 return;
5933
5934 open_app_context();
5935 if (app_context != NULL && xterm_Shell == (Widget)0)
5936 {
5937 int (*oldhandler)();
5938#if defined(HAVE_SETJMP_H)
5939 int (*oldIOhandler)();
5940#endif
5941# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5942 struct timeval start_tv;
5943
5944 if (p_verbose > 0)
5945 gettimeofday(&start_tv, NULL);
5946# endif
5947
5948 /* Ignore X errors while opening the display */
5949 oldhandler = XSetErrorHandler(x_error_check);
5950
5951#if defined(HAVE_SETJMP_H)
5952 /* Ignore X IO errors while opening the display */
5953 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
5954 mch_startjmp();
5955 if (SETJMP(lc_jump_env) != 0)
5956 {
5957 mch_didjmp();
5958 xterm_dpy = NULL;
5959 }
5960 else
5961#endif
5962 {
5963 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
5964 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
5965#if defined(HAVE_SETJMP_H)
5966 mch_endjmp();
5967#endif
5968 }
5969
5970#if defined(HAVE_SETJMP_H)
5971 /* Now handle X IO errors normally. */
5972 (void)XSetIOErrorHandler(oldIOhandler);
5973#endif
5974 /* Now handle X errors normally. */
5975 (void)XSetErrorHandler(oldhandler);
5976
5977 if (xterm_dpy == NULL)
5978 {
5979 if (p_verbose > 0)
5980 MSG(_("Opening the X display failed"));
5981 return;
5982 }
5983
5984 /* Catch terminating error of the X server connection. */
5985 (void)XSetIOErrorHandler(x_IOerror_handler);
5986
5987# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5988 if (p_verbose > 0)
5989 xopen_message(&start_tv);
5990# endif
5991
5992 /* Create a Shell to make converters work. */
5993 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
5994 applicationShellWidgetClass, xterm_dpy,
5995 NULL);
5996 if (AppShell == (Widget)0)
5997 return;
5998 xterm_Shell = XtVaCreatePopupShell("VIM",
5999 topLevelShellWidgetClass, AppShell,
6000 XtNmappedWhenManaged, 0,
6001 XtNwidth, 1,
6002 XtNheight, 1,
6003 NULL);
6004 if (xterm_Shell == (Widget)0)
6005 return;
6006
6007 x11_setup_atoms(xterm_dpy);
6008 if (x11_display == NULL)
6009 x11_display = xterm_dpy;
6010
6011 XtRealizeWidget(xterm_Shell);
6012 XSync(xterm_dpy, False);
6013 xterm_update();
6014 }
6015 if (xterm_Shell != (Widget)0)
6016 {
6017 clip_init(TRUE);
6018 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6019 x11_window = (Window)atol(strp);
6020 /* Check if $WINDOWID is valid. */
6021 if (test_x11_window(xterm_dpy) == FAIL)
6022 x11_window = 0;
6023 if (x11_window != 0)
6024 xterm_trace = 0;
6025 }
6026}
6027
6028 void
6029start_xterm_trace(button)
6030 int button;
6031{
6032 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6033 return;
6034 xterm_trace = 1;
6035 xterm_button = button;
6036 do_xterm_trace();
6037}
6038
6039
6040 void
6041stop_xterm_trace()
6042{
6043 if (xterm_trace < 0)
6044 return;
6045 xterm_trace = 0;
6046}
6047
6048/*
6049 * Query the xterm pointer and generate mouse termcodes if necessary
6050 * return TRUE if dragging is active, else FALSE
6051 */
6052 static int
6053do_xterm_trace()
6054{
6055 Window root, child;
6056 int root_x, root_y;
6057 int win_x, win_y;
6058 int row, col;
6059 int_u mask_return;
6060 char_u buf[50];
6061 char_u *strp;
6062 long got_hints;
6063 static char_u *mouse_code;
6064 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6065 static int prev_row = 0, prev_col = 0;
6066 static XSizeHints xterm_hints;
6067
6068 if (xterm_trace <= 0)
6069 return FALSE;
6070
6071 if (xterm_trace == 1)
6072 {
6073 /* Get the hints just before tracking starts. The font size might
6074 * have changed recently */
6075 XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints);
6076 if (!(got_hints & PResizeInc)
6077 || xterm_hints.width_inc <= 1
6078 || xterm_hints.height_inc <= 1)
6079 {
6080 xterm_trace = -1; /* Not enough data -- disable tracing */
6081 return FALSE;
6082 }
6083
6084 /* Rely on the same mouse code for the duration of this */
6085 mouse_code = find_termcode(mouse_name);
6086 prev_row = mouse_row;
6087 prev_row = mouse_col;
6088 xterm_trace = 2;
6089
6090 /* Find the offset of the chars, there might be a scrollbar on the
6091 * left of the window and/or a menu on the top (eterm etc.) */
6092 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6093 &win_x, &win_y, &mask_return);
6094 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6095 - (xterm_hints.height_inc / 2);
6096 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6097 xterm_hints.y = 2;
6098 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6099 - (xterm_hints.width_inc / 2);
6100 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6101 xterm_hints.x = 2;
6102 return TRUE;
6103 }
6104 if (mouse_code == NULL)
6105 {
6106 xterm_trace = 0;
6107 return FALSE;
6108 }
6109
6110 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6111 &win_x, &win_y, &mask_return);
6112
6113 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6114 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6115 if (row == prev_row && col == prev_col)
6116 return TRUE;
6117
6118 STRCPY(buf, mouse_code);
6119 strp = buf + STRLEN(buf);
6120 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6121 *strp++ = (char_u)(col + ' ' + 1);
6122 *strp++ = (char_u)(row + ' ' + 1);
6123 *strp = 0;
6124 add_to_input_buf(buf, STRLEN(buf));
6125
6126 prev_row = row;
6127 prev_col = col;
6128 return TRUE;
6129}
6130
6131# if defined(FEAT_GUI) || defined(PROTO)
6132/*
6133 * Destroy the display, window and app_context. Required for GTK.
6134 */
6135 void
6136clear_xterm_clip()
6137{
6138 if (xterm_Shell != (Widget)0)
6139 {
6140 XtDestroyWidget(xterm_Shell);
6141 xterm_Shell = (Widget)0;
6142 }
6143 if (xterm_dpy != NULL)
6144 {
6145#if 0
6146 /* Lesstif and Solaris crash here, lose some memory */
6147 XtCloseDisplay(xterm_dpy);
6148#endif
6149 if (x11_display == xterm_dpy)
6150 x11_display = NULL;
6151 xterm_dpy = NULL;
6152 }
6153#if 0
6154 if (app_context != (XtAppContext)NULL)
6155 {
6156 /* Lesstif and Solaris crash here, lose some memory */
6157 XtDestroyApplicationContext(app_context);
6158 app_context = (XtAppContext)NULL;
6159 }
6160#endif
6161}
6162# endif
6163
6164/*
6165 * Catch up with any queued X events. This may put keyboard input into the
6166 * input buffer, call resize call-backs, trigger timers etc. If there is
6167 * nothing in the X event queue (& no timers pending), then we return
6168 * immediately.
6169 */
6170 static void
6171xterm_update()
6172{
6173 XEvent event;
6174
6175 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6176 {
6177 XtAppNextEvent(app_context, &event);
6178#ifdef FEAT_CLIENTSERVER
6179 {
6180 XPropertyEvent *e = (XPropertyEvent *)&event;
6181
6182 if (e->type == PropertyNotify && e->window == commWindow
6183 && e->atom == commProperty && e->state == PropertyNewValue)
6184 serverEventProc(xterm_dpy, &event);
6185 }
6186#endif
6187 XtDispatchEvent(&event);
6188 }
6189}
6190
6191 int
6192clip_xterm_own_selection(cbd)
6193 VimClipboard *cbd;
6194{
6195 if (xterm_Shell != (Widget)0)
6196 return clip_x11_own_selection(xterm_Shell, cbd);
6197 return FAIL;
6198}
6199
6200 void
6201clip_xterm_lose_selection(cbd)
6202 VimClipboard *cbd;
6203{
6204 if (xterm_Shell != (Widget)0)
6205 clip_x11_lose_selection(xterm_Shell, cbd);
6206}
6207
6208 void
6209clip_xterm_request_selection(cbd)
6210 VimClipboard *cbd;
6211{
6212 if (xterm_Shell != (Widget)0)
6213 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6214}
6215
6216 void
6217clip_xterm_set_selection(cbd)
6218 VimClipboard *cbd;
6219{
6220 clip_x11_set_selection(cbd);
6221}
6222#endif
6223
6224
6225#if defined(USE_XSMP) || defined(PROTO)
6226/*
6227 * Code for X Session Management Protocol.
6228 */
6229static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6230static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6231static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6232static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6233static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6234
6235
6236# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6237static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6238
6239/*
6240 * This is our chance to ask the user if they want to save,
6241 * or abort the logout
6242 */
6243/*ARGSUSED*/
6244 static void
6245xsmp_handle_interaction(smc_conn, client_data)
6246 SmcConn smc_conn;
6247 SmPointer client_data;
6248{
6249 cmdmod_T save_cmdmod;
6250 int cancel_shutdown = False;
6251
6252 save_cmdmod = cmdmod;
6253 cmdmod.confirm = TRUE;
6254 if (check_changed_any(FALSE))
6255 /* Mustn't logout */
6256 cancel_shutdown = True;
6257 cmdmod = save_cmdmod;
6258 setcursor(); /* position cursor */
6259 out_flush();
6260
6261 /* Done interaction */
6262 SmcInteractDone(smc_conn, cancel_shutdown);
6263
6264 /* Finish off
6265 * Only end save-yourself here if we're not cancelling shutdown;
6266 * we'll get a cancelled callback later in which we'll end it.
6267 * Hopefully get around glitchy SMs (like GNOME-1)
6268 */
6269 if (!cancel_shutdown)
6270 {
6271 xsmp.save_yourself = False;
6272 SmcSaveYourselfDone(smc_conn, True);
6273 }
6274}
6275# endif
6276
6277/*
6278 * Callback that starts save-yourself.
6279 */
6280/*ARGSUSED*/
6281 static void
6282xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6283 shutdown, interact_style, fast)
6284 SmcConn smc_conn;
6285 SmPointer client_data;
6286 int save_type;
6287 Bool shutdown;
6288 int interact_style;
6289 Bool fast;
6290{
6291 /* Handle already being in saveyourself */
6292 if (xsmp.save_yourself)
6293 SmcSaveYourselfDone(smc_conn, True);
6294 xsmp.save_yourself = True;
6295 xsmp.shutdown = shutdown;
6296
6297 /* First up, preserve all files */
6298 out_flush();
6299 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6300
6301 if (p_verbose > 0)
6302 MSG(_("XSMP handling save-yourself request"));
6303
6304# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6305 /* Now see if we can ask about unsaved files */
6306 if (shutdown && !fast && gui.in_use)
6307 /* Need to interact with user, but need SM's permission */
6308 SmcInteractRequest(smc_conn, SmDialogError,
6309 xsmp_handle_interaction, client_data);
6310 else
6311# endif
6312 {
6313 /* Can stop the cycle here */
6314 SmcSaveYourselfDone(smc_conn, True);
6315 xsmp.save_yourself = False;
6316 }
6317}
6318
6319
6320/*
6321 * Callback to warn us of imminent death.
6322 */
6323/*ARGSUSED*/
6324 static void
6325xsmp_die(smc_conn, client_data)
6326 SmcConn smc_conn;
6327 SmPointer client_data;
6328{
6329 xsmp_close();
6330
6331 /* quit quickly leaving swapfiles for modified buffers behind */
6332 getout_preserve_modified(0);
6333}
6334
6335
6336/*
6337 * Callback to tell us that save-yourself has completed.
6338 */
6339/*ARGSUSED*/
6340 static void
6341xsmp_save_complete(smc_conn, client_data)
6342 SmcConn smc_conn;
6343 SmPointer client_data;
6344{
6345 xsmp.save_yourself = False;
6346}
6347
6348
6349/*
6350 * Callback to tell us that an instigated shutdown was cancelled
6351 * (maybe even by us)
6352 */
6353/*ARGSUSED*/
6354 static void
6355xsmp_shutdown_cancelled(smc_conn, client_data)
6356 SmcConn smc_conn;
6357 SmPointer client_data;
6358{
6359 if (xsmp.save_yourself)
6360 SmcSaveYourselfDone(smc_conn, True);
6361 xsmp.save_yourself = False;
6362 xsmp.shutdown = False;
6363}
6364
6365
6366/*
6367 * Callback to tell us that a new ICE connection has been established.
6368 */
6369/*ARGSUSED*/
6370 static void
6371xsmp_ice_connection(iceConn, clientData, opening, watchData)
6372 IceConn iceConn;
6373 IcePointer clientData;
6374 Bool opening;
6375 IcePointer *watchData;
6376{
6377 /* Intercept creation of ICE connection fd */
6378 if (opening)
6379 {
6380 xsmp_icefd = IceConnectionNumber(iceConn);
6381 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6382 }
6383}
6384
6385
6386/* Handle any ICE processing that's required; return FAIL if SM lost */
6387 int
6388xsmp_handle_requests()
6389{
6390 Bool rep;
6391
6392 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6393 == IceProcessMessagesIOError)
6394 {
6395 /* Lost ICE */
6396 if (p_verbose > 0)
6397 MSG(_("XSMP lost ICE connection"));
6398 xsmp_close();
6399 return FAIL;
6400 }
6401 else
6402 return OK;
6403}
6404
6405static int dummy;
6406
6407/* Set up X Session Management Protocol */
6408 void
6409xsmp_init(void)
6410{
6411 char errorstring[80];
6412 char *clientid;
6413 SmcCallbacks smcallbacks;
6414#if 0
6415 SmPropValue smname;
6416 SmProp smnameprop;
6417 SmProp *smprops[1];
6418#endif
6419
6420 if (p_verbose > 0)
6421 MSG(_("XSMP opening connection"));
6422
6423 xsmp.save_yourself = xsmp.shutdown = False;
6424
6425 /* Set up SM callbacks - must have all, even if they're not used */
6426 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6427 smcallbacks.save_yourself.client_data = NULL;
6428 smcallbacks.die.callback = xsmp_die;
6429 smcallbacks.die.client_data = NULL;
6430 smcallbacks.save_complete.callback = xsmp_save_complete;
6431 smcallbacks.save_complete.client_data = NULL;
6432 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6433 smcallbacks.shutdown_cancelled.client_data = NULL;
6434
6435 /* Set up a watch on ICE connection creations. The "dummy" argument is
6436 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6437 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6438 {
6439 if (p_verbose > 0)
6440 MSG(_("XSMP ICE connection watch failed"));
6441 return;
6442 }
6443
6444 /* Create an SM connection */
6445 xsmp.smcconn = SmcOpenConnection(
6446 NULL,
6447 NULL,
6448 SmProtoMajor,
6449 SmProtoMinor,
6450 SmcSaveYourselfProcMask | SmcDieProcMask
6451 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6452 &smcallbacks,
6453 NULL,
6454 &clientid,
6455 sizeof(errorstring),
6456 errorstring);
6457 if (xsmp.smcconn == NULL)
6458 {
6459 char errorreport[132];
6460 sprintf(errorreport, _("XSMP SmcOpenConnection failed: %s"),
6461 errorstring);
6462 if (p_verbose > 0)
6463 MSG(errorreport);
6464 return;
6465 }
6466 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6467
6468#if 0
6469 /* ID ourselves */
6470 smname.value = "vim";
6471 smname.length = 3;
6472 smnameprop.name = "SmProgram";
6473 smnameprop.type = "SmARRAY8";
6474 smnameprop.num_vals = 1;
6475 smnameprop.vals = &smname;
6476
6477 smprops[0] = &smnameprop;
6478 SmcSetProperties(xsmp.smcconn, 1, smprops);
6479#endif
6480}
6481
6482
6483/* Shut down XSMP comms. */
6484 void
6485xsmp_close()
6486{
6487 if (xsmp_icefd != -1)
6488 {
6489 SmcCloseConnection(xsmp.smcconn, 0, NULL);
6490 xsmp_icefd = -1;
6491 }
6492}
6493#endif /* USE_XSMP */
6494
6495
6496#ifdef EBCDIC
6497/* Translate character to its CTRL- value */
6498char CtrlTable[] =
6499{
6500/* 00 - 5E */
6501 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6502 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6503 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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,
6507/* ^ */ 0x1E,
6508/* - */ 0x1F,
6509/* 61 - 6C */
6510 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6511/* _ */ 0x1F,
6512/* 6E - 80 */
6513 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6514/* a */ 0x01,
6515/* b */ 0x02,
6516/* c */ 0x03,
6517/* d */ 0x37,
6518/* e */ 0x2D,
6519/* f */ 0x2E,
6520/* g */ 0x2F,
6521/* h */ 0x16,
6522/* i */ 0x05,
6523/* 8A - 90 */
6524 0, 0, 0, 0, 0, 0, 0,
6525/* j */ 0x15,
6526/* k */ 0x0B,
6527/* l */ 0x0C,
6528/* m */ 0x0D,
6529/* n */ 0x0E,
6530/* o */ 0x0F,
6531/* p */ 0x10,
6532/* q */ 0x11,
6533/* r */ 0x12,
6534/* 9A - A1 */
6535 0, 0, 0, 0, 0, 0, 0, 0,
6536/* s */ 0x13,
6537/* t */ 0x3C,
6538/* u */ 0x3D,
6539/* v */ 0x32,
6540/* w */ 0x26,
6541/* x */ 0x18,
6542/* y */ 0x19,
6543/* z */ 0x3F,
6544/* AA - AC */
6545 0, 0, 0,
6546/* [ */ 0x27,
6547/* AE - BC */
6548 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6549/* ] */ 0x1D,
6550/* BE - C0 */ 0, 0, 0,
6551/* A */ 0x01,
6552/* B */ 0x02,
6553/* C */ 0x03,
6554/* D */ 0x37,
6555/* E */ 0x2D,
6556/* F */ 0x2E,
6557/* G */ 0x2F,
6558/* H */ 0x16,
6559/* I */ 0x05,
6560/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6561/* J */ 0x15,
6562/* K */ 0x0B,
6563/* L */ 0x0C,
6564/* M */ 0x0D,
6565/* N */ 0x0E,
6566/* O */ 0x0F,
6567/* P */ 0x10,
6568/* Q */ 0x11,
6569/* R */ 0x12,
6570/* DA - DF */ 0, 0, 0, 0, 0, 0,
6571/* \ */ 0x1C,
6572/* E1 */ 0,
6573/* S */ 0x13,
6574/* T */ 0x3C,
6575/* U */ 0x3D,
6576/* V */ 0x32,
6577/* W */ 0x26,
6578/* X */ 0x18,
6579/* Y */ 0x19,
6580/* Z */ 0x3F,
6581/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6582 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6583};
6584
6585char MetaCharTable[]=
6586{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6587 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6588 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6589 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6590 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6591};
6592
6593
6594/* TODO: Use characters NOT numbers!!! */
6595char CtrlCharTable[]=
6596{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6597 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6598 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6599 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6600 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6601};
6602
6603
6604#endif