blob: 945092f15765c7577f6a20b397210fdcea573f53 [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 */
3833 for (;;)
3834 {
3835 l = STRLEN(p + written);
3836 if (l == 0)
3837 len = 0;
3838 else if (p[written] == NL)
3839 /* NL -> NUL translation */
3840 len = write(toshell_fd, "", (size_t)1);
3841 else
3842 {
3843 s = vim_strchr(p + written, NL);
3844 len = write(toshell_fd, (char *)p + written,
3845 s == NULL ? l : s - (p + written));
3846 }
3847 if (len == l)
3848 {
3849 /* Finished a line, add a NL, unless this line
3850 * should not have one. */
3851 if (lnum != curbuf->b_op_end.lnum
3852 || !curbuf->b_p_bin
3853 || (lnum != write_no_eol_lnum
3854 && (lnum !=
3855 curbuf->b_ml.ml_line_count
3856 || curbuf->b_p_eol)))
3857 write(toshell_fd, "\n", (size_t)1);
3858 ++lnum;
3859 if (lnum > curbuf->b_op_end.lnum)
3860 {
3861 /* finished all the lines, close pipe */
3862 close(toshell_fd);
3863 toshell_fd = -1;
3864 break;
3865 }
3866 p = ml_get(lnum);
3867 written = 0;
3868 }
3869 else if (len > 0)
3870 written += len;
3871 }
3872 _exit(0);
3873 }
3874 else
3875 {
3876 close(toshell_fd);
3877 toshell_fd = -1;
3878 }
3879 }
3880
3881 if (options & SHELL_READ)
3882 ga_init2(&ga, 1, BUFLEN);
3883
3884 noread_cnt = 0;
3885
Bram Moolenaar071d4272004-06-13 20:20:40 +00003886 for (;;)
3887 {
3888 /*
3889 * Check if keys have been typed, write them to the child
3890 * if there are any. Don't do this if we are expanding
3891 * wild cards (would eat typeahead). Don't get extra
3892 * characters when we already have one.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003893 * Don't read characters unless we didn't get output for a
3894 * while, avoids that ":r !ls" eats typeahead.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003895 */
3896 len = 0;
3897 if (!(options & SHELL_EXPAND)
3898 && (ta_len > 0
Bram Moolenaardf177f62005-02-22 08:39:57 +00003899 || (noread_cnt > 4
3900 && (len = ui_inchar(ta_buf,
3901 BUFLEN, 10L, 0)) > 0)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003902 {
3903 /*
3904 * For pipes:
3905 * Check for CTRL-C: send interrupt signal to child.
3906 * Check for CTRL-D: EOF, close pipe to child.
3907 */
3908 if (len == 1 && (pty_master_fd < 0 || cmd != NULL))
3909 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00003910# ifdef SIGINT
Bram Moolenaar071d4272004-06-13 20:20:40 +00003911 /*
3912 * Send SIGINT to the child's group or all
3913 * processes in our group.
3914 */
3915 if (ta_buf[ta_len] == Ctrl_C
3916 || ta_buf[ta_len] == intr_char)
Bram Moolenaardf177f62005-02-22 08:39:57 +00003917 {
3918# ifdef HAVE_SETSID
Bram Moolenaar071d4272004-06-13 20:20:40 +00003919 kill(-pid, SIGINT);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003920# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003921 kill(0, SIGINT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003922# endif
Bram Moolenaardf177f62005-02-22 08:39:57 +00003923 if (wpid > 0)
3924 kill(wpid, SIGINT);
3925 }
3926# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003927 if (pty_master_fd < 0 && toshell_fd >= 0
3928 && ta_buf[ta_len] == Ctrl_D)
3929 {
3930 close(toshell_fd);
3931 toshell_fd = -1;
3932 }
3933 }
3934
3935 /* replace K_BS by <BS> and K_DEL by <DEL> */
3936 for (i = ta_len; i < ta_len + len; ++i)
3937 {
3938 if (ta_buf[i] == CSI && len - i > 2)
3939 {
3940 c = TERMCAP2KEY(ta_buf[i + 1], ta_buf[i + 2]);
3941 if (c == K_DEL || c == K_KDEL || c == K_BS)
3942 {
3943 mch_memmove(ta_buf + i + 1, ta_buf + i + 3,
3944 (size_t)(len - i - 2));
3945 if (c == K_DEL || c == K_KDEL)
3946 ta_buf[i] = DEL;
3947 else
3948 ta_buf[i] = Ctrl_H;
3949 len -= 2;
3950 }
3951 }
3952 else if (ta_buf[i] == '\r')
3953 ta_buf[i] = '\n';
Bram Moolenaardf177f62005-02-22 08:39:57 +00003954# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955 if (has_mbyte)
3956 i += (*mb_ptr2len_check)(ta_buf + i) - 1;
Bram Moolenaardf177f62005-02-22 08:39:57 +00003957# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003958 }
3959
3960 /*
3961 * For pipes: echo the typed characters.
3962 * For a pty this does not seem to work.
3963 */
3964 if (pty_master_fd < 0)
3965 {
3966 for (i = ta_len; i < ta_len + len; ++i)
3967 {
3968 if (ta_buf[i] == '\n' || ta_buf[i] == '\b')
3969 msg_putchar(ta_buf[i]);
Bram Moolenaardf177f62005-02-22 08:39:57 +00003970# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00003971 else if (has_mbyte)
3972 {
3973 int l = (*mb_ptr2len_check)(ta_buf + i);
3974
3975 msg_outtrans_len(ta_buf + i, l);
3976 i += l - 1;
3977 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00003978# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003979 else
3980 msg_outtrans_len(ta_buf + i, 1);
3981 }
3982 windgoto(msg_row, msg_col);
3983 out_flush();
3984 }
3985
3986 ta_len += len;
3987
3988 /*
3989 * Write the characters to the child, unless EOF has
3990 * been typed for pipes. Write one character at a
3991 * time, to avoid loosing too much typeahead.
Bram Moolenaardf177f62005-02-22 08:39:57 +00003992 * When writing buffer lines, drop the typed
3993 * characters (only check for CTRL-C).
Bram Moolenaar071d4272004-06-13 20:20:40 +00003994 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00003995 if (options & SHELL_WRITE)
3996 ta_len = 0;
3997 else if (toshell_fd >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003998 {
3999 len = write(toshell_fd, (char *)ta_buf, (size_t)1);
4000 if (len > 0)
4001 {
4002 ta_len -= len;
4003 mch_memmove(ta_buf, ta_buf + len, ta_len);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004004 noread_cnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004005 }
4006 }
4007 }
4008
Bram Moolenaardf177f62005-02-22 08:39:57 +00004009 if (got_int)
4010 {
4011 /* CTRL-C sends a signal to the child, we ignore it
4012 * ourselves */
4013# ifdef HAVE_SETSID
4014 kill(-pid, SIGINT);
4015# else
4016 kill(0, SIGINT);
4017# endif
4018 if (wpid > 0)
4019 kill(wpid, SIGINT);
4020 got_int = FALSE;
4021 }
4022
Bram Moolenaar071d4272004-06-13 20:20:40 +00004023 /*
4024 * Check if the child has any characters to be printed.
4025 * Read them and write them to our window. Repeat this as
4026 * long as there is something to do, avoid the 10ms wait
4027 * for mch_inchar(), or sending typeahead characters to
4028 * the external process.
4029 * TODO: This should handle escape sequences, compatible
4030 * to some terminal (vt52?).
4031 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004032 ++noread_cnt;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004033 while (RealWaitForChar(fromshell_fd, 10L, NULL))
4034 {
4035 len = read(fromshell_fd, (char *)buffer
Bram Moolenaardf177f62005-02-22 08:39:57 +00004036# ifdef FEAT_MBYTE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004037 + buffer_off, (size_t)(BUFLEN - buffer_off)
Bram Moolenaardf177f62005-02-22 08:39:57 +00004038# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004039 , (size_t)BUFLEN
Bram Moolenaardf177f62005-02-22 08:39:57 +00004040# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004041 );
4042 if (len <= 0) /* end of file or error */
4043 goto finished;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004044
4045 noread_cnt = 0;
4046 if (options & SHELL_READ)
4047 {
4048 /* Do NUL -> NL translation, append NL separated
4049 * lines to the current buffer. */
4050 for (i = 0; i < len; ++i)
4051 {
4052 if (buffer[i] == NL)
4053 append_ga_line(&ga);
4054 else if (buffer[i] == NUL)
4055 ga_append(&ga, NL);
4056 else
4057 ga_append(&ga, buffer[i]);
4058 }
4059 }
4060# ifdef FEAT_MBYTE
4061 else if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004062 {
4063 int l;
4064
Bram Moolenaardf177f62005-02-22 08:39:57 +00004065 len += buffer_off;
4066 buffer[len] = NUL;
4067
Bram Moolenaar071d4272004-06-13 20:20:40 +00004068 /* Check if the last character in buffer[] is
4069 * incomplete, keep these bytes for the next
4070 * round. */
4071 for (p = buffer; p < buffer + len; p += l)
4072 {
4073 if (enc_utf8) /* exclude composing chars */
4074 l = utf_ptr2len_check(p);
4075 else
4076 l = (*mb_ptr2len_check)(p);
4077 if (l == 0)
4078 l = 1; /* NUL byte? */
4079 else if (MB_BYTE2LEN(*p) != l)
4080 break;
4081 }
4082 if (p == buffer) /* no complete character */
4083 {
4084 /* avoid getting stuck at an illegal byte */
4085 if (len >= 12)
4086 ++p;
4087 else
4088 {
4089 buffer_off = len;
4090 continue;
4091 }
4092 }
4093 c = *p;
4094 *p = NUL;
4095 msg_puts(buffer);
4096 if (p < buffer + len)
4097 {
4098 *p = c;
4099 buffer_off = (buffer + len) - p;
4100 mch_memmove(buffer, p, buffer_off);
4101 continue;
4102 }
4103 buffer_off = 0;
4104 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004105# endif /* FEAT_MBYTE */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004106 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004107 {
4108 buffer[len] = NUL;
4109 msg_puts(buffer);
4110 }
4111
4112 windgoto(msg_row, msg_col);
4113 cursor_on();
4114 out_flush();
4115 if (got_int)
4116 break;
4117 }
4118
4119 /*
4120 * Check if the child still exists, before checking for
4121 * typed characters (otherwise we would loose typeahead).
4122 */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004123# ifdef __NeXT__
Bram Moolenaar071d4272004-06-13 20:20:40 +00004124 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *) 0);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004125# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004126 wait_pid = waitpid(pid, &status, WNOHANG);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004127# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004128 if ((wait_pid == (pid_t)-1 && errno == ECHILD)
4129 || (wait_pid == pid && WIFEXITED(status)))
4130 {
4131 wait_pid = pid;
4132 break;
4133 }
4134 wait_pid = 0;
4135 }
4136finished:
4137 p_more = p_more_save;
Bram Moolenaardf177f62005-02-22 08:39:57 +00004138 if (options & SHELL_READ)
4139 {
4140 if (ga.ga_len > 0)
4141 {
4142 append_ga_line(&ga);
4143 /* remember that the NL was missing */
4144 write_no_eol_lnum = curwin->w_cursor.lnum;
4145 }
4146 else
4147 write_no_eol_lnum = 0;
4148 ga_clear(&ga);
4149 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004150
Bram Moolenaar071d4272004-06-13 20:20:40 +00004151 /*
4152 * Give all typeahead that wasn't used back to ui_inchar().
4153 */
4154 if (ta_len)
4155 ui_inchar_undo(ta_buf, ta_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004156 State = old_State;
4157 if (toshell_fd >= 0)
4158 close(toshell_fd);
4159 close(fromshell_fd);
4160 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161
4162 /*
4163 * Wait until our child has exited.
4164 * Ignore wait() returning pids of other children and returning
4165 * because of some signal like SIGWINCH.
4166 * Don't wait if wait_pid was already set above, indicating the
4167 * child already exited.
4168 */
4169 while (wait_pid != pid)
4170 {
Bram Moolenaardf177f62005-02-22 08:39:57 +00004171# ifdef _THREAD_SAFE
Bram Moolenaar071d4272004-06-13 20:20:40 +00004172 /* Ugly hack: when compiled with Python threads are probably
4173 * used, in which case wait() sometimes hangs for no obvious
4174 * reason. Use waitpid() instead and loop (like the GUI). */
4175# ifdef __NeXT__
4176 wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
4177# else
4178 wait_pid = waitpid(pid, &status, WNOHANG);
4179# endif
4180 if (wait_pid == 0)
4181 {
4182 /* Wait for 1/100 sec before trying again. */
4183 mch_delay(10L, TRUE);
4184 continue;
4185 }
Bram Moolenaardf177f62005-02-22 08:39:57 +00004186# else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004187 wait_pid = wait(&status);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004188# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004189 if (wait_pid <= 0
4190# ifdef ECHILD
4191 && errno == ECHILD
4192# endif
4193 )
4194 break;
4195 }
4196
Bram Moolenaardf177f62005-02-22 08:39:57 +00004197 /* Make sure the child that writes to the external program is
4198 * dead. */
4199 if (wpid > 0)
4200 kill(wpid, SIGKILL);
4201
Bram Moolenaar071d4272004-06-13 20:20:40 +00004202 /*
4203 * Set to raw mode right now, otherwise a CTRL-C after
4204 * catch_signals() will kill Vim.
4205 */
4206 if (tmode == TMODE_RAW)
4207 settmode(TMODE_RAW);
4208 did_settmode = TRUE;
4209 set_signals();
4210
4211 if (WIFEXITED(status))
4212 {
Bram Moolenaar9d75c832005-01-25 21:57:23 +00004213 /* LINTED avoid "bitwise operation on signed value" */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004214 retval = WEXITSTATUS(status);
4215 if (retval && !emsg_silent)
4216 {
4217 if (retval == EXEC_FAILED)
4218 {
4219 MSG_PUTS(_("\nCannot execute shell "));
4220 msg_outtrans(p_sh);
4221 msg_putchar('\n');
4222 }
4223 else if (!(options & SHELL_SILENT))
4224 {
4225 MSG_PUTS(_("\nshell returned "));
4226 msg_outnum((long)retval);
4227 msg_putchar('\n');
4228 }
4229 }
4230 }
4231 else
4232 MSG_PUTS(_("\nCommand terminated\n"));
4233 }
4234 }
4235 vim_free(argv);
4236
4237error:
4238 if (!did_settmode)
4239 if (tmode == TMODE_RAW)
4240 settmode(TMODE_RAW); /* set to raw mode */
4241# ifdef FEAT_TITLE
4242 resettitle();
4243# endif
4244 vim_free(newcmd);
4245
4246 return retval;
4247
4248#endif /* USE_SYSTEM */
4249}
4250
4251/*
4252 * Check for CTRL-C typed by reading all available characters.
4253 * In cooked mode we should get SIGINT, no need to check.
4254 */
4255 void
4256mch_breakcheck()
4257{
4258 if (curr_tmode == TMODE_RAW && RealWaitForChar(read_cmd_fd, 0L, NULL))
4259 fill_input_buf(FALSE);
4260}
4261
4262/*
4263 * Wait "msec" msec until a character is available from the keyboard or from
4264 * inbuf[]. msec == -1 will block forever.
4265 * When a GUI is being used, this will never get called -- webb
4266 */
4267 static int
4268WaitForChar(msec)
4269 long msec;
4270{
4271#ifdef FEAT_MOUSE_GPM
4272 int gpm_process_wanted;
4273#endif
4274#ifdef FEAT_XCLIPBOARD
4275 int rest;
4276#endif
4277 int avail;
4278
4279 if (input_available()) /* something in inbuf[] */
4280 return 1;
4281
4282#if defined(FEAT_MOUSE_DEC)
4283 /* May need to query the mouse position. */
4284 if (WantQueryMouse)
4285 {
4286 WantQueryMouse = 0;
4287 mch_write((char_u *)IF_EB("\033[1'|", ESC_STR "[1'|"), 5);
4288 }
4289#endif
4290
4291 /*
4292 * For FEAT_MOUSE_GPM and FEAT_XCLIPBOARD we loop here to process mouse
4293 * events. This is a bit complicated, because they might both be defined.
4294 */
4295#if defined(FEAT_MOUSE_GPM) || defined(FEAT_XCLIPBOARD)
4296# ifdef FEAT_XCLIPBOARD
4297 rest = 0;
4298 if (do_xterm_trace())
4299 rest = msec;
4300# endif
4301 do
4302 {
4303# ifdef FEAT_XCLIPBOARD
4304 if (rest != 0)
4305 {
4306 msec = XT_TRACE_DELAY;
4307 if (rest >= 0 && rest < XT_TRACE_DELAY)
4308 msec = rest;
4309 if (rest >= 0)
4310 rest -= msec;
4311 }
4312# endif
4313# ifdef FEAT_MOUSE_GPM
4314 gpm_process_wanted = 0;
4315 avail = RealWaitForChar(read_cmd_fd, msec, &gpm_process_wanted);
4316# else
4317 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4318# endif
4319 if (!avail)
4320 {
4321 if (input_available())
4322 return 1;
4323# ifdef FEAT_XCLIPBOARD
4324 if (rest == 0 || !do_xterm_trace())
4325# endif
4326 break;
4327 }
4328 }
4329 while (FALSE
4330# ifdef FEAT_MOUSE_GPM
4331 || (gpm_process_wanted && mch_gpm_process() == 0)
4332# endif
4333# ifdef FEAT_XCLIPBOARD
4334 || (!avail && rest != 0)
4335# endif
4336 );
4337
4338#else
4339 avail = RealWaitForChar(read_cmd_fd, msec, NULL);
4340#endif
4341 return avail;
4342}
4343
4344/*
4345 * Wait "msec" msec until a character is available from file descriptor "fd".
4346 * Time == -1 will block forever.
4347 * When a GUI is being used, this will not be used for input -- webb
4348 * Returns also, when a request from Sniff is waiting -- toni.
4349 * Or when a Linux GPM mouse event is waiting.
4350 */
4351/* ARGSUSED */
4352#if defined(__BEOS__)
4353 int
4354#else
4355 static int
4356#endif
4357RealWaitForChar(fd, msec, check_for_gpm)
4358 int fd;
4359 long msec;
4360 int *check_for_gpm;
4361{
4362 int ret;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004363#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004364 static int busy = FALSE;
4365
4366 /* May retry getting characters after an event was handled. */
4367# define MAY_LOOP
4368
4369# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
4370 /* Remember at what time we started, so that we know how much longer we
4371 * should wait after being interrupted. */
4372# define USE_START_TV
4373 struct timeval start_tv;
4374
4375 if (msec > 0 && (
4376# ifdef FEAT_XCLIPBOARD
4377 xterm_Shell != (Widget)0
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004378# if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004379 ||
4380# endif
4381# endif
4382# ifdef USE_XSMP
4383 xsmp_icefd != -1
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004384# ifdef FEAT_MZSCHEME
4385 ||
4386# endif
4387# endif
4388# ifdef FEAT_MZSCHEME
4389 (mzthreads_allowed() && p_mzq > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004390# endif
4391 ))
4392 gettimeofday(&start_tv, NULL);
4393# endif
4394
4395 /* Handle being called recursively. This may happen for the session
4396 * manager stuff, it may save the file, which does a breakcheck. */
4397 if (busy)
4398 return 0;
4399#endif
4400
4401#ifdef MAY_LOOP
4402 while (1)
4403#endif
4404 {
4405#ifdef MAY_LOOP
4406 int finished = TRUE; /* default is to 'loop' just once */
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004407# ifdef FEAT_MZSCHEME
4408 int mzquantum_used = FALSE;
4409# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004410#endif
4411#ifndef HAVE_SELECT
4412 struct pollfd fds[5];
4413 int nfd;
4414# ifdef FEAT_XCLIPBOARD
4415 int xterm_idx = -1;
4416# endif
4417# ifdef FEAT_MOUSE_GPM
4418 int gpm_idx = -1;
4419# endif
4420# ifdef USE_XSMP
4421 int xsmp_idx = -1;
4422# endif
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004423 int towait = (int)msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004424
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004425# ifdef FEAT_MZSCHEME
4426 mzvim_check_threads();
4427 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4428 {
4429 towait = (int)p_mzq; /* don't wait longer than 'mzquantum' */
4430 mzquantum_used = TRUE;
4431 }
4432# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433 fds[0].fd = fd;
4434 fds[0].events = POLLIN;
4435 nfd = 1;
4436
4437# ifdef FEAT_SNIFF
4438# define SNIFF_IDX 1
4439 if (want_sniff_request)
4440 {
4441 fds[SNIFF_IDX].fd = fd_from_sniff;
4442 fds[SNIFF_IDX].events = POLLIN;
4443 nfd++;
4444 }
4445# endif
4446# ifdef FEAT_XCLIPBOARD
4447 if (xterm_Shell != (Widget)0)
4448 {
4449 xterm_idx = nfd;
4450 fds[nfd].fd = ConnectionNumber(xterm_dpy);
4451 fds[nfd].events = POLLIN;
4452 nfd++;
4453 }
4454# endif
4455# ifdef FEAT_MOUSE_GPM
4456 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4457 {
4458 gpm_idx = nfd;
4459 fds[nfd].fd = gpm_fd;
4460 fds[nfd].events = POLLIN;
4461 nfd++;
4462 }
4463# endif
4464# ifdef USE_XSMP
4465 if (xsmp_icefd != -1)
4466 {
4467 xsmp_idx = nfd;
4468 fds[nfd].fd = xsmp_icefd;
4469 fds[nfd].events = POLLIN;
4470 nfd++;
4471 }
4472# endif
4473
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004474 ret = poll(fds, nfd, towait);
4475# ifdef FEAT_MZSCHEME
4476 if (ret == 0 && mzquantum_used)
4477 /* MzThreads scheduling is required and timeout occured */
4478 finished = FALSE;
4479# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004480
4481# ifdef FEAT_SNIFF
4482 if (ret < 0)
4483 sniff_disconnect(1);
4484 else if (want_sniff_request)
4485 {
4486 if (fds[SNIFF_IDX].revents & POLLHUP)
4487 sniff_disconnect(1);
4488 if (fds[SNIFF_IDX].revents & POLLIN)
4489 sniff_request_waiting = 1;
4490 }
4491# endif
4492# ifdef FEAT_XCLIPBOARD
4493 if (xterm_Shell != (Widget)0 && (fds[xterm_idx].revents & POLLIN))
4494 {
4495 xterm_update(); /* Maybe we should hand out clipboard */
4496 if (--ret == 0 && !input_available())
4497 /* Try again */
4498 finished = FALSE;
4499 }
4500# endif
4501# ifdef FEAT_MOUSE_GPM
4502 if (gpm_idx >= 0 && (fds[gpm_idx].revents & POLLIN))
4503 {
4504 *check_for_gpm = 1;
4505 }
4506# endif
4507# ifdef USE_XSMP
4508 if (xsmp_idx >= 0 && (fds[xsmp_idx].revents & (POLLIN | POLLHUP)))
4509 {
4510 if (fds[xsmp_idx].revents & POLLIN)
4511 {
4512 busy = TRUE;
4513 xsmp_handle_requests();
4514 busy = FALSE;
4515 }
4516 else if (fds[xsmp_idx].revents & POLLHUP)
4517 {
4518 if (p_verbose > 0)
4519 MSG(_("XSMP lost ICE connection"));
4520 xsmp_close();
4521 }
4522 if (--ret == 0)
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004523 finished = FALSE; /* Try again */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004524 }
4525# endif
4526
4527
4528#else /* HAVE_SELECT */
4529
4530 struct timeval tv;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004531 struct timeval *tvp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004532 fd_set rfds, efds;
4533 int maxfd;
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004534 long towait = msec;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004535
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004536# ifdef FEAT_MZSCHEME
4537 mzvim_check_threads();
4538 if (mzthreads_allowed() && p_mzq > 0 && (msec < 0 || msec > p_mzq))
4539 {
4540 towait = p_mzq; /* don't wait longer than 'mzquantum' */
4541 mzquantum_used = TRUE;
4542 }
4543# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004544# ifdef __EMX__
4545 /* don't check for incoming chars if not in raw mode, because select()
4546 * always returns TRUE then (in some version of emx.dll) */
4547 if (curr_tmode != TMODE_RAW)
4548 return 0;
4549# endif
4550
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004551 if (towait >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004552 {
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004553 tv.tv_sec = towait / 1000;
4554 tv.tv_usec = (towait % 1000) * (1000000/1000);
4555 tvp = &tv;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004556 }
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004557 else
4558 tvp = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004559
4560 /*
4561 * Select on ready for reading and exceptional condition (end of file).
4562 */
4563 FD_ZERO(&rfds); /* calls bzero() on a sun */
4564 FD_ZERO(&efds);
4565 FD_SET(fd, &rfds);
4566# if !defined(__QNX__) && !defined(__CYGWIN32__)
4567 /* For QNX select() always returns 1 if this is set. Why? */
4568 FD_SET(fd, &efds);
4569# endif
4570 maxfd = fd;
4571
4572# ifdef FEAT_SNIFF
4573 if (want_sniff_request)
4574 {
4575 FD_SET(fd_from_sniff, &rfds);
4576 FD_SET(fd_from_sniff, &efds);
4577 if (maxfd < fd_from_sniff)
4578 maxfd = fd_from_sniff;
4579 }
4580# endif
4581# ifdef FEAT_XCLIPBOARD
4582 if (xterm_Shell != (Widget)0)
4583 {
4584 FD_SET(ConnectionNumber(xterm_dpy), &rfds);
4585 if (maxfd < ConnectionNumber(xterm_dpy))
4586 maxfd = ConnectionNumber(xterm_dpy);
4587 }
4588# endif
4589# ifdef FEAT_MOUSE_GPM
4590 if (check_for_gpm != NULL && gpm_flag && gpm_fd >= 0)
4591 {
4592 FD_SET(gpm_fd, &rfds);
4593 FD_SET(gpm_fd, &efds);
4594 if (maxfd < gpm_fd)
4595 maxfd = gpm_fd;
4596 }
4597# endif
4598# ifdef USE_XSMP
4599 if (xsmp_icefd != -1)
4600 {
4601 FD_SET(xsmp_icefd, &rfds);
4602 FD_SET(xsmp_icefd, &efds);
4603 if (maxfd < xsmp_icefd)
4604 maxfd = xsmp_icefd;
4605 }
4606# endif
4607
4608# ifdef OLD_VMS
4609 /* Old VMS as v6.2 and older have broken select(). It waits more than
4610 * required. Should not be used */
4611 ret = 0;
4612# else
Bram Moolenaar325b7a22004-07-05 15:58:32 +00004613 ret = select(maxfd + 1, &rfds, NULL, &efds, tvp);
4614# endif
4615# ifdef FEAT_MZSCHEME
4616 if (ret == 0 && mzquantum_used)
4617 /* loop if MzThreads must be scheduled and timeout occured */
4618 finished = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619# endif
4620
4621# ifdef FEAT_SNIFF
4622 if (ret < 0 )
4623 sniff_disconnect(1);
4624 else if (ret > 0 && want_sniff_request)
4625 {
4626 if (FD_ISSET(fd_from_sniff, &efds))
4627 sniff_disconnect(1);
4628 if (FD_ISSET(fd_from_sniff, &rfds))
4629 sniff_request_waiting = 1;
4630 }
4631# endif
4632# ifdef FEAT_XCLIPBOARD
4633 if (ret > 0 && xterm_Shell != (Widget)0
4634 && FD_ISSET(ConnectionNumber(xterm_dpy), &rfds))
4635 {
4636 xterm_update(); /* Maybe we should hand out clipboard */
4637 /* continue looping when we only got the X event and the input
4638 * buffer is empty */
4639 if (--ret == 0 && !input_available())
4640 {
4641 /* Try again */
4642 finished = FALSE;
4643 }
4644 }
4645# endif
4646# ifdef FEAT_MOUSE_GPM
4647 if (ret > 0 && gpm_flag && check_for_gpm != NULL && gpm_fd >= 0)
4648 {
4649 if (FD_ISSET(gpm_fd, &efds))
4650 gpm_close();
4651 else if (FD_ISSET(gpm_fd, &rfds))
4652 *check_for_gpm = 1;
4653 }
4654# endif
4655# ifdef USE_XSMP
4656 if (ret > 0 && xsmp_icefd != -1)
4657 {
4658 if (FD_ISSET(xsmp_icefd, &efds))
4659 {
4660 if (p_verbose > 0)
4661 MSG(_("XSMP lost ICE connection"));
4662 xsmp_close();
4663 if (--ret == 0)
4664 finished = FALSE; /* keep going if event was only one */
4665 }
4666 else if (FD_ISSET(xsmp_icefd, &rfds))
4667 {
4668 busy = TRUE;
4669 xsmp_handle_requests();
4670 busy = FALSE;
4671 if (--ret == 0)
4672 finished = FALSE; /* keep going if event was only one */
4673 }
4674 }
4675# endif
4676
4677#endif /* HAVE_SELECT */
4678
4679#ifdef MAY_LOOP
4680 if (finished || msec == 0)
4681 break;
4682
4683 /* We're going to loop around again, find out for how long */
4684 if (msec > 0)
4685 {
4686# ifdef USE_START_TV
4687 struct timeval mtv;
4688
4689 /* Compute remaining wait time. */
4690 gettimeofday(&mtv, NULL);
4691 msec -= (mtv.tv_sec - start_tv.tv_sec) * 1000L
4692 + (mtv.tv_usec - start_tv.tv_usec) / 1000L;
4693# else
4694 /* Guess we got interrupted halfway. */
4695 msec = msec / 2;
4696# endif
4697 if (msec <= 0)
4698 break; /* waited long enough */
4699 }
4700#endif
4701 }
4702
4703 return (ret > 0);
4704}
4705
4706#ifndef VMS
4707
4708#ifndef NO_EXPANDPATH
4709 static int
4710pstrcmp(a, b)
4711 const void *a, *b;
4712{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00004713 return (pathcmp(*(char **)a, *(char **)b, -1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004714}
4715
4716/*
4717 * Recursively expand one path component into all matching files and/or
4718 * directories.
4719 * "path" has backslashes before chars that are not to be expanded, starting
4720 * at "path + wildoff".
4721 * Return the number of matches found.
4722 */
4723 int
4724mch_expandpath(gap, path, flags)
4725 garray_T *gap;
4726 char_u *path;
4727 int flags; /* EW_* flags */
4728{
4729 return unix_expandpath(gap, path, 0, flags);
4730}
4731
4732 static int
4733unix_expandpath(gap, path, wildoff, flags)
4734 garray_T *gap;
4735 char_u *path;
4736 int wildoff;
4737 int flags; /* EW_* flags */
4738{
4739 char_u *buf;
4740 char_u *path_end;
4741 char_u *p, *s, *e;
4742 int start_len, c;
4743 char_u *pat;
4744 DIR *dirp;
4745 regmatch_T regmatch;
4746 struct dirent *dp;
4747 int starts_with_dot;
4748 int matches;
4749 int len;
4750
4751 start_len = gap->ga_len;
4752 buf = alloc(STRLEN(path) + BASENAMELEN + 5);/* make room for file name */
4753 if (buf == NULL)
4754 return 0;
4755
4756/*
4757 * Find the first part in the path name that contains a wildcard.
4758 * Copy it into buf, including the preceding characters.
4759 */
4760 p = buf;
4761 s = buf;
4762 e = NULL;
4763 path_end = path;
4764 while (*path_end != NUL)
4765 {
4766 /* May ignore a wildcard that has a backslash before it; it will
4767 * be removed by rem_backslash() or file_pat_to_reg_pat() below. */
4768 if (path_end >= path + wildoff && rem_backslash(path_end))
4769 *p++ = *path_end++;
4770 else if (*path_end == '/')
4771 {
4772 if (e != NULL)
4773 break;
4774 s = p + 1;
4775 }
4776 else if (path_end >= path + wildoff
4777 && vim_strchr((char_u *)"*?[{~$", *path_end) != NULL)
4778 e = p;
4779#ifdef FEAT_MBYTE
4780 if (has_mbyte)
4781 {
4782 len = (*mb_ptr2len_check)(path_end);
4783 STRNCPY(p, path_end, len);
4784 p += len;
4785 path_end += len;
4786 }
4787 else
4788#endif
4789 *p++ = *path_end++;
4790 }
4791 e = p;
4792 *e = NUL;
4793
4794 /* now we have one wildcard component between s and e */
4795 /* Remove backslashes between "wildoff" and the start of the wildcard
4796 * component. */
4797 for (p = buf + wildoff; p < s; ++p)
4798 if (rem_backslash(p))
4799 {
4800 STRCPY(p, p + 1);
4801 --e;
4802 --s;
4803 }
4804
4805 /* convert the file pattern to a regexp pattern */
4806 starts_with_dot = (*s == '.');
4807 pat = file_pat_to_reg_pat(s, e, NULL, FALSE);
4808 if (pat == NULL)
4809 {
4810 vim_free(buf);
4811 return 0;
4812 }
4813
4814 /* compile the regexp into a program */
4815#ifdef MACOS_X /* Can/Should we use CASE_INSENSITIVE_FILENAME instead ?*/
4816 regmatch.rm_ic = TRUE; /* Behave like Terminal.app */
4817#else
4818 regmatch.rm_ic = FALSE; /* Don't ever ignore case */
4819#endif
4820 regmatch.regprog = vim_regcomp(pat, RE_MAGIC);
4821 vim_free(pat);
4822
4823 if (regmatch.regprog == NULL)
4824 {
4825 vim_free(buf);
4826 return 0;
4827 }
4828
4829 /* open the directory for scanning */
4830 c = *s;
4831 *s = NUL;
4832 dirp = opendir(*buf == NUL ? "." : (char *)buf);
4833 *s = c;
4834
4835 /* Find all matching entries */
4836 if (dirp != NULL)
4837 {
4838 for (;;)
4839 {
4840 dp = readdir(dirp);
4841 if (dp == NULL)
4842 break;
4843 if ((dp->d_name[0] != '.' || starts_with_dot)
4844 && vim_regexec(&regmatch, (char_u *)dp->d_name, (colnr_T)0))
4845 {
4846 STRCPY(s, dp->d_name);
4847 len = STRLEN(buf);
4848 STRCPY(buf + len, path_end);
4849 if (mch_has_exp_wildcard(path_end)) /* handle more wildcards */
4850 {
4851 /* need to expand another component of the path */
4852 /* remove backslashes for the remaining components only */
4853 (void)unix_expandpath(gap, buf, len + 1, flags);
4854 }
4855 else
4856 {
4857 /* no more wildcards, check if there is a match */
4858 /* remove backslashes for the remaining components only */
4859 if (*path_end != NUL)
4860 backslash_halve(buf + len + 1);
4861 if (mch_getperm(buf) >= 0) /* add existing file */
Bram Moolenaardf177f62005-02-22 08:39:57 +00004862 {
4863#if defined(MACOS_X) && defined(FEAT_MBYTE)
4864 size_t precomp_len = STRLEN(buf)+1;
4865 char_u *precomp_buf =
4866 mac_precompose_path(buf, precomp_len, &precomp_len);
4867 if (precomp_buf)
4868 {
4869 mch_memmove(buf, precomp_buf, precomp_len);
4870 vim_free(precomp_buf);
4871 }
4872#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004873 addfile(gap, buf, flags);
Bram Moolenaardf177f62005-02-22 08:39:57 +00004874 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004875 }
4876 }
4877 }
4878
4879 closedir(dirp);
4880 }
4881
4882 vim_free(buf);
4883 vim_free(regmatch.regprog);
4884
4885 matches = gap->ga_len - start_len;
4886 if (matches > 0)
4887 qsort(((char_u **)gap->ga_data) + start_len, matches,
4888 sizeof(char_u *), pstrcmp);
4889 return matches;
4890}
4891#endif
4892
4893/*
4894 * mch_expand_wildcards() - this code does wild-card pattern matching using
4895 * the shell
4896 *
4897 * return OK for success, FAIL for error (you may lose some memory) and put
4898 * an error message in *file.
4899 *
4900 * num_pat is number of input patterns
4901 * pat is array of pointers to input patterns
4902 * num_file is pointer to number of matched file names
4903 * file is pointer to array of pointers to matched file names
4904 */
4905
4906#ifndef SEEK_SET
4907# define SEEK_SET 0
4908#endif
4909#ifndef SEEK_END
4910# define SEEK_END 2
4911#endif
4912
4913/* ARGSUSED */
4914 int
4915mch_expand_wildcards(num_pat, pat, num_file, file, flags)
4916 int num_pat;
4917 char_u **pat;
4918 int *num_file;
4919 char_u ***file;
4920 int flags; /* EW_* flags */
4921{
4922 int i;
4923 size_t len;
4924 char_u *p;
4925 int dir;
4926#ifdef __EMX__
4927# define EXPL_ALLOC_INC 16
4928 char_u **expl_files;
4929 size_t files_alloced, files_free;
4930 char_u *buf;
4931 int has_wildcard;
4932
4933 *num_file = 0; /* default: no files found */
4934 files_alloced = EXPL_ALLOC_INC; /* how much space is allocated */
4935 files_free = EXPL_ALLOC_INC; /* how much space is not used */
4936 *file = (char_u **)alloc(sizeof(char_u **) * files_alloced);
4937 if (*file == NULL)
4938 return FAIL;
4939
4940 for (; num_pat > 0; num_pat--, pat++)
4941 {
4942 expl_files = NULL;
4943 if (vim_strchr(*pat, '$') || vim_strchr(*pat, '~'))
4944 /* expand environment var or home dir */
4945 buf = expand_env_save(*pat);
4946 else
4947 buf = vim_strsave(*pat);
4948 expl_files = NULL;
Bram Moolenaard8b02732005-01-14 21:48:43 +00004949 has_wildcard = mch_has_exp_wildcard(buf); /* (still) wildcards? */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004950 if (has_wildcard) /* yes, so expand them */
4951 expl_files = (char_u **)_fnexplode(buf);
4952
4953 /*
4954 * return value of buf if no wildcards left,
4955 * OR if no match AND EW_NOTFOUND is set.
4956 */
4957 if ((!has_wildcard && ((flags & EW_NOTFOUND) || mch_getperm(buf) >= 0))
4958 || (expl_files == NULL && (flags & EW_NOTFOUND)))
4959 { /* simply save the current contents of *buf */
4960 expl_files = (char_u **)alloc(sizeof(char_u **) * 2);
4961 if (expl_files != NULL)
4962 {
4963 expl_files[0] = vim_strsave(buf);
4964 expl_files[1] = NULL;
4965 }
4966 }
4967 vim_free(buf);
4968
4969 /*
4970 * Count number of names resulting from expansion,
4971 * At the same time add a backslash to the end of names that happen to
4972 * be directories, and replace slashes with backslashes.
4973 */
4974 if (expl_files)
4975 {
4976 for (i = 0; (p = expl_files[i]) != NULL; i++)
4977 {
4978 dir = mch_isdir(p);
4979 /* If we don't want dirs and this is one, skip it */
4980 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
4981 continue;
4982
4983 if (--files_free == 0)
4984 {
4985 /* need more room in table of pointers */
4986 files_alloced += EXPL_ALLOC_INC;
4987 *file = (char_u **)vim_realloc(*file,
4988 sizeof(char_u **) * files_alloced);
4989 if (*file == NULL)
4990 {
4991 EMSG(_(e_outofmem));
4992 *num_file = 0;
4993 return FAIL;
4994 }
4995 files_free = EXPL_ALLOC_INC;
4996 }
4997 slash_adjust(p);
4998 if (dir)
4999 {
5000 /* For a directory we add a '/', unless it's already
5001 * there. */
5002 len = STRLEN(p);
5003 if (((*file)[*num_file] = alloc(len + 2)) != NULL)
5004 {
5005 STRCPY((*file)[*num_file], p);
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005006 if (!after_pathsep((*file)[*num_file] + len))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005007 {
5008 (*file)[*num_file][len] = psepc;
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005009 (*file)[*num_file][len + 1] = NUL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005010 }
5011 }
5012 }
5013 else
5014 {
5015 (*file)[*num_file] = vim_strsave(p);
5016 }
5017
5018 /*
5019 * Error message already given by either alloc or vim_strsave.
5020 * Should return FAIL, but returning OK works also.
5021 */
5022 if ((*file)[*num_file] == NULL)
5023 break;
5024 (*num_file)++;
5025 }
5026 _fnexplodefree((char **)expl_files);
5027 }
5028 }
5029 return OK;
5030
5031#else /* __EMX__ */
5032
5033 int j;
5034 char_u *tempname;
5035 char_u *command;
5036 FILE *fd;
5037 char_u *buffer;
5038#define STYLE_ECHO 0 /* use "echo" to expand */
5039#define STYLE_GLOB 1 /* use "glob" to expand, for csh */
5040#define STYLE_PRINT 2 /* use "print -N" to expand, for zsh */
5041#define STYLE_BT 3 /* `cmd` expansion, execute the pattern directly */
5042 int shell_style = STYLE_ECHO;
5043 int check_spaces;
5044 static int did_find_nul = FALSE;
5045 int ampersent = FALSE;
5046
5047 *num_file = 0; /* default: no files found */
5048 *file = NULL;
5049
5050 /*
5051 * If there are no wildcards, just copy the names to allocated memory.
5052 * Saves a lot of time, because we don't have to start a new shell.
5053 */
5054 if (!have_wildcard(num_pat, pat))
5055 return save_patterns(num_pat, pat, num_file, file);
5056
5057 /*
5058 * Don't allow the use of backticks in secure and restricted mode.
5059 */
5060 if (secure || restricted)
5061 for (i = 0; i < num_pat; ++i)
5062 if (vim_strchr(pat[i], '`') != NULL
5063 && (check_restricted() || check_secure()))
5064 return FAIL;
5065
5066 /*
5067 * get a name for the temp file
5068 */
5069 if ((tempname = vim_tempname('o')) == NULL)
5070 {
5071 EMSG(_(e_notmp));
5072 return FAIL;
5073 }
5074
5075 /*
5076 * Let the shell expand the patterns and write the result into the temp
5077 * file. if expanding `cmd` execute it directly.
5078 * If we use csh, glob will work better than echo.
5079 * If we use zsh, print -N will work better than glob.
5080 */
5081 if (num_pat == 1 && *pat[0] == '`'
5082 && (len = STRLEN(pat[0])) > 2
5083 && *(pat[0] + len - 1) == '`')
5084 shell_style = STYLE_BT;
5085 else if ((len = STRLEN(p_sh)) >= 3)
5086 {
5087 if (STRCMP(p_sh + len - 3, "csh") == 0)
5088 shell_style = STYLE_GLOB;
5089 else if (STRCMP(p_sh + len - 3, "zsh") == 0)
5090 shell_style = STYLE_PRINT;
5091 }
5092
5093 /* "unset nonomatch; print -N >" plus two is 29 */
5094 len = STRLEN(tempname) + 29;
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005095 for (i = 0; i < num_pat; ++i)
5096 {
5097 /* Count the length of the patterns in the same way as they are put in
5098 * "command" below. */
5099#ifdef USE_SYSTEM
Bram Moolenaar071d4272004-06-13 20:20:40 +00005100 len += STRLEN(pat[i]) + 3; /* add space and two quotes */
Bram Moolenaarb23c3382005-01-31 19:09:12 +00005101#else
5102 ++len; /* add space */
5103 for (j = 0; pat[i][j] != NUL; )
5104 if (vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5105 {
5106 len += 2; /* add two quotes */
5107 while (pat[i][j] != NUL
5108 && vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5109 {
5110 ++len;
5111 ++j;
5112 }
5113 }
5114 else
5115 {
5116 ++len;
5117 ++j;
5118 }
5119#endif
5120 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005121 command = alloc(len);
5122 if (command == NULL)
5123 {
5124 /* out of memory */
5125 vim_free(tempname);
5126 return FAIL;
5127 }
5128
5129 /*
5130 * Build the shell command:
5131 * - Set $nonomatch depending on EW_NOTFOUND (hopefully the shell
5132 * recognizes this).
5133 * - Add the shell command to print the expanded names.
5134 * - Add the temp file name.
5135 * - Add the file name patterns.
5136 */
5137 if (shell_style == STYLE_BT)
5138 {
5139 STRCPY(command, pat[0] + 1); /* exclude first backtick */
5140 p = command + STRLEN(command) - 1;
5141 *p = ' '; /* remove last backtick */
5142 while (p > command && vim_iswhite(*p))
5143 --p;
5144 if (*p == '&') /* remove trailing '&' */
5145 {
5146 ampersent = TRUE;
5147 *p = ' ';
5148 }
5149 STRCAT(command, ">");
5150 }
5151 else
5152 {
5153 if (flags & EW_NOTFOUND)
5154 STRCPY(command, "set nonomatch; ");
5155 else
5156 STRCPY(command, "unset nonomatch; ");
5157 if (shell_style == STYLE_GLOB)
5158 STRCAT(command, "glob >");
5159 else if (shell_style == STYLE_PRINT)
5160 STRCAT(command, "print -N >");
5161 else
5162 STRCAT(command, "echo >");
5163 }
5164 STRCAT(command, tempname);
5165 if (shell_style != STYLE_BT)
5166 for (i = 0; i < num_pat; ++i)
5167 {
5168 /* When using system() always add extra quotes, because the shell
5169 * is started twice. Otherwise only put quotes around spaces and
5170 * single quotes. */
5171#ifdef USE_SYSTEM
5172 STRCAT(command, " \"");
5173 STRCAT(command, pat[i]);
5174 STRCAT(command, "\"");
5175#else
5176 p = command + STRLEN(command);
5177 *p++ = ' ';
5178 for (j = 0; pat[i][j] != NUL; )
5179 if (vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5180 {
5181 *p++ = '"';
5182 while (pat[i][j] != NUL
5183 && vim_strchr((char_u *)" '", pat[i][j]) != NULL)
5184 *p++ = pat[i][j++];
5185 *p++ = '"';
5186 }
5187 else
Bram Moolenaar0cf6f542005-01-16 21:59:36 +00005188 {
5189 /* For a backslash also copy the next character, don't
5190 * want to put quotes around it. */
5191 if ((*p++ = pat[i][j++]) == '\\' && pat[i][j] != NUL)
5192 *p++ = pat[i][j++];
5193 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005194 *p = NUL;
5195#endif
5196 }
5197 if (flags & EW_SILENT)
5198 show_shell_mess = FALSE;
5199 if (ampersent)
5200 STRCAT(command, "&"); /* put the '&' back after the
5201 redirection */
5202
5203 /*
5204 * Using zsh -G: If a pattern has no matches, it is just deleted from
5205 * the argument list, otherwise zsh gives an error message and doesn't
5206 * expand any other pattern.
5207 */
5208 if (shell_style == STYLE_PRINT)
5209 extra_shell_arg = (char_u *)"-G"; /* Use zsh NULL_GLOB option */
5210
5211 /*
5212 * If we use -f then shell variables set in .cshrc won't get expanded.
5213 * vi can do it, so we will too, but it is only necessary if there is a "$"
5214 * in one of the patterns, otherwise we can still use the fast option.
5215 */
5216 else if (shell_style == STYLE_GLOB && !have_dollars(num_pat, pat))
5217 extra_shell_arg = (char_u *)"-f"; /* Use csh fast option */
5218
5219 /*
5220 * execute the shell command
5221 */
5222 i = call_shell(command, SHELL_EXPAND | SHELL_SILENT);
5223
5224 /* When running in the background, give it some time to create the temp
5225 * file, but don't wait for it to finish. */
5226 if (ampersent)
5227 mch_delay(10L, TRUE);
5228
5229 extra_shell_arg = NULL; /* cleanup */
5230 show_shell_mess = TRUE;
5231 vim_free(command);
5232
5233 if (i) /* mch_call_shell() failed */
5234 {
5235 mch_remove(tempname);
5236 vim_free(tempname);
5237 /*
5238 * With interactive completion, the error message is not printed.
5239 * However with USE_SYSTEM, I don't know how to turn off error messages
5240 * from the shell, so screen may still get messed up -- webb.
5241 */
5242#ifndef USE_SYSTEM
5243 if (!(flags & EW_SILENT))
5244#endif
5245 {
5246 redraw_later_clear(); /* probably messed up screen */
5247 msg_putchar('\n'); /* clear bottom line quickly */
5248 cmdline_row = Rows - 1; /* continue on last line */
5249#ifdef USE_SYSTEM
5250 if (!(flags & EW_SILENT))
5251#endif
5252 {
5253 MSG(_(e_wildexpand));
5254 msg_start(); /* don't overwrite this message */
5255 }
5256 }
5257 /* If a `cmd` expansion failed, don't list `cmd` as a match, even when
5258 * EW_NOTFOUND is given */
5259 if (shell_style == STYLE_BT)
5260 return FAIL;
5261 goto notfound;
5262 }
5263
5264 /*
5265 * read the names from the file into memory
5266 */
5267 fd = fopen((char *)tempname, READBIN);
5268 if (fd == NULL)
5269 {
5270 /* Something went wrong, perhaps a file name with a special char. */
5271 if (!(flags & EW_SILENT))
5272 {
5273 MSG(_(e_wildexpand));
5274 msg_start(); /* don't overwrite this message */
5275 }
5276 vim_free(tempname);
5277 goto notfound;
5278 }
5279 fseek(fd, 0L, SEEK_END);
5280 len = ftell(fd); /* get size of temp file */
5281 fseek(fd, 0L, SEEK_SET);
5282 buffer = alloc(len + 1);
5283 if (buffer == NULL)
5284 {
5285 /* out of memory */
5286 mch_remove(tempname);
5287 vim_free(tempname);
5288 fclose(fd);
5289 return FAIL;
5290 }
5291 i = fread((char *)buffer, 1, len, fd);
5292 fclose(fd);
5293 mch_remove(tempname);
5294 if (i != len)
5295 {
5296 /* unexpected read error */
5297 EMSG2(_(e_notread), tempname);
5298 vim_free(tempname);
5299 vim_free(buffer);
5300 return FAIL;
5301 }
5302 vim_free(tempname);
5303
5304#if defined(__CYGWIN__) || defined(__CYGWIN32__)
5305 /* Translate <CR><NL> into <NL>. Caution, buffer may contain NUL. */
5306 p = buffer;
5307 for (i = 0; i < len; ++i)
5308 if (!(buffer[i] == CAR && buffer[i + 1] == NL))
5309 *p++ = buffer[i];
5310 len = p - buffer;
5311# endif
5312
5313
5314 /* file names are separated with Space */
5315 if (shell_style == STYLE_ECHO)
5316 {
5317 buffer[len] = '\n'; /* make sure the buffer ends in NL */
5318 p = buffer;
5319 for (i = 0; *p != '\n'; ++i) /* count number of entries */
5320 {
5321 while (*p != ' ' && *p != '\n')
5322 ++p;
5323 p = skipwhite(p); /* skip to next entry */
5324 }
5325 }
5326 /* file names are separated with NL */
5327 else if (shell_style == STYLE_BT)
5328 {
5329 buffer[len] = NUL; /* make sure the buffer ends in NUL */
5330 p = buffer;
5331 for (i = 0; *p != NUL; ++i) /* count number of entries */
5332 {
5333 while (*p != '\n' && *p != NUL)
5334 ++p;
5335 if (*p != NUL)
5336 ++p;
5337 p = skipwhite(p); /* skip leading white space */
5338 }
5339 }
5340 /* file names are separated with NUL */
5341 else
5342 {
5343 /*
5344 * Some versions of zsh use spaces instead of NULs to separate
5345 * results. Only do this when there is no NUL before the end of the
5346 * buffer, otherwise we would never be able to use file names with
5347 * embedded spaces when zsh does use NULs.
5348 * When we found a NUL once, we know zsh is OK, set did_find_nul and
5349 * don't check for spaces again.
5350 */
5351 check_spaces = FALSE;
5352 if (shell_style == STYLE_PRINT && !did_find_nul)
5353 {
5354 /* If there is a NUL, set did_find_nul, else set check_spaces */
5355 if (len && (int)STRLEN(buffer) < len - 1)
5356 did_find_nul = TRUE;
5357 else
5358 check_spaces = TRUE;
5359 }
5360
5361 /*
5362 * Make sure the buffer ends with a NUL. For STYLE_PRINT there
5363 * already is one, for STYLE_GLOB it needs to be added.
5364 */
5365 if (len && buffer[len - 1] == NUL)
5366 --len;
5367 else
5368 buffer[len] = NUL;
5369 i = 0;
5370 for (p = buffer; p < buffer + len; ++p)
5371 if (*p == NUL || (*p == ' ' && check_spaces)) /* count entry */
5372 {
5373 ++i;
5374 *p = NUL;
5375 }
5376 if (len)
5377 ++i; /* count last entry */
5378 }
5379 if (i == 0)
5380 {
5381 /*
5382 * Can happen when using /bin/sh and typing ":e $NO_SUCH_VAR^I".
5383 * /bin/sh will happily expand it to nothing rather than returning an
5384 * error; and hey, it's good to check anyway -- webb.
5385 */
5386 vim_free(buffer);
5387 goto notfound;
5388 }
5389 *num_file = i;
5390 *file = (char_u **)alloc(sizeof(char_u *) * i);
5391 if (*file == NULL)
5392 {
5393 /* out of memory */
5394 vim_free(buffer);
5395 return FAIL;
5396 }
5397
5398 /*
5399 * Isolate the individual file names.
5400 */
5401 p = buffer;
5402 for (i = 0; i < *num_file; ++i)
5403 {
5404 (*file)[i] = p;
5405 /* Space or NL separates */
5406 if (shell_style == STYLE_ECHO || shell_style == STYLE_BT)
5407 {
5408 while (!(shell_style == STYLE_ECHO && *p == ' ') && *p != '\n')
5409 ++p;
5410 if (p == buffer + len) /* last entry */
5411 *p = NUL;
5412 else
5413 {
5414 *p++ = NUL;
5415 p = skipwhite(p); /* skip to next entry */
5416 }
5417 }
5418 else /* NUL separates */
5419 {
5420 while (*p && p < buffer + len) /* skip entry */
5421 ++p;
5422 ++p; /* skip NUL */
5423 }
5424 }
5425
5426 /*
5427 * Move the file names to allocated memory.
5428 */
5429 for (j = 0, i = 0; i < *num_file; ++i)
5430 {
5431 /* Require the files to exist. Helps when using /bin/sh */
5432 if (!(flags & EW_NOTFOUND) && mch_getperm((*file)[i]) < 0)
5433 continue;
5434
5435 /* check if this entry should be included */
5436 dir = (mch_isdir((*file)[i]));
5437 if ((dir && !(flags & EW_DIR)) || (!dir && !(flags & EW_FILE)))
5438 continue;
5439
5440 p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
5441 if (p)
5442 {
5443 STRCPY(p, (*file)[i]);
5444 if (dir)
5445 STRCAT(p, "/"); /* add '/' to a directory name */
5446 (*file)[j++] = p;
5447 }
5448 }
5449 vim_free(buffer);
5450 *num_file = j;
5451
5452 if (*num_file == 0) /* rejected all entries */
5453 {
5454 vim_free(*file);
5455 *file = NULL;
5456 goto notfound;
5457 }
5458
5459 return OK;
5460
5461notfound:
5462 if (flags & EW_NOTFOUND)
5463 return save_patterns(num_pat, pat, num_file, file);
5464 return FAIL;
5465
5466#endif /* __EMX__ */
5467}
5468
5469#endif /* VMS */
5470
5471#ifndef __EMX__
5472 static int
5473save_patterns(num_pat, pat, num_file, file)
5474 int num_pat;
5475 char_u **pat;
5476 int *num_file;
5477 char_u ***file;
5478{
5479 int i;
Bram Moolenaard8b02732005-01-14 21:48:43 +00005480 char_u *s;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005481
5482 *file = (char_u **)alloc(num_pat * sizeof(char_u *));
5483 if (*file == NULL)
5484 return FAIL;
5485 for (i = 0; i < num_pat; i++)
Bram Moolenaard8b02732005-01-14 21:48:43 +00005486 {
5487 s = vim_strsave(pat[i]);
5488 if (s != NULL)
5489 /* Be compatible with expand_filename(): halve the number of
5490 * backslashes. */
5491 backslash_halve(s);
5492 (*file)[i] = s;
5493 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005494 *num_file = num_pat;
5495 return OK;
5496}
5497#endif
5498
5499
5500/*
5501 * Return TRUE if the string "p" contains a wildcard that mch_expandpath() can
5502 * expand.
5503 */
5504 int
5505mch_has_exp_wildcard(p)
5506 char_u *p;
5507{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005508 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005509 {
5510#ifndef OS2
5511 if (*p == '\\' && p[1] != NUL)
5512 ++p;
5513 else
5514#endif
5515 if (vim_strchr((char_u *)
5516#ifdef VMS
5517 "*?%"
5518#else
5519# ifdef OS2
5520 "*?"
5521# else
5522 "*?[{'"
5523# endif
5524#endif
5525 , *p) != NULL)
5526 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005527 }
5528 return FALSE;
5529}
5530
5531/*
5532 * Return TRUE if the string "p" contains a wildcard.
5533 * Don't recognize '~' at the end as a wildcard.
5534 */
5535 int
5536mch_has_wildcard(p)
5537 char_u *p;
5538{
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00005539 for ( ; *p; mb_ptr_adv(p))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005540 {
5541#ifndef OS2
5542 if (*p == '\\' && p[1] != NUL)
5543 ++p;
5544 else
5545#endif
5546 if (vim_strchr((char_u *)
5547#ifdef VMS
5548 "*?%$"
5549#else
5550# ifdef OS2
5551# ifdef VIM_BACKTICK
5552 "*?$`"
5553# else
5554 "*?$"
5555# endif
5556# else
5557 "*?[{`'$"
5558# endif
5559#endif
5560 , *p) != NULL
5561 || (*p == '~' && p[1] != NUL))
5562 return TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005563 }
5564 return FALSE;
5565}
5566
5567#ifndef __EMX__
5568 static int
5569have_wildcard(num, file)
5570 int num;
5571 char_u **file;
5572{
5573 int i;
5574
5575 for (i = 0; i < num; i++)
5576 if (mch_has_wildcard(file[i]))
5577 return 1;
5578 return 0;
5579}
5580
5581 static int
5582have_dollars(num, file)
5583 int num;
5584 char_u **file;
5585{
5586 int i;
5587
5588 for (i = 0; i < num; i++)
5589 if (vim_strchr(file[i], '$') != NULL)
5590 return TRUE;
5591 return FALSE;
5592}
5593#endif /* ifndef __EMX__ */
5594
5595#ifndef HAVE_RENAME
5596/*
5597 * Scaled-down version of rename(), which is missing in Xenix.
5598 * This version can only move regular files and will fail if the
5599 * destination exists.
5600 */
5601 int
5602mch_rename(src, dest)
5603 const char *src, *dest;
5604{
5605 struct stat st;
5606
5607 if (stat(dest, &st) >= 0) /* fail if destination exists */
5608 return -1;
5609 if (link(src, dest) != 0) /* link file to new name */
5610 return -1;
5611 if (mch_remove(src) == 0) /* delete link to old name */
5612 return 0;
5613 return -1;
5614}
5615#endif /* !HAVE_RENAME */
5616
5617#ifdef FEAT_MOUSE_GPM
5618/*
5619 * Initializes connection with gpm (if it isn't already opened)
5620 * Return 1 if succeeded (or connection already opened), 0 if failed
5621 */
5622 static int
5623gpm_open()
5624{
5625 static Gpm_Connect gpm_connect; /* Must it be kept till closing ? */
5626
5627 if (!gpm_flag)
5628 {
5629 gpm_connect.eventMask = (GPM_UP | GPM_DRAG | GPM_DOWN);
5630 gpm_connect.defaultMask = ~GPM_HARD;
5631 /* Default handling for mouse move*/
5632 gpm_connect.minMod = 0; /* Handle any modifier keys */
5633 gpm_connect.maxMod = 0xffff;
5634 if (Gpm_Open(&gpm_connect, 0) > 0)
5635 {
5636 /* gpm library tries to handling TSTP causes
5637 * problems. Anyways, we close connection to Gpm whenever
5638 * we are going to suspend or starting an external process
5639 * so we should'nt have problem with this
5640 */
5641 signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL);
5642 return 1; /* succeed */
5643 }
5644 if (gpm_fd == -2)
5645 Gpm_Close(); /* We don't want to talk to xterm via gpm */
5646 return 0;
5647 }
5648 return 1; /* already open */
5649}
5650
5651/*
5652 * Closes connection to gpm
5653 * returns non-zero if connection succesfully closed
5654 */
5655 static void
5656gpm_close()
5657{
5658 if (gpm_flag && gpm_fd >= 0) /* if Open */
5659 Gpm_Close();
5660}
5661
5662/* Reads gpm event and adds special keys to input buf. Returns length of
5663 * generated key sequence.
5664 * This function is made after gui_send_mouse_event
5665 */
5666 static int
5667mch_gpm_process()
5668{
5669 int button;
5670 static Gpm_Event gpm_event;
5671 char_u string[6];
5672 int_u vim_modifiers;
5673 int row,col;
5674 unsigned char buttons_mask;
5675 unsigned char gpm_modifiers;
5676 static unsigned char old_buttons = 0;
5677
5678 Gpm_GetEvent(&gpm_event);
5679
5680#ifdef FEAT_GUI
5681 /* Don't put events in the input queue now. */
5682 if (hold_gui_events)
5683 return 0;
5684#endif
5685
5686 row = gpm_event.y - 1;
5687 col = gpm_event.x - 1;
5688
5689 string[0] = ESC; /* Our termcode */
5690 string[1] = 'M';
5691 string[2] = 'G';
5692 switch (GPM_BARE_EVENTS(gpm_event.type))
5693 {
5694 case GPM_DRAG:
5695 string[3] = MOUSE_DRAG;
5696 break;
5697 case GPM_DOWN:
5698 buttons_mask = gpm_event.buttons & ~old_buttons;
5699 old_buttons = gpm_event.buttons;
5700 switch (buttons_mask)
5701 {
5702 case GPM_B_LEFT:
5703 button = MOUSE_LEFT;
5704 break;
5705 case GPM_B_MIDDLE:
5706 button = MOUSE_MIDDLE;
5707 break;
5708 case GPM_B_RIGHT:
5709 button = MOUSE_RIGHT;
5710 break;
5711 default:
5712 return 0;
5713 /*Don't know what to do. Can more than one button be
5714 * reported in one event? */
5715 }
5716 string[3] = (char_u)(button | 0x20);
5717 SET_NUM_MOUSE_CLICKS(string[3], gpm_event.clicks + 1);
5718 break;
5719 case GPM_UP:
5720 string[3] = MOUSE_RELEASE;
5721 old_buttons &= ~gpm_event.buttons;
5722 break;
5723 default:
5724 return 0;
5725 }
5726 /*This code is based on gui_x11_mouse_cb in gui_x11.c */
5727 gpm_modifiers = gpm_event.modifiers;
5728 vim_modifiers = 0x0;
5729 /* I ignore capslock stats. Aren't we all just hate capslock mixing with
5730 * Vim commands ? Besides, gpm_event.modifiers is unsigned char, and
5731 * K_CAPSSHIFT is defined 8, so it probably isn't even reported
5732 */
5733 if (gpm_modifiers & ((1 << KG_SHIFT) | (1 << KG_SHIFTR) | (1 << KG_SHIFTL)))
5734 vim_modifiers |= MOUSE_SHIFT;
5735
5736 if (gpm_modifiers & ((1 << KG_CTRL) | (1 << KG_CTRLR) | (1 << KG_CTRLL)))
5737 vim_modifiers |= MOUSE_CTRL;
5738 if (gpm_modifiers & ((1 << KG_ALT) | (1 << KG_ALTGR)))
5739 vim_modifiers |= MOUSE_ALT;
5740 string[3] |= vim_modifiers;
5741 string[4] = (char_u)(col + ' ' + 1);
5742 string[5] = (char_u)(row + ' ' + 1);
5743 add_to_input_buf(string, 6);
5744 return 6;
5745}
5746#endif /* FEAT_MOUSE_GPM */
5747
5748#if defined(FEAT_LIBCALL) || defined(PROTO)
5749typedef char_u * (*STRPROCSTR)__ARGS((char_u *));
5750typedef char_u * (*INTPROCSTR)__ARGS((int));
5751typedef int (*STRPROCINT)__ARGS((char_u *));
5752typedef int (*INTPROCINT)__ARGS((int));
5753
5754/*
5755 * Call a DLL routine which takes either a string or int param
5756 * and returns an allocated string.
5757 */
5758 int
5759mch_libcall(libname, funcname, argstring, argint, string_result, number_result)
5760 char_u *libname;
5761 char_u *funcname;
5762 char_u *argstring; /* NULL when using a argint */
5763 int argint;
5764 char_u **string_result;/* NULL when using number_result */
5765 int *number_result;
5766{
5767# if defined(USE_DLOPEN)
5768 void *hinstLib;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005769 char *dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005770# else
5771 shl_t hinstLib;
5772# endif
5773 STRPROCSTR ProcAdd;
5774 INTPROCSTR ProcAddI;
5775 char_u *retval_str = NULL;
5776 int retval_int = 0;
5777 int success = FALSE;
5778
5779 /* Get a handle to the DLL module. */
5780# if defined(USE_DLOPEN)
5781 hinstLib = dlopen((char *)libname, RTLD_LAZY
5782# ifdef RTLD_LOCAL
5783 | RTLD_LOCAL
5784# endif
5785 );
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005786 if (hinstLib == NULL)
5787 {
5788 /* "dlerr" must be used before dlclose() */
5789 dlerr = (char *)dlerror();
5790 if (dlerr != NULL)
5791 EMSG2(_("dlerror = \"%s\""), dlerr);
5792 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005793# else
5794 hinstLib = shl_load((const char*)libname, BIND_IMMEDIATE|BIND_VERBOSE, 0L);
5795# endif
5796
5797 /* If the handle is valid, try to get the function address. */
5798 if (hinstLib != NULL)
5799 {
5800# ifdef HAVE_SETJMP_H
5801 /*
5802 * Catch a crash when calling the library function. For example when
5803 * using a number where a string pointer is expected.
5804 */
5805 mch_startjmp();
5806 if (SETJMP(lc_jump_env) != 0)
5807 {
5808 success = FALSE;
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005809 dlerr = NULL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005810 mch_didjmp();
5811 }
5812 else
5813# endif
5814 {
5815 retval_str = NULL;
5816 retval_int = 0;
5817
5818 if (argstring != NULL)
5819 {
5820# if defined(USE_DLOPEN)
5821 ProcAdd = (STRPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005822 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005823# else
5824 if (shl_findsym(&hinstLib, (const char *)funcname,
5825 TYPE_PROCEDURE, (void *)&ProcAdd) < 0)
5826 ProcAdd = NULL;
5827# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005828 if ((success = (ProcAdd != NULL
5829# if defined(USE_DLOPEN)
5830 && dlerr == NULL
5831# endif
5832 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005833 {
5834 if (string_result == NULL)
5835 retval_int = ((STRPROCINT)ProcAdd)(argstring);
5836 else
5837 retval_str = (ProcAdd)(argstring);
5838 }
5839 }
5840 else
5841 {
5842# if defined(USE_DLOPEN)
5843 ProcAddI = (INTPROCSTR)dlsym(hinstLib, (const char *)funcname);
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005844 dlerr = (char *)dlerror();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005845# else
5846 if (shl_findsym(&hinstLib, (const char *)funcname,
5847 TYPE_PROCEDURE, (void *)&ProcAddI) < 0)
5848 ProcAddI = NULL;
5849# endif
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005850 if ((success = (ProcAddI != NULL
5851# if defined(USE_DLOPEN)
5852 && dlerr == NULL
5853# endif
5854 )))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005855 {
5856 if (string_result == NULL)
5857 retval_int = ((INTPROCINT)ProcAddI)(argint);
5858 else
5859 retval_str = (ProcAddI)(argint);
5860 }
5861 }
5862
5863 /* Save the string before we free the library. */
5864 /* Assume that a "1" or "-1" result is an illegal pointer. */
5865 if (string_result == NULL)
5866 *number_result = retval_int;
5867 else if (retval_str != NULL
5868 && retval_str != (char_u *)1
5869 && retval_str != (char_u *)-1)
5870 *string_result = vim_strsave(retval_str);
5871 }
5872
5873# ifdef HAVE_SETJMP_H
5874 mch_endjmp();
5875# ifdef SIGHASARG
5876 if (lc_signal != 0)
5877 {
5878 int i;
5879
5880 /* try to find the name of this signal */
5881 for (i = 0; signal_info[i].sig != -1; i++)
5882 if (lc_signal == signal_info[i].sig)
5883 break;
5884 EMSG2("E368: got SIG%s in libcall()", signal_info[i].name);
5885 }
5886# endif
5887# endif
5888
Bram Moolenaar071d4272004-06-13 20:20:40 +00005889# if defined(USE_DLOPEN)
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00005890 /* "dlerr" must be used before dlclose() */
5891 if (dlerr != NULL)
5892 EMSG2(_("dlerror = \"%s\""), dlerr);
5893
5894 /* Free the DLL module. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005895 (void)dlclose(hinstLib);
5896# else
5897 (void)shl_unload(hinstLib);
5898# endif
5899 }
5900
5901 if (!success)
5902 {
5903 EMSG2(_(e_libcall), funcname);
5904 return FAIL;
5905 }
5906
5907 return OK;
5908}
5909#endif
5910
5911#if (defined(FEAT_X11) && defined(FEAT_XCLIPBOARD)) || defined(PROTO)
5912static int xterm_trace = -1; /* default: disabled */
5913static int xterm_button;
5914
5915/*
5916 * Setup a dummy window for X selections in a terminal.
5917 */
5918 void
5919setup_term_clip()
5920{
5921 int z = 0;
5922 char *strp = "";
5923 Widget AppShell;
5924
5925 if (!x_connect_to_server())
5926 return;
5927
5928 open_app_context();
5929 if (app_context != NULL && xterm_Shell == (Widget)0)
5930 {
5931 int (*oldhandler)();
5932#if defined(HAVE_SETJMP_H)
5933 int (*oldIOhandler)();
5934#endif
5935# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5936 struct timeval start_tv;
5937
5938 if (p_verbose > 0)
5939 gettimeofday(&start_tv, NULL);
5940# endif
5941
5942 /* Ignore X errors while opening the display */
5943 oldhandler = XSetErrorHandler(x_error_check);
5944
5945#if defined(HAVE_SETJMP_H)
5946 /* Ignore X IO errors while opening the display */
5947 oldIOhandler = XSetIOErrorHandler(x_IOerror_check);
5948 mch_startjmp();
5949 if (SETJMP(lc_jump_env) != 0)
5950 {
5951 mch_didjmp();
5952 xterm_dpy = NULL;
5953 }
5954 else
5955#endif
5956 {
5957 xterm_dpy = XtOpenDisplay(app_context, xterm_display,
5958 "vim_xterm", "Vim_xterm", NULL, 0, &z, &strp);
5959#if defined(HAVE_SETJMP_H)
5960 mch_endjmp();
5961#endif
5962 }
5963
5964#if defined(HAVE_SETJMP_H)
5965 /* Now handle X IO errors normally. */
5966 (void)XSetIOErrorHandler(oldIOhandler);
5967#endif
5968 /* Now handle X errors normally. */
5969 (void)XSetErrorHandler(oldhandler);
5970
5971 if (xterm_dpy == NULL)
5972 {
5973 if (p_verbose > 0)
5974 MSG(_("Opening the X display failed"));
5975 return;
5976 }
5977
5978 /* Catch terminating error of the X server connection. */
5979 (void)XSetIOErrorHandler(x_IOerror_handler);
5980
5981# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
5982 if (p_verbose > 0)
5983 xopen_message(&start_tv);
5984# endif
5985
5986 /* Create a Shell to make converters work. */
5987 AppShell = XtVaAppCreateShell("vim_xterm", "Vim_xterm",
5988 applicationShellWidgetClass, xterm_dpy,
5989 NULL);
5990 if (AppShell == (Widget)0)
5991 return;
5992 xterm_Shell = XtVaCreatePopupShell("VIM",
5993 topLevelShellWidgetClass, AppShell,
5994 XtNmappedWhenManaged, 0,
5995 XtNwidth, 1,
5996 XtNheight, 1,
5997 NULL);
5998 if (xterm_Shell == (Widget)0)
5999 return;
6000
6001 x11_setup_atoms(xterm_dpy);
6002 if (x11_display == NULL)
6003 x11_display = xterm_dpy;
6004
6005 XtRealizeWidget(xterm_Shell);
6006 XSync(xterm_dpy, False);
6007 xterm_update();
6008 }
6009 if (xterm_Shell != (Widget)0)
6010 {
6011 clip_init(TRUE);
6012 if (x11_window == 0 && (strp = getenv("WINDOWID")) != NULL)
6013 x11_window = (Window)atol(strp);
6014 /* Check if $WINDOWID is valid. */
6015 if (test_x11_window(xterm_dpy) == FAIL)
6016 x11_window = 0;
6017 if (x11_window != 0)
6018 xterm_trace = 0;
6019 }
6020}
6021
6022 void
6023start_xterm_trace(button)
6024 int button;
6025{
6026 if (x11_window == 0 || xterm_trace < 0 || xterm_Shell == (Widget)0)
6027 return;
6028 xterm_trace = 1;
6029 xterm_button = button;
6030 do_xterm_trace();
6031}
6032
6033
6034 void
6035stop_xterm_trace()
6036{
6037 if (xterm_trace < 0)
6038 return;
6039 xterm_trace = 0;
6040}
6041
6042/*
6043 * Query the xterm pointer and generate mouse termcodes if necessary
6044 * return TRUE if dragging is active, else FALSE
6045 */
6046 static int
6047do_xterm_trace()
6048{
6049 Window root, child;
6050 int root_x, root_y;
6051 int win_x, win_y;
6052 int row, col;
6053 int_u mask_return;
6054 char_u buf[50];
6055 char_u *strp;
6056 long got_hints;
6057 static char_u *mouse_code;
6058 static char_u mouse_name[2] = {KS_MOUSE, KE_FILLER};
6059 static int prev_row = 0, prev_col = 0;
6060 static XSizeHints xterm_hints;
6061
6062 if (xterm_trace <= 0)
6063 return FALSE;
6064
6065 if (xterm_trace == 1)
6066 {
6067 /* Get the hints just before tracking starts. The font size might
6068 * have changed recently */
6069 XGetWMNormalHints(xterm_dpy, x11_window, &xterm_hints, &got_hints);
6070 if (!(got_hints & PResizeInc)
6071 || xterm_hints.width_inc <= 1
6072 || xterm_hints.height_inc <= 1)
6073 {
6074 xterm_trace = -1; /* Not enough data -- disable tracing */
6075 return FALSE;
6076 }
6077
6078 /* Rely on the same mouse code for the duration of this */
6079 mouse_code = find_termcode(mouse_name);
6080 prev_row = mouse_row;
6081 prev_row = mouse_col;
6082 xterm_trace = 2;
6083
6084 /* Find the offset of the chars, there might be a scrollbar on the
6085 * left of the window and/or a menu on the top (eterm etc.) */
6086 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6087 &win_x, &win_y, &mask_return);
6088 xterm_hints.y = win_y - (xterm_hints.height_inc * mouse_row)
6089 - (xterm_hints.height_inc / 2);
6090 if (xterm_hints.y <= xterm_hints.height_inc / 2)
6091 xterm_hints.y = 2;
6092 xterm_hints.x = win_x - (xterm_hints.width_inc * mouse_col)
6093 - (xterm_hints.width_inc / 2);
6094 if (xterm_hints.x <= xterm_hints.width_inc / 2)
6095 xterm_hints.x = 2;
6096 return TRUE;
6097 }
6098 if (mouse_code == NULL)
6099 {
6100 xterm_trace = 0;
6101 return FALSE;
6102 }
6103
6104 XQueryPointer(xterm_dpy, x11_window, &root, &child, &root_x, &root_y,
6105 &win_x, &win_y, &mask_return);
6106
6107 row = check_row((win_y - xterm_hints.y) / xterm_hints.height_inc);
6108 col = check_col((win_x - xterm_hints.x) / xterm_hints.width_inc);
6109 if (row == prev_row && col == prev_col)
6110 return TRUE;
6111
6112 STRCPY(buf, mouse_code);
6113 strp = buf + STRLEN(buf);
6114 *strp++ = (xterm_button | MOUSE_DRAG) & ~0x20;
6115 *strp++ = (char_u)(col + ' ' + 1);
6116 *strp++ = (char_u)(row + ' ' + 1);
6117 *strp = 0;
6118 add_to_input_buf(buf, STRLEN(buf));
6119
6120 prev_row = row;
6121 prev_col = col;
6122 return TRUE;
6123}
6124
6125# if defined(FEAT_GUI) || defined(PROTO)
6126/*
6127 * Destroy the display, window and app_context. Required for GTK.
6128 */
6129 void
6130clear_xterm_clip()
6131{
6132 if (xterm_Shell != (Widget)0)
6133 {
6134 XtDestroyWidget(xterm_Shell);
6135 xterm_Shell = (Widget)0;
6136 }
6137 if (xterm_dpy != NULL)
6138 {
6139#if 0
6140 /* Lesstif and Solaris crash here, lose some memory */
6141 XtCloseDisplay(xterm_dpy);
6142#endif
6143 if (x11_display == xterm_dpy)
6144 x11_display = NULL;
6145 xterm_dpy = NULL;
6146 }
6147#if 0
6148 if (app_context != (XtAppContext)NULL)
6149 {
6150 /* Lesstif and Solaris crash here, lose some memory */
6151 XtDestroyApplicationContext(app_context);
6152 app_context = (XtAppContext)NULL;
6153 }
6154#endif
6155}
6156# endif
6157
6158/*
6159 * Catch up with any queued X events. This may put keyboard input into the
6160 * input buffer, call resize call-backs, trigger timers etc. If there is
6161 * nothing in the X event queue (& no timers pending), then we return
6162 * immediately.
6163 */
6164 static void
6165xterm_update()
6166{
6167 XEvent event;
6168
6169 while (XtAppPending(app_context) && !vim_is_input_buf_full())
6170 {
6171 XtAppNextEvent(app_context, &event);
6172#ifdef FEAT_CLIENTSERVER
6173 {
6174 XPropertyEvent *e = (XPropertyEvent *)&event;
6175
6176 if (e->type == PropertyNotify && e->window == commWindow
6177 && e->atom == commProperty && e->state == PropertyNewValue)
6178 serverEventProc(xterm_dpy, &event);
6179 }
6180#endif
6181 XtDispatchEvent(&event);
6182 }
6183}
6184
6185 int
6186clip_xterm_own_selection(cbd)
6187 VimClipboard *cbd;
6188{
6189 if (xterm_Shell != (Widget)0)
6190 return clip_x11_own_selection(xterm_Shell, cbd);
6191 return FAIL;
6192}
6193
6194 void
6195clip_xterm_lose_selection(cbd)
6196 VimClipboard *cbd;
6197{
6198 if (xterm_Shell != (Widget)0)
6199 clip_x11_lose_selection(xterm_Shell, cbd);
6200}
6201
6202 void
6203clip_xterm_request_selection(cbd)
6204 VimClipboard *cbd;
6205{
6206 if (xterm_Shell != (Widget)0)
6207 clip_x11_request_selection(xterm_Shell, xterm_dpy, cbd);
6208}
6209
6210 void
6211clip_xterm_set_selection(cbd)
6212 VimClipboard *cbd;
6213{
6214 clip_x11_set_selection(cbd);
6215}
6216#endif
6217
6218
6219#if defined(USE_XSMP) || defined(PROTO)
6220/*
6221 * Code for X Session Management Protocol.
6222 */
6223static void xsmp_handle_save_yourself __ARGS((SmcConn smc_conn, SmPointer client_data, int save_type, Bool shutdown, int interact_style, Bool fast));
6224static void xsmp_die __ARGS((SmcConn smc_conn, SmPointer client_data));
6225static void xsmp_save_complete __ARGS((SmcConn smc_conn, SmPointer client_data));
6226static void xsmp_shutdown_cancelled __ARGS((SmcConn smc_conn, SmPointer client_data));
6227static void xsmp_ice_connection __ARGS((IceConn iceConn, IcePointer clientData, Bool opening, IcePointer *watchData));
6228
6229
6230# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6231static void xsmp_handle_interaction __ARGS((SmcConn smc_conn, SmPointer client_data));
6232
6233/*
6234 * This is our chance to ask the user if they want to save,
6235 * or abort the logout
6236 */
6237/*ARGSUSED*/
6238 static void
6239xsmp_handle_interaction(smc_conn, client_data)
6240 SmcConn smc_conn;
6241 SmPointer client_data;
6242{
6243 cmdmod_T save_cmdmod;
6244 int cancel_shutdown = False;
6245
6246 save_cmdmod = cmdmod;
6247 cmdmod.confirm = TRUE;
6248 if (check_changed_any(FALSE))
6249 /* Mustn't logout */
6250 cancel_shutdown = True;
6251 cmdmod = save_cmdmod;
6252 setcursor(); /* position cursor */
6253 out_flush();
6254
6255 /* Done interaction */
6256 SmcInteractDone(smc_conn, cancel_shutdown);
6257
6258 /* Finish off
6259 * Only end save-yourself here if we're not cancelling shutdown;
6260 * we'll get a cancelled callback later in which we'll end it.
6261 * Hopefully get around glitchy SMs (like GNOME-1)
6262 */
6263 if (!cancel_shutdown)
6264 {
6265 xsmp.save_yourself = False;
6266 SmcSaveYourselfDone(smc_conn, True);
6267 }
6268}
6269# endif
6270
6271/*
6272 * Callback that starts save-yourself.
6273 */
6274/*ARGSUSED*/
6275 static void
6276xsmp_handle_save_yourself(smc_conn, client_data, save_type,
6277 shutdown, interact_style, fast)
6278 SmcConn smc_conn;
6279 SmPointer client_data;
6280 int save_type;
6281 Bool shutdown;
6282 int interact_style;
6283 Bool fast;
6284{
6285 /* Handle already being in saveyourself */
6286 if (xsmp.save_yourself)
6287 SmcSaveYourselfDone(smc_conn, True);
6288 xsmp.save_yourself = True;
6289 xsmp.shutdown = shutdown;
6290
6291 /* First up, preserve all files */
6292 out_flush();
6293 ml_sync_all(FALSE, FALSE); /* preserve all swap files */
6294
6295 if (p_verbose > 0)
6296 MSG(_("XSMP handling save-yourself request"));
6297
6298# if defined(FEAT_GUI) && defined(USE_XSMP_INTERACT)
6299 /* Now see if we can ask about unsaved files */
6300 if (shutdown && !fast && gui.in_use)
6301 /* Need to interact with user, but need SM's permission */
6302 SmcInteractRequest(smc_conn, SmDialogError,
6303 xsmp_handle_interaction, client_data);
6304 else
6305# endif
6306 {
6307 /* Can stop the cycle here */
6308 SmcSaveYourselfDone(smc_conn, True);
6309 xsmp.save_yourself = False;
6310 }
6311}
6312
6313
6314/*
6315 * Callback to warn us of imminent death.
6316 */
6317/*ARGSUSED*/
6318 static void
6319xsmp_die(smc_conn, client_data)
6320 SmcConn smc_conn;
6321 SmPointer client_data;
6322{
6323 xsmp_close();
6324
6325 /* quit quickly leaving swapfiles for modified buffers behind */
6326 getout_preserve_modified(0);
6327}
6328
6329
6330/*
6331 * Callback to tell us that save-yourself has completed.
6332 */
6333/*ARGSUSED*/
6334 static void
6335xsmp_save_complete(smc_conn, client_data)
6336 SmcConn smc_conn;
6337 SmPointer client_data;
6338{
6339 xsmp.save_yourself = False;
6340}
6341
6342
6343/*
6344 * Callback to tell us that an instigated shutdown was cancelled
6345 * (maybe even by us)
6346 */
6347/*ARGSUSED*/
6348 static void
6349xsmp_shutdown_cancelled(smc_conn, client_data)
6350 SmcConn smc_conn;
6351 SmPointer client_data;
6352{
6353 if (xsmp.save_yourself)
6354 SmcSaveYourselfDone(smc_conn, True);
6355 xsmp.save_yourself = False;
6356 xsmp.shutdown = False;
6357}
6358
6359
6360/*
6361 * Callback to tell us that a new ICE connection has been established.
6362 */
6363/*ARGSUSED*/
6364 static void
6365xsmp_ice_connection(iceConn, clientData, opening, watchData)
6366 IceConn iceConn;
6367 IcePointer clientData;
6368 Bool opening;
6369 IcePointer *watchData;
6370{
6371 /* Intercept creation of ICE connection fd */
6372 if (opening)
6373 {
6374 xsmp_icefd = IceConnectionNumber(iceConn);
6375 IceRemoveConnectionWatch(xsmp_ice_connection, NULL);
6376 }
6377}
6378
6379
6380/* Handle any ICE processing that's required; return FAIL if SM lost */
6381 int
6382xsmp_handle_requests()
6383{
6384 Bool rep;
6385
6386 if (IceProcessMessages(xsmp.iceconn, NULL, &rep)
6387 == IceProcessMessagesIOError)
6388 {
6389 /* Lost ICE */
6390 if (p_verbose > 0)
6391 MSG(_("XSMP lost ICE connection"));
6392 xsmp_close();
6393 return FAIL;
6394 }
6395 else
6396 return OK;
6397}
6398
6399static int dummy;
6400
6401/* Set up X Session Management Protocol */
6402 void
6403xsmp_init(void)
6404{
6405 char errorstring[80];
6406 char *clientid;
6407 SmcCallbacks smcallbacks;
6408#if 0
6409 SmPropValue smname;
6410 SmProp smnameprop;
6411 SmProp *smprops[1];
6412#endif
6413
6414 if (p_verbose > 0)
6415 MSG(_("XSMP opening connection"));
6416
6417 xsmp.save_yourself = xsmp.shutdown = False;
6418
6419 /* Set up SM callbacks - must have all, even if they're not used */
6420 smcallbacks.save_yourself.callback = xsmp_handle_save_yourself;
6421 smcallbacks.save_yourself.client_data = NULL;
6422 smcallbacks.die.callback = xsmp_die;
6423 smcallbacks.die.client_data = NULL;
6424 smcallbacks.save_complete.callback = xsmp_save_complete;
6425 smcallbacks.save_complete.client_data = NULL;
6426 smcallbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
6427 smcallbacks.shutdown_cancelled.client_data = NULL;
6428
6429 /* Set up a watch on ICE connection creations. The "dummy" argument is
6430 * apparently required for FreeBSD (we get a BUS error when using NULL). */
6431 if (IceAddConnectionWatch(xsmp_ice_connection, &dummy) == 0)
6432 {
6433 if (p_verbose > 0)
6434 MSG(_("XSMP ICE connection watch failed"));
6435 return;
6436 }
6437
6438 /* Create an SM connection */
6439 xsmp.smcconn = SmcOpenConnection(
6440 NULL,
6441 NULL,
6442 SmProtoMajor,
6443 SmProtoMinor,
6444 SmcSaveYourselfProcMask | SmcDieProcMask
6445 | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
6446 &smcallbacks,
6447 NULL,
6448 &clientid,
6449 sizeof(errorstring),
6450 errorstring);
6451 if (xsmp.smcconn == NULL)
6452 {
6453 char errorreport[132];
6454 sprintf(errorreport, _("XSMP SmcOpenConnection failed: %s"),
6455 errorstring);
6456 if (p_verbose > 0)
6457 MSG(errorreport);
6458 return;
6459 }
6460 xsmp.iceconn = SmcGetIceConnection(xsmp.smcconn);
6461
6462#if 0
6463 /* ID ourselves */
6464 smname.value = "vim";
6465 smname.length = 3;
6466 smnameprop.name = "SmProgram";
6467 smnameprop.type = "SmARRAY8";
6468 smnameprop.num_vals = 1;
6469 smnameprop.vals = &smname;
6470
6471 smprops[0] = &smnameprop;
6472 SmcSetProperties(xsmp.smcconn, 1, smprops);
6473#endif
6474}
6475
6476
6477/* Shut down XSMP comms. */
6478 void
6479xsmp_close()
6480{
6481 if (xsmp_icefd != -1)
6482 {
6483 SmcCloseConnection(xsmp.smcconn, 0, NULL);
6484 xsmp_icefd = -1;
6485 }
6486}
6487#endif /* USE_XSMP */
6488
6489
6490#ifdef EBCDIC
6491/* Translate character to its CTRL- value */
6492char CtrlTable[] =
6493{
6494/* 00 - 5E */
6495 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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,
6501/* ^ */ 0x1E,
6502/* - */ 0x1F,
6503/* 61 - 6C */
6504 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6505/* _ */ 0x1F,
6506/* 6E - 80 */
6507 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6508/* a */ 0x01,
6509/* b */ 0x02,
6510/* c */ 0x03,
6511/* d */ 0x37,
6512/* e */ 0x2D,
6513/* f */ 0x2E,
6514/* g */ 0x2F,
6515/* h */ 0x16,
6516/* i */ 0x05,
6517/* 8A - 90 */
6518 0, 0, 0, 0, 0, 0, 0,
6519/* j */ 0x15,
6520/* k */ 0x0B,
6521/* l */ 0x0C,
6522/* m */ 0x0D,
6523/* n */ 0x0E,
6524/* o */ 0x0F,
6525/* p */ 0x10,
6526/* q */ 0x11,
6527/* r */ 0x12,
6528/* 9A - A1 */
6529 0, 0, 0, 0, 0, 0, 0, 0,
6530/* s */ 0x13,
6531/* t */ 0x3C,
6532/* u */ 0x3D,
6533/* v */ 0x32,
6534/* w */ 0x26,
6535/* x */ 0x18,
6536/* y */ 0x19,
6537/* z */ 0x3F,
6538/* AA - AC */
6539 0, 0, 0,
6540/* [ */ 0x27,
6541/* AE - BC */
6542 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6543/* ] */ 0x1D,
6544/* BE - C0 */ 0, 0, 0,
6545/* A */ 0x01,
6546/* B */ 0x02,
6547/* C */ 0x03,
6548/* D */ 0x37,
6549/* E */ 0x2D,
6550/* F */ 0x2E,
6551/* G */ 0x2F,
6552/* H */ 0x16,
6553/* I */ 0x05,
6554/* CA - D0 */ 0, 0, 0, 0, 0, 0, 0,
6555/* J */ 0x15,
6556/* K */ 0x0B,
6557/* L */ 0x0C,
6558/* M */ 0x0D,
6559/* N */ 0x0E,
6560/* O */ 0x0F,
6561/* P */ 0x10,
6562/* Q */ 0x11,
6563/* R */ 0x12,
6564/* DA - DF */ 0, 0, 0, 0, 0, 0,
6565/* \ */ 0x1C,
6566/* E1 */ 0,
6567/* S */ 0x13,
6568/* T */ 0x3C,
6569/* U */ 0x3D,
6570/* V */ 0x32,
6571/* W */ 0x26,
6572/* X */ 0x18,
6573/* Y */ 0x19,
6574/* Z */ 0x3F,
6575/* EA - FF*/ 0, 0, 0, 0, 0, 0,
6576 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6577};
6578
6579char MetaCharTable[]=
6580{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6581 0, 0, 0, 0,'\\', 0,'F', 0,'W','M','N', 0, 0, 0, 0, 0,
6582 0, 0, 0, 0,']', 0, 0,'G', 0, 0,'R','O', 0, 0, 0, 0,
6583 '@','A','B','C','D','E', 0, 0,'H','I','J','K','L', 0, 0, 0,
6584 'P','Q', 0,'S','T','U','V', 0,'X','Y','Z','[', 0, 0,'^', 0
6585};
6586
6587
6588/* TODO: Use characters NOT numbers!!! */
6589char CtrlCharTable[]=
6590{/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
6591 124,193,194,195, 0,201, 0, 0, 0, 0, 0,210,211,212,213,214,
6592 215,216,217,226, 0,209,200, 0,231,232, 0, 0,224,189, 95,109,
6593 0, 0, 0, 0, 0, 0,230,173, 0, 0, 0, 0, 0,197,198,199,
6594 0, 0,229, 0, 0, 0, 0,196, 0, 0, 0, 0,227,228, 0,233,
6595};
6596
6597
6598#endif