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