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