comparison src/os_unix.c @ 7:3fc0f57ecb91 v7.0001

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