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