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