1 /* $NetBSD: cl_funcs.c,v 1.9 2018/08/07 08:05:47 rin Exp $ */ 2 /*- 3 * Copyright (c) 1993, 1994 4 * The Regents of the University of California. All rights reserved. 5 * Copyright (c) 1993, 1994, 1995, 1996 6 * Keith Bostic. All rights reserved. 7 * 8 * See the LICENSE file for redistribution information. 9 */ 10 11 #include "config.h" 12 13 #include <sys/cdefs.h> 14 #if 0 15 #ifndef lint 16 static const char sccsid[] = "Id: cl_funcs.c,v 10.72 2002/03/02 23:18:33 skimo Exp (Berkeley) Date: 2002/03/02 23:18:33 "; 17 #endif /* not lint */ 18 #else 19 __RCSID("$NetBSD: cl_funcs.c,v 1.9 2018/08/07 08:05:47 rin Exp $"); 20 #endif 21 22 #include <sys/types.h> 23 #include <sys/queue.h> 24 #include <sys/time.h> 25 26 #include <bitstring.h> 27 #include <ctype.h> 28 #include <signal.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <termios.h> 33 #include <unistd.h> 34 35 #include "../common/common.h" 36 #include "../vi/vi.h" 37 #include "cl.h" 38 39 static void cl_rdiv __P((SCR *)); 40 41 static int 42 addstr4(SCR *sp, const void *str, size_t len, int wide) 43 { 44 WINDOW *win; 45 size_t y, x; 46 int iv; 47 48 win = CLSP(sp) ? CLSP(sp) : stdscr; 49 50 /* 51 * If ex isn't in control, it's the last line of the screen and 52 * it's a split screen, use inverse video. 53 */ 54 iv = 0; 55 getyx(win, y, x); 56 __USE(x); 57 if (!F_ISSET(sp, SC_SCR_EXWROTE) && 58 y == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) { 59 iv = 1; 60 (void)wstandout(win); 61 } 62 63 #ifdef USE_WIDECHAR 64 if (wide) { 65 if (waddnwstr(win, str, len) == ERR) 66 return (1); 67 } else 68 #endif 69 if (waddnstr(win, str, len) == ERR) 70 return (1); 71 72 if (iv) 73 (void)wstandend(win); 74 return (0); 75 } 76 77 /* 78 * cl_waddstr -- 79 * Add len bytes from the string at the cursor, advancing the cursor. 80 * 81 * PUBLIC: int cl_waddstr __P((SCR *, const CHAR_T *, size_t)); 82 */ 83 int 84 cl_waddstr(SCR *sp, const CHAR_T *str, size_t len) 85 { 86 return addstr4(sp, (const void *)str, len, 1); 87 } 88 89 /* 90 * cl_addstr -- 91 * Add len bytes from the string at the cursor, advancing the cursor. 92 * 93 * PUBLIC: int cl_addstr __P((SCR *, const char *, size_t)); 94 */ 95 int 96 cl_addstr(SCR *sp, const char *str, size_t len) 97 { 98 return addstr4(sp, (const void *)str, len, 0); 99 } 100 101 /* 102 * cl_attr -- 103 * Toggle a screen attribute on/off. 104 * 105 * PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int)); 106 */ 107 int 108 cl_attr(SCR *sp, scr_attr_t attribute, int on) 109 { 110 CL_PRIVATE *clp; 111 WINDOW *win; 112 113 clp = CLP(sp); 114 win = CLSP(sp) ? CLSP(sp) : stdscr; 115 116 switch (attribute) { 117 case SA_ALTERNATE: 118 /* 119 * !!! 120 * There's a major layering violation here. The problem is that the 121 * X11 xterm screen has what's known as an "alternate" screen. Some 122 * xterm termcap/terminfo entries include sequences to switch to/from 123 * that alternate screen as part of the ti/te (smcup/rmcup) strings. 124 * Vi runs in the alternate screen, so that you are returned to the 125 * same screen contents on exit from vi that you had when you entered 126 * vi. Further, when you run :shell, or :!date or similar ex commands, 127 * you also see the original screen contents. This wasn't deliberate 128 * on vi's part, it's just that it historically sent terminal init/end 129 * sequences at those times, and the addition of the alternate screen 130 * sequences to the strings changed the behavior of vi. The problem 131 * caused by this is that we don't want to switch back to the alternate 132 * screen while getting a new command from the user, when the user is 133 * continuing to enter ex commands, e.g.: 134 * 135 * :!date <<< switch to original screen 136 * [Hit return to continue] <<< prompt user to continue 137 * :command <<< get command from user 138 * 139 * Note that the :command input is a true vi input mode, e.g., input 140 * maps and abbreviations are being done. So, we need to be able to 141 * switch back into the vi screen mode, without flashing the screen. 142 * 143 * To make matters worse, the curses initscr() and endwin() calls will 144 * do this automatically -- so, this attribute isn't as controlled by 145 * the higher level screen as closely as one might like. 146 */ 147 if (on) { 148 if (clp->ti_te != TI_SENT) { 149 clp->ti_te = TI_SENT; 150 if (clp->smcup == NULL) 151 (void)cl_getcap(sp, "smcup", &clp->smcup); 152 if (clp->smcup != NULL) 153 (void)tputs(clp->smcup, 1, cl_putchar); 154 } 155 } else if (clp->ti_te != TE_SENT) { 156 clp->ti_te = TE_SENT; 157 if (clp->rmcup == NULL) 158 (void)cl_getcap(sp, "rmcup", &clp->rmcup); 159 if (clp->rmcup != NULL) 160 (void)tputs(clp->rmcup, 1, cl_putchar); 161 } 162 (void)fflush(stdout); 163 break; 164 case SA_INVERSE: 165 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) { 166 if (clp->smso == NULL) 167 return (1); 168 if (on) 169 (void)tputs(clp->smso, 1, cl_putchar); 170 else 171 (void)tputs(clp->rmso, 1, cl_putchar); 172 (void)fflush(stdout); 173 } else { 174 if (on) 175 (void)wstandout(win); 176 else 177 (void)wstandend(win); 178 } 179 break; 180 default: 181 abort(); 182 } 183 return (0); 184 } 185 186 /* 187 * cl_baud -- 188 * Return the baud rate. 189 * 190 * PUBLIC: int cl_baud __P((SCR *, u_long *)); 191 */ 192 int 193 cl_baud(SCR *sp, u_long *ratep) 194 { 195 CL_PRIVATE *clp; 196 197 /* 198 * XXX 199 * There's no portable way to get a "baud rate" -- cfgetospeed(3) 200 * returns the value associated with some #define, which we may 201 * never have heard of, or which may be a purely local speed. Vi 202 * only cares if it's SLOW (w300), slow (w1200) or fast (w9600). 203 * Try and detect the slow ones, and default to fast. 204 */ 205 clp = CLP(sp); 206 switch (cfgetospeed(&clp->orig)) { 207 case B50: 208 case B75: 209 case B110: 210 case B134: 211 case B150: 212 case B200: 213 case B300: 214 case B600: 215 *ratep = 600; 216 break; 217 case B1200: 218 *ratep = 1200; 219 break; 220 default: 221 *ratep = 9600; 222 break; 223 } 224 return (0); 225 } 226 227 /* 228 * cl_bell -- 229 * Ring the bell/flash the screen. 230 * 231 * PUBLIC: int cl_bell __P((SCR *)); 232 */ 233 int 234 cl_bell(SCR *sp) 235 { 236 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE | SC_SCR_EX)) 237 (void)write(STDOUT_FILENO, "\07", 1); /* \a */ 238 else { 239 /* 240 * Vi has an edit option which determines if the terminal 241 * should be beeped or the screen flashed. 242 */ 243 if (O_ISSET(sp, O_FLASH)) 244 (void)flash(); 245 else 246 (void)beep(); 247 } 248 return (0); 249 } 250 251 /* 252 * cl_clrtoeol -- 253 * Clear from the current cursor to the end of the line. 254 * 255 * PUBLIC: int cl_clrtoeol __P((SCR *)); 256 */ 257 int 258 cl_clrtoeol(SCR *sp) 259 { 260 WINDOW *win; 261 #if 0 262 size_t spcnt, y, x; 263 #endif 264 265 win = CLSP(sp) ? CLSP(sp) : stdscr; 266 267 #if 0 268 if (IS_VSPLIT(sp)) { 269 /* The cursor must be returned to its original position. */ 270 getyx(win, y, x); 271 for (spcnt = (sp->coff + sp->cols) - x; spcnt > 0; --spcnt) 272 (void)waddch(win, ' '); 273 (void)wmove(win, y, x); 274 return (0); 275 } else 276 #endif 277 return (wclrtoeol(win) == ERR); 278 } 279 280 /* 281 * cl_cursor -- 282 * Return the current cursor position. 283 * 284 * PUBLIC: int cl_cursor __P((SCR *, size_t *, size_t *)); 285 */ 286 int 287 cl_cursor(SCR *sp, size_t *yp, size_t *xp) 288 { 289 WINDOW *win; 290 win = CLSP(sp) ? CLSP(sp) : stdscr; 291 /* 292 * The curses screen support splits a single underlying curses screen 293 * into multiple screens to support split screen semantics. For this 294 * reason the returned value must be adjusted to be relative to the 295 * current screen, and not absolute. Screens that implement the split 296 * using physically distinct screens won't need this hack. 297 */ 298 getyx(win, *yp, *xp); 299 /* 300 *yp -= sp->roff; 301 *xp -= sp->coff; 302 */ 303 return (0); 304 } 305 306 /* 307 * cl_deleteln -- 308 * Delete the current line, scrolling all lines below it. 309 * 310 * PUBLIC: int cl_deleteln __P((SCR *)); 311 */ 312 int 313 cl_deleteln(SCR *sp) 314 { 315 WINDOW *win; 316 size_t y, x; 317 #ifndef HAVE_MVWCHGAT 318 CHAR_T ch; 319 size_t col, lno, spcnt; 320 #endif 321 322 win = CLSP(sp) ? CLSP(sp) : stdscr; 323 324 /* 325 * This clause is required because the curses screen uses reverse 326 * video to delimit split screens. If the screen does not do this, 327 * this code won't be necessary. 328 * 329 * If the bottom line was in reverse video, rewrite it in normal 330 * video before it's scrolled. 331 * 332 * Check for the existence of a chgat function; XSI requires it, but 333 * historic implementations of System V curses don't. If it's not 334 * a #define, we'll fall back to doing it by hand, which is slow but 335 * acceptable. 336 * 337 * By hand means walking through the line, retrieving and rewriting 338 * each character. Curses has no EOL marker, so track strings of 339 * spaces, and copy the trailing spaces only if there's a non-space 340 * character following. 341 */ 342 if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) { 343 getyx(win, y, x); 344 #ifdef HAVE_MVWCHGAT 345 mvwchgat(win, RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL); 346 #else 347 for (lno = RLNO(sp, LASTLINE(sp)), col = spcnt = 0;;) { 348 (void)wmove(win, lno, col); 349 ch = winch(win); 350 if (ISBLANK(ch)) 351 ++spcnt; 352 else { 353 (void)wmove(win, lno, col - spcnt); 354 for (; spcnt > 0; --spcnt) 355 (void)waddch(win, ' '); 356 (void)waddch(win, ch); 357 } 358 if (++col >= sp->cols) 359 break; 360 } 361 #endif 362 (void)wmove(win, y, x); 363 } 364 365 /* 366 * The bottom line is expected to be blank after this operation, 367 * and other screens must support that semantic. 368 */ 369 return (wdeleteln(win) == ERR); 370 } 371 372 /* 373 * cl_discard -- 374 * Discard a screen. 375 * 376 * PUBLIC: int cl_discard __P((SCR *, SCR **)); 377 */ 378 int 379 cl_discard(SCR *discardp, SCR **acquirep) 380 { 381 CL_PRIVATE *clp; 382 SCR* tsp; 383 384 if (discardp) { 385 clp = CLP(discardp); 386 F_SET(clp, CL_LAYOUT); 387 388 if (CLSP(discardp)) { 389 delwin(CLSP(discardp)); 390 discardp->cl_private = NULL; 391 } 392 } 393 394 /* no screens got a piece; we're done */ 395 if (!acquirep) 396 return 0; 397 398 for (; (tsp = *acquirep) != NULL; ++acquirep) { 399 clp = CLP(tsp); 400 F_SET(clp, CL_LAYOUT); 401 402 if (CLSP(tsp)) 403 delwin(CLSP(tsp)); 404 tsp->cl_private = subwin(stdscr, tsp->rows, tsp->cols, 405 tsp->roff, tsp->coff); 406 } 407 408 /* discardp is going away, acquirep is taking up its space. */ 409 return (0); 410 } 411 412 /* 413 * cl_ex_adjust -- 414 * Adjust the screen for ex. This routine is purely for standalone 415 * ex programs. All special purpose, all special case. 416 * 417 * PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t)); 418 */ 419 int 420 cl_ex_adjust(SCR *sp, exadj_t action) 421 { 422 CL_PRIVATE *clp; 423 int cnt; 424 425 clp = CLP(sp); 426 switch (action) { 427 case EX_TERM_SCROLL: 428 /* Move the cursor up one line if that's possible. */ 429 if (clp->cuu1 != NULL) 430 (void)tputs(clp->cuu1, 1, cl_putchar); 431 else if (clp->cup != NULL) 432 (void)tputs(tgoto(clp->cup, 433 0, LINES - 2), 1, cl_putchar); 434 else 435 return (0); 436 /* FALLTHROUGH */ 437 case EX_TERM_CE: 438 /* Clear the line. */ 439 if (clp->el != NULL) { 440 (void)putchar('\r'); 441 (void)tputs(clp->el, 1, cl_putchar); 442 } else { 443 /* 444 * Historically, ex didn't erase the line, so, if the 445 * displayed line was only a single glyph, and <eof> 446 * was more than one glyph, the output would not fully 447 * overwrite the user's input. To fix this, output 448 * the maxiumum character number of spaces. Note, 449 * this won't help if the user entered extra prompt 450 * or <blank> characters before the command character. 451 * We'd have to do a lot of work to make that work, and 452 * it's almost certainly not worth the effort. 453 */ 454 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) 455 (void)putchar('\b'); 456 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) 457 (void)putchar(' '); 458 (void)putchar('\r'); 459 (void)fflush(stdout); 460 } 461 break; 462 default: 463 abort(); 464 } 465 return (0); 466 } 467 468 #ifdef IMCTRL 469 /* 470 * cl_imctrl -- 471 * Control the state of input method by using escape sequences compatible 472 * to Tera Term and RLogin. 473 * 474 * PUBLIC: void cl_imctrl __P((SCR *, imctrl_t)); 475 */ 476 void 477 cl_imctrl(SCR *sp, imctrl_t action) 478 { 479 #define TT_IM_OFF "\033[<t" /* TTIMEST */ 480 #define TT_IM_RESTORE "\033[<r" /* TTIMERS */ 481 #define TT_IM_SAVE "\033[<s" /* TTIMESV */ 482 483 if (!O_ISSET(sp, O_IMCTRL) && action != IMCTRL_INIT) 484 return; 485 486 switch (action) { 487 case IMCTRL_INIT: 488 (void)printf(TT_IM_OFF TT_IM_SAVE); 489 break; 490 case IMCTRL_OFF: 491 (void)printf(TT_IM_SAVE TT_IM_OFF); 492 break; 493 case IMCTRL_ON: 494 (void)printf(TT_IM_RESTORE); 495 break; 496 default: 497 abort(); 498 } 499 (void)fflush(stdout); 500 } 501 #endif 502 503 /* 504 * cl_insertln -- 505 * Push down the current line, discarding the bottom line. 506 * 507 * PUBLIC: int cl_insertln __P((SCR *)); 508 */ 509 int 510 cl_insertln(SCR *sp) 511 { 512 WINDOW *win; 513 win = CLSP(sp) ? CLSP(sp) : stdscr; 514 /* 515 * The current line is expected to be blank after this operation, 516 * and the screen must support that semantic. 517 */ 518 return (winsertln(win) == ERR); 519 } 520 521 /* 522 * cl_keyval -- 523 * Return the value for a special key. 524 * 525 * PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *)); 526 */ 527 int 528 cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep) 529 { 530 CL_PRIVATE *clp; 531 532 /* 533 * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990, 534 * VWERASE is a 4BSD extension. 535 */ 536 clp = CLP(sp); 537 switch (val) { 538 case KEY_VEOF: 539 *dnep = 540 (*chp = clp->orig.c_cc[VEOF]) == (CHAR_T)_POSIX_VDISABLE; 541 break; 542 case KEY_VERASE: 543 *dnep = 544 (*chp = clp->orig.c_cc[VERASE]) == (CHAR_T)_POSIX_VDISABLE; 545 break; 546 case KEY_VKILL: 547 *dnep = 548 (*chp = clp->orig.c_cc[VKILL]) == (CHAR_T)_POSIX_VDISABLE; 549 break; 550 #ifdef VWERASE 551 case KEY_VWERASE: 552 *dnep = 553 (*chp = clp->orig.c_cc[VWERASE]) == (CHAR_T)_POSIX_VDISABLE; 554 break; 555 #endif 556 default: 557 *dnep = 1; 558 break; 559 } 560 return (0); 561 } 562 563 /* 564 * cl_move -- 565 * Move the cursor. 566 * 567 * PUBLIC: int cl_move __P((SCR *, size_t, size_t)); 568 */ 569 int 570 cl_move(SCR *sp, size_t lno, size_t cno) 571 { 572 WINDOW *win; 573 win = CLSP(sp) ? CLSP(sp) : stdscr; 574 /* See the comment in cl_cursor. */ 575 if (wmove(win, RLNO(sp, lno), RCNO(sp, cno)) == ERR) { 576 msgq(sp, M_ERR, "Error: move: l(%zu + %zu) c(%zu + %zu)", 577 lno, sp->roff, cno, sp->coff); 578 return (1); 579 } 580 return (0); 581 } 582 583 /* 584 * cl_refresh -- 585 * Refresh the screen. 586 * 587 * PUBLIC: int cl_refresh __P((SCR *, int)); 588 */ 589 int 590 cl_refresh(SCR *sp, int repaint) 591 { 592 CL_PRIVATE *clp; 593 WINDOW *win; 594 SCR *psp, *tsp; 595 size_t y, x; 596 597 clp = CLP(sp); 598 win = CLSP(sp) ? CLSP(sp) : stdscr; 599 600 /* 601 * If we received a killer signal, we're done, there's no point 602 * in refreshing the screen. 603 */ 604 if (clp->killersig) 605 return (0); 606 607 /* 608 * If repaint is set, the editor is telling us that we don't know 609 * what's on the screen, so we have to repaint from scratch. 610 * 611 * If repaint set or the screen layout changed, we need to redraw 612 * any lines separating vertically split screens. If the horizontal 613 * offsets are the same, then the split was vertical, and need to 614 * draw a dividing line. 615 */ 616 if (repaint || F_ISSET(clp, CL_LAYOUT)) { 617 getyx(stdscr, y, x); 618 for (psp = sp; psp != NULL; psp = TAILQ_NEXT(psp, q)) 619 for (tsp = TAILQ_NEXT(psp, q); tsp != NULL; 620 tsp = TAILQ_NEXT(tsp, q)) 621 if (psp->roff == tsp->roff) { 622 if (psp->coff + psp->cols + 1 == tsp->coff) 623 cl_rdiv(psp); 624 else 625 if (tsp->coff + tsp->cols + 1 == psp->coff) 626 cl_rdiv(tsp); 627 } 628 (void)wmove(stdscr, y, x); 629 F_CLR(clp, CL_LAYOUT); 630 } 631 632 /* 633 * In the curses library, doing wrefresh(curscr) is okay, but the 634 * screen flashes when we then apply the refresh() to bring it up 635 * to date. So, use clearok(). 636 */ 637 if (repaint) 638 clearok(curscr, 1); 639 /* 640 * Only do an actual refresh, when this is the focus window, 641 * i.e. the one holding the cursor. This assumes that refresh 642 * is called for that window after refreshing the others. 643 * This prevents the cursor being drawn in the other windows. 644 */ 645 return (wnoutrefresh(stdscr) == ERR || 646 wnoutrefresh(win) == ERR || 647 (sp == clp->focus && doupdate() == ERR)); 648 } 649 650 /* 651 * cl_rdiv -- 652 * Draw a dividing line between two vertically split screens. 653 */ 654 static void 655 cl_rdiv(SCR *sp) 656 { 657 size_t cnt; 658 659 for (cnt = 0; cnt < sp->rows - 1; ++cnt) { 660 wmove(stdscr, sp->roff + cnt, sp->cols + sp->coff); 661 waddch(stdscr, '|'); 662 } 663 } 664 665 /* 666 * cl_rename -- 667 * Rename the file. 668 * 669 * PUBLIC: int cl_rename __P((SCR *, char *, int)); 670 */ 671 int 672 cl_rename(SCR *sp, char *name, int on) 673 { 674 CL_PRIVATE *clp; 675 FILE *pfp; 676 GS *gp; 677 char buf[256], *p; 678 679 gp = sp->gp; 680 clp = CLP(sp); 681 682 if (on) { 683 clp->focus = sp; 684 if (!F_ISSET(clp, CL_RENAME_OK)) 685 return (0); 686 687 /* 688 * XXX 689 * We can only rename windows for xterm. 690 */ 691 if (strncmp(OG_STR(gp, GO_TERM), "xterm", sizeof("xterm") - 1)) 692 return (0); 693 694 /* 695 * XXX 696 * Try and figure out the current name of this window. There 697 * are two forms of the xwininfo output I've seen: 698 * 699 * Window id: 0x400000d "name" 700 * Window id: 0x140000d (name) 701 */ 702 #define COMMAND \ 703 "expr \"`xwininfo -id $WINDOWID | grep id:`\" : '.* [\"(]\\(.*\\)[\")]'" 704 705 if (clp->oname == NULL && 706 (pfp = popen(COMMAND, "r")) != NULL) { 707 if (fgets(buf, sizeof(buf), pfp) != NULL && 708 (p = strchr(buf, '\n')) != NULL) { 709 *p = '\0'; 710 clp->oname = strdup(buf); 711 } 712 (void)fclose(pfp); 713 } 714 715 cl_setname(gp, name); 716 717 F_SET(clp, CL_RENAME); 718 } else 719 if (F_ISSET(clp, CL_RENAME)) { 720 cl_setname(gp, clp->oname); 721 722 F_CLR(clp, CL_RENAME); 723 } 724 return (0); 725 } 726 727 /* 728 * cl_setname -- 729 * Set a X11 icon/window name. 730 * 731 * PUBLIC: void cl_setname __P((GS *, char *)); 732 */ 733 void 734 cl_setname(GS *gp, char *name) 735 { 736 /* X11 xterm escape sequence to rename the icon/window. */ 737 #define XTERM_RENAME "\033]0;%s\007" 738 739 (void)printf(XTERM_RENAME, name == NULL ? OG_STR(gp, GO_TERM) : name); 740 (void)fflush(stdout); 741 } 742 743 /* 744 * cl_split -- 745 * Split a screen. 746 * 747 * PUBLIC: int cl_split __P((SCR *, SCR *)); 748 */ 749 int 750 cl_split(SCR *origp, SCR *newp) 751 { 752 CL_PRIVATE *clp; 753 754 clp = CLP(origp); 755 F_SET(clp, CL_LAYOUT); 756 757 if (CLSP(origp)) 758 delwin(CLSP(origp)); 759 760 origp->cl_private = subwin(stdscr, origp->rows, origp->cols, 761 origp->roff, origp->coff); 762 newp->cl_private = subwin(stdscr, newp->rows, newp->cols, 763 newp->roff, newp->coff); 764 765 /* origp is the original screen, giving up space to newp. */ 766 return (0); 767 } 768 769 /* 770 * cl_suspend -- 771 * Suspend a screen. 772 * 773 * PUBLIC: int cl_suspend __P((SCR *, int *)); 774 */ 775 int 776 cl_suspend(SCR *sp, int *allowedp) 777 { 778 struct termios t; 779 CL_PRIVATE *clp; 780 WINDOW *win; 781 size_t y, x; 782 int changed; 783 784 clp = CLP(sp); 785 win = CLSP(sp) ? CLSP(sp) : stdscr; 786 *allowedp = 1; 787 788 /* 789 * The ex implementation of this function isn't needed by screens not 790 * supporting ex commands that require full terminal canonical mode 791 * (e.g. :suspend). 792 * 793 * The vi implementation of this function isn't needed by screens not 794 * supporting vi process suspension, i.e. any screen that isn't backed 795 * by a UNIX shell. 796 * 797 * Setting allowedp to 0 will cause the editor to reject the command. 798 */ 799 if (F_ISSET(sp, SC_EX)) { 800 /* Save the terminal settings, and restore the original ones. */ 801 if (F_ISSET(clp, CL_STDIN_TTY)) { 802 (void)tcgetattr(STDIN_FILENO, &t); 803 (void)tcsetattr(STDIN_FILENO, 804 TCSASOFT | TCSADRAIN, &clp->orig); 805 } 806 807 /* Stop the process group. */ 808 (void)kill(0, SIGTSTP); 809 810 /* Time passes ... */ 811 812 /* Restore terminal settings. */ 813 if (F_ISSET(clp, CL_STDIN_TTY)) 814 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); 815 return (0); 816 } 817 818 /* 819 * Move to the lower left-hand corner of the screen. 820 * 821 * XXX 822 * Not sure this is necessary in System V implementations, but it 823 * shouldn't hurt. 824 */ 825 getyx(win, y, x); 826 (void)wmove(win, LINES - 1, 0); 827 (void)wrefresh(win); 828 829 /* 830 * Temporarily end the screen. System V introduced a semantic where 831 * endwin() could be restarted. We use it because restarting curses 832 * from scratch often fails in System V. 4BSD curses didn't support 833 * restarting after endwin(), so we have to do what clean up we can 834 * without calling it. 835 */ 836 /* Save the terminal settings. */ 837 (void)tcgetattr(STDIN_FILENO, &t); 838 839 /* Restore the cursor keys to normal mode. */ 840 (void)keypad(stdscr, FALSE); 841 842 /* Restore the window name. */ 843 (void)cl_rename(sp, NULL, 0); 844 845 #ifdef HAVE_BSD_CURSES 846 (void)cl_attr(sp, SA_ALTERNATE, 0); 847 #else 848 (void)endwin(); 849 #endif 850 /* 851 * XXX 852 * Restore the original terminal settings. This is bad -- the 853 * reset can cause character loss from the tty queue. However, 854 * we can't call endwin() in BSD curses implementations, and too 855 * many System V curses implementations don't get it right. 856 */ 857 (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig); 858 859 /* Stop the process group. */ 860 (void)kill(0, SIGTSTP); 861 862 /* Time passes ... */ 863 864 /* 865 * If we received a killer signal, we're done. Leave everything 866 * unchanged. In addition, the terminal has already been reset 867 * correctly, so leave it alone. 868 */ 869 if (clp->killersig) { 870 F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT); 871 return (0); 872 } 873 874 /* Restore terminal settings. */ 875 wrefresh(win); /* Needed on SunOs/Solaris ? */ 876 if (F_ISSET(clp, CL_STDIN_TTY)) 877 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); 878 879 #ifdef HAVE_BSD_CURSES 880 (void)cl_attr(sp, SA_ALTERNATE, 1); 881 #endif 882 883 /* Set the window name. */ 884 (void)cl_rename(sp, sp->frp->name, 1); 885 886 /* Put the cursor keys into application mode. */ 887 (void)keypad(stdscr, TRUE); 888 889 /* Refresh and repaint the screen. */ 890 (void)wmove(win, y, x); 891 (void)cl_refresh(sp, 1); 892 893 /* If the screen changed size, set the SIGWINCH bit. */ 894 if (cl_ssize(sp, 1, NULL, NULL, &changed)) 895 return (1); 896 if (changed) 897 F_SET(CLP(sp), CL_SIGWINCH); 898 899 return (0); 900 } 901 902 /* 903 * cl_usage -- 904 * Print out the curses usage messages. 905 * 906 * PUBLIC: void cl_usage __P((void)); 907 */ 908 void 909 cl_usage(void) 910 { 911 #define USAGE "\ 912 usage: ex [-eFRrSsv] [-c command] [-t tag] [-w size] [file ...]\n\ 913 usage: vi [-eFlRrSv] [-c command] [-t tag] [-w size] [file ...]\n" 914 (void)fprintf(stderr, "%s", USAGE); 915 #undef USAGE 916 } 917 918 #ifdef DEBUG 919 /* 920 * gdbrefresh -- 921 * Stub routine so can flush out curses screen changes using gdb. 922 */ 923 int 924 gdbrefresh(void) 925 { 926 refresh(); 927 return (0); /* XXX Convince gdb to run it. */ 928 } 929 #endif 930