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