1 /* $OpenBSD: cl_funcs.c,v 1.14 2009/10/27 23:59:47 deraadt Exp $ */ 2 3 /*- 4 * Copyright (c) 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * Copyright (c) 1993, 1994, 1995, 1996 7 * Keith Bostic. All rights reserved. 8 * 9 * See the LICENSE file for redistribution information. 10 */ 11 12 #include "config.h" 13 14 #include <sys/types.h> 15 #include <sys/queue.h> 16 #include <sys/time.h> 17 18 #include <bitstring.h> 19 #include <ctype.h> 20 #include <curses.h> 21 #include <signal.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <term.h> 26 #include <termios.h> 27 #include <unistd.h> 28 29 #include "../common/common.h" 30 #include "../vi/vi.h" 31 #include "cl.h" 32 33 /* 34 * cl_addstr -- 35 * Add len bytes from the string at the cursor, advancing the cursor. 36 * 37 * PUBLIC: int cl_addstr(SCR *, const char *, size_t); 38 */ 39 int 40 cl_addstr(sp, str, len) 41 SCR *sp; 42 const char *str; 43 size_t len; 44 { 45 size_t oldy, oldx; 46 int iv; 47 48 /* 49 * If ex isn't in control, it's the last line of the screen and 50 * it's a split screen, use inverse video. 51 */ 52 iv = 0; 53 getyx(stdscr, oldy, oldx); 54 if (!F_ISSET(sp, SC_SCR_EXWROTE) && 55 oldy == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) { 56 iv = 1; 57 (void)standout(); 58 } 59 60 if (addnstr(str, len) == ERR) 61 return (1); 62 63 if (iv) 64 (void)standend(); 65 return (0); 66 } 67 68 /* 69 * cl_attr -- 70 * Toggle a screen attribute on/off. 71 * 72 * PUBLIC: int cl_attr(SCR *, scr_attr_t, int); 73 */ 74 int 75 cl_attr(sp, attribute, on) 76 SCR *sp; 77 scr_attr_t attribute; 78 int on; 79 { 80 CL_PRIVATE *clp; 81 82 clp = CLP(sp); 83 84 switch (attribute) { 85 case SA_ALTERNATE: 86 /* 87 * !!! 88 * There's a major layering violation here. The problem is that the 89 * X11 xterm screen has what's known as an "alternate" screen. Some 90 * xterm termcap/terminfo entries include sequences to switch to/from 91 * that alternate screen as part of the ti/te (smcup/rmcup) strings. 92 * Vi runs in the alternate screen, so that you are returned to the 93 * same screen contents on exit from vi that you had when you entered 94 * vi. Further, when you run :shell, or :!date or similar ex commands, 95 * you also see the original screen contents. This wasn't deliberate 96 * on vi's part, it's just that it historically sent terminal init/end 97 * sequences at those times, and the addition of the alternate screen 98 * sequences to the strings changed the behavior of vi. The problem 99 * caused by this is that we don't want to switch back to the alternate 100 * screen while getting a new command from the user, when the user is 101 * continuing to enter ex commands, e.g.: 102 * 103 * :!date <<< switch to original screen 104 * [Hit return to continue] <<< prompt user to continue 105 * :command <<< get command from user 106 * 107 * Note that the :command input is a true vi input mode, e.g., input 108 * maps and abbreviations are being done. So, we need to be able to 109 * switch back into the vi screen mode, without flashing the screen. 110 * 111 * To make matters worse, the curses initscr() and endwin() calls will 112 * do this automatically -- so, this attribute isn't as controlled by 113 * the higher level screen as closely as one might like. 114 */ 115 if (on) { 116 if (clp->ti_te != TI_SENT) { 117 clp->ti_te = TI_SENT; 118 if (clp->smcup == NULL) 119 (void)cl_getcap(sp, "smcup", &clp->smcup); 120 if (clp->smcup != NULL) 121 (void)tputs(clp->smcup, 1, cl_putchar); 122 } 123 } else 124 if (clp->ti_te != TE_SENT) { 125 clp->ti_te = TE_SENT; 126 if (clp->rmcup == NULL) 127 (void)cl_getcap(sp, "rmcup", &clp->rmcup); 128 if (clp->rmcup != NULL) 129 (void)tputs(clp->rmcup, 1, cl_putchar); 130 (void)fflush(stdout); 131 } 132 (void)fflush(stdout); 133 break; 134 case SA_INVERSE: 135 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) { 136 if (clp->smso == NULL) 137 return (1); 138 if (on) 139 (void)tputs(clp->smso, 1, cl_putchar); 140 else 141 (void)tputs(clp->rmso, 1, cl_putchar); 142 (void)fflush(stdout); 143 } else { 144 if (on) 145 (void)standout(); 146 else 147 (void)standend(); 148 } 149 break; 150 default: 151 abort(); 152 } 153 return (0); 154 } 155 156 /* 157 * cl_baud -- 158 * Return the baud rate. 159 * 160 * PUBLIC: int cl_baud(SCR *, u_long *); 161 */ 162 int 163 cl_baud(sp, ratep) 164 SCR *sp; 165 u_long *ratep; 166 { 167 CL_PRIVATE *clp; 168 169 /* 170 * XXX 171 * There's no portable way to get a "baud rate" -- cfgetospeed(3) 172 * returns the value associated with some #define, which we may 173 * never have heard of, or which may be a purely local speed. Vi 174 * only cares if it's SLOW (w300), slow (w1200) or fast (w9600). 175 * Try and detect the slow ones, and default to fast. 176 */ 177 clp = CLP(sp); 178 switch (cfgetospeed(&clp->orig)) { 179 case B50: 180 case B75: 181 case B110: 182 case B134: 183 case B150: 184 case B200: 185 case B300: 186 case B600: 187 *ratep = 600; 188 break; 189 case B1200: 190 *ratep = 1200; 191 break; 192 default: 193 *ratep = 9600; 194 break; 195 } 196 return (0); 197 } 198 199 /* 200 * cl_bell -- 201 * Ring the bell/flash the screen. 202 * 203 * PUBLIC: int cl_bell(SCR *); 204 */ 205 int 206 cl_bell(sp) 207 SCR *sp; 208 { 209 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) 210 (void)write(STDOUT_FILENO, "\07", 1); /* \a */ 211 else { 212 /* 213 * If the screen has not been setup we cannot call 214 * curses routines yet. 215 */ 216 if (F_ISSET(sp, SC_SCR_VI)) { 217 /* 218 * Vi has an edit option which determines if the 219 * terminal should be beeped or the screen flashed. 220 */ 221 if (O_ISSET(sp, O_FLASH)) 222 (void)flash(); 223 else 224 (void)beep(); 225 } else if (!O_ISSET(sp, O_FLASH)) 226 (void)write(STDOUT_FILENO, "\07", 1); 227 } 228 return (0); 229 } 230 231 /* 232 * cl_clrtoeol -- 233 * Clear from the current cursor to the end of the line. 234 * 235 * PUBLIC: int cl_clrtoeol(SCR *); 236 */ 237 int 238 cl_clrtoeol(sp) 239 SCR *sp; 240 { 241 return (clrtoeol() == ERR); 242 } 243 244 /* 245 * cl_cursor -- 246 * Return the current cursor position. 247 * 248 * PUBLIC: int cl_cursor(SCR *, size_t *, size_t *); 249 */ 250 int 251 cl_cursor(sp, yp, xp) 252 SCR *sp; 253 size_t *yp, *xp; 254 { 255 /* 256 * The curses screen support splits a single underlying curses screen 257 * into multiple screens to support split screen semantics. For this 258 * reason the returned value must be adjusted to be relative to the 259 * current screen, and not absolute. Screens that implement the split 260 * using physically distinct screens won't need this hack. 261 */ 262 getyx(stdscr, *yp, *xp); 263 *yp -= sp->woff; 264 return (0); 265 } 266 267 /* 268 * cl_deleteln -- 269 * Delete the current line, scrolling all lines below it. 270 * 271 * PUBLIC: int cl_deleteln(SCR *); 272 */ 273 int 274 cl_deleteln(sp) 275 SCR *sp; 276 { 277 #ifndef mvchgat 278 CHAR_T ch; 279 size_t col, lno, spcnt; 280 #endif 281 size_t oldy, oldx; 282 283 /* 284 * This clause is required because the curses screen uses reverse 285 * video to delimit split screens. If the screen does not do this, 286 * this code won't be necessary. 287 * 288 * If the bottom line was in reverse video, rewrite it in normal 289 * video before it's scrolled. 290 * 291 * Check for the existence of a chgat function; XSI requires it, but 292 * historic implementations of System V curses don't. If it's not 293 * a #define, we'll fall back to doing it by hand, which is slow but 294 * acceptable. 295 * 296 * By hand means walking through the line, retrieving and rewriting 297 * each character. Curses has no EOL marker, so track strings of 298 * spaces, and copy the trailing spaces only if there's a non-space 299 * character following. 300 */ 301 if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) { 302 getyx(stdscr, oldy, oldx); 303 #ifdef mvchgat 304 mvchgat(RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL); 305 #else 306 for (lno = RLNO(sp, LASTLINE(sp)), col = spcnt = 0;;) { 307 (void)move(lno, col); 308 ch = winch(stdscr); 309 if (isblank(ch)) 310 ++spcnt; 311 else { 312 (void)move(lno, col - spcnt); 313 for (; spcnt > 0; --spcnt) 314 (void)addch(' '); 315 (void)addch(ch); 316 } 317 if (++col >= sp->cols) 318 break; 319 } 320 #endif 321 (void)move(oldy, oldx); 322 } 323 324 /* 325 * The bottom line is expected to be blank after this operation, 326 * and other screens must support that semantic. 327 */ 328 return (deleteln() == ERR); 329 } 330 331 /* 332 * cl_ex_adjust -- 333 * Adjust the screen for ex. This routine is purely for standalone 334 * ex programs. All special purpose, all special case. 335 * 336 * PUBLIC: int cl_ex_adjust(SCR *, exadj_t); 337 */ 338 int 339 cl_ex_adjust(sp, action) 340 SCR *sp; 341 exadj_t action; 342 { 343 CL_PRIVATE *clp; 344 int cnt; 345 346 clp = CLP(sp); 347 switch (action) { 348 case EX_TERM_SCROLL: 349 /* Move the cursor up one line if that's possible. */ 350 if (clp->cuu1 != NULL) 351 (void)tputs(clp->cuu1, 1, cl_putchar); 352 else if (clp->cup != NULL) 353 (void)tputs(tgoto(clp->cup, 354 0, LINES - 2), 1, cl_putchar); 355 else 356 return (0); 357 /* FALLTHROUGH */ 358 case EX_TERM_CE: 359 /* Clear the line. */ 360 if (clp->el != NULL) { 361 (void)putchar('\r'); 362 (void)tputs(clp->el, 1, cl_putchar); 363 } else { 364 /* 365 * Historically, ex didn't erase the line, so, if the 366 * displayed line was only a single glyph, and <eof> 367 * was more than one glyph, the output would not fully 368 * overwrite the user's input. To fix this, output 369 * the maxiumum character number of spaces. Note, 370 * this won't help if the user entered extra prompt 371 * or <blank> characters before the command character. 372 * We'd have to do a lot of work to make that work, and 373 * it's almost certainly not worth the effort. 374 */ 375 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) 376 (void)putchar('\b'); 377 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) 378 (void)putchar(' '); 379 (void)putchar('\r'); 380 (void)fflush(stdout); 381 } 382 break; 383 default: 384 abort(); 385 } 386 return (0); 387 } 388 389 /* 390 * cl_insertln -- 391 * Push down the current line, discarding the bottom line. 392 * 393 * PUBLIC: int cl_insertln(SCR *); 394 */ 395 int 396 cl_insertln(sp) 397 SCR *sp; 398 { 399 /* 400 * The current line is expected to be blank after this operation, 401 * and the screen must support that semantic. 402 */ 403 return (insertln() == ERR); 404 } 405 406 /* 407 * cl_keyval -- 408 * Return the value for a special key. 409 * 410 * PUBLIC: int cl_keyval(SCR *, scr_keyval_t, CHAR_T *, int *); 411 */ 412 int 413 cl_keyval(sp, val, chp, dnep) 414 SCR *sp; 415 scr_keyval_t val; 416 CHAR_T *chp; 417 int *dnep; 418 { 419 CL_PRIVATE *clp; 420 421 /* 422 * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990, 423 * VWERASE is a 4BSD extension. 424 */ 425 clp = CLP(sp); 426 switch (val) { 427 case KEY_VEOF: 428 *dnep = (*chp = clp->orig.c_cc[VEOF]) == _POSIX_VDISABLE; 429 break; 430 case KEY_VERASE: 431 *dnep = (*chp = clp->orig.c_cc[VERASE]) == _POSIX_VDISABLE; 432 break; 433 case KEY_VKILL: 434 *dnep = (*chp = clp->orig.c_cc[VKILL]) == _POSIX_VDISABLE; 435 break; 436 #ifdef VWERASE 437 case KEY_VWERASE: 438 *dnep = (*chp = clp->orig.c_cc[VWERASE]) == _POSIX_VDISABLE; 439 break; 440 #endif 441 default: 442 *dnep = 1; 443 break; 444 } 445 return (0); 446 } 447 448 /* 449 * cl_move -- 450 * Move the cursor. 451 * 452 * PUBLIC: int cl_move(SCR *, size_t, size_t); 453 */ 454 int 455 cl_move(sp, lno, cno) 456 SCR *sp; 457 size_t lno, cno; 458 { 459 /* See the comment in cl_cursor. */ 460 if (move(RLNO(sp, lno), cno) == ERR) { 461 msgq(sp, M_ERR, 462 "Error: move: l(%u) c(%u) o(%u)", lno, cno, sp->woff); 463 return (1); 464 } 465 return (0); 466 } 467 468 /* 469 * cl_refresh -- 470 * Refresh the screen. 471 * 472 * PUBLIC: int cl_refresh(SCR *, int); 473 */ 474 int 475 cl_refresh(sp, repaint) 476 SCR *sp; 477 int repaint; 478 { 479 CL_PRIVATE *clp; 480 481 clp = CLP(sp); 482 483 /* 484 * If we received a killer signal, we're done, there's no point 485 * in refreshing the screen. 486 */ 487 if (clp->killersig) 488 return (0); 489 490 /* 491 * If repaint is set, the editor is telling us that we don't know 492 * what's on the screen, so we have to repaint from scratch. 493 * 494 * In the curses library, doing wrefresh(curscr) is okay, but the 495 * screen flashes when we then apply the refresh() to bring it up 496 * to date. So, use clearok(). 497 */ 498 if (repaint) 499 clearok(curscr, 1); 500 return (refresh() == ERR); 501 } 502 503 /* 504 * cl_rename -- 505 * Rename the file. 506 * 507 * PUBLIC: int cl_rename(SCR *, char *, int); 508 */ 509 int 510 cl_rename(sp, name, on) 511 SCR *sp; 512 char *name; 513 int on; 514 { 515 GS *gp; 516 CL_PRIVATE *clp; 517 char *ttype; 518 519 gp = sp->gp; 520 clp = CLP(sp); 521 522 ttype = OG_STR(gp, GO_TERM); 523 524 /* 525 * XXX 526 * We can only rename windows for xterm. 527 */ 528 if (on) { 529 if (F_ISSET(clp, CL_RENAME_OK) && 530 !strncmp(ttype, "xterm", sizeof("xterm") - 1)) { 531 F_SET(clp, CL_RENAME); 532 (void)printf(XTERM_RENAME, name); 533 (void)fflush(stdout); 534 } 535 } else 536 if (F_ISSET(clp, CL_RENAME)) { 537 F_CLR(clp, CL_RENAME); 538 (void)printf(XTERM_RENAME, ttype); 539 (void)fflush(stdout); 540 } 541 return (0); 542 } 543 544 /* 545 * cl_suspend -- 546 * Suspend a screen. 547 * 548 * PUBLIC: int cl_suspend(SCR *, int *); 549 */ 550 int 551 cl_suspend(sp, allowedp) 552 SCR *sp; 553 int *allowedp; 554 { 555 struct termios t; 556 CL_PRIVATE *clp; 557 size_t oldy, oldx; 558 int changed; 559 560 clp = CLP(sp); 561 *allowedp = 1; 562 563 /* 564 * The ex implementation of this function isn't needed by screens not 565 * supporting ex commands that require full terminal canonical mode 566 * (e.g. :suspend). 567 * 568 * The vi implementation of this function isn't needed by screens not 569 * supporting vi process suspension, i.e. any screen that isn't backed 570 * by a UNIX shell. 571 * 572 * Setting allowedp to 0 will cause the editor to reject the command. 573 */ 574 if (F_ISSET(sp, SC_EX)) { 575 /* Save the terminal settings, and restore the original ones. */ 576 if (F_ISSET(clp, CL_STDIN_TTY)) { 577 (void)tcgetattr(STDIN_FILENO, &t); 578 (void)tcsetattr(STDIN_FILENO, 579 TCSASOFT | TCSADRAIN, &clp->orig); 580 } 581 582 /* Stop the process group. */ 583 (void)kill(0, SIGTSTP); 584 585 /* Time passes ... */ 586 587 /* Restore terminal settings. */ 588 if (F_ISSET(clp, CL_STDIN_TTY)) 589 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); 590 return (0); 591 } 592 593 /* 594 * Move to the lower left-hand corner of the screen. 595 * 596 * XXX 597 * Not sure this is necessary in System V implementations, but it 598 * shouldn't hurt. 599 */ 600 getyx(stdscr, oldy, oldx); 601 (void)move(LINES - 1, 0); 602 (void)refresh(); 603 604 /* 605 * Temporarily end the screen. System V introduced a semantic where 606 * endwin() could be restarted. We use it because restarting curses 607 * from scratch often fails in System V. 4BSD curses didn't support 608 * restarting after endwin(), so we have to do what clean up we can 609 * without calling it. 610 */ 611 #ifdef HAVE_BSD_CURSES 612 /* Save the terminal settings. */ 613 (void)tcgetattr(STDIN_FILENO, &t); 614 #endif 615 616 /* Restore the cursor keys to normal mode. */ 617 (void)keypad(stdscr, FALSE); 618 619 /* Restore the window name. */ 620 (void)cl_rename(sp, NULL, 0); 621 622 #ifdef HAVE_BSD_CURSES 623 (void)cl_attr(sp, SA_ALTERNATE, 0); 624 #else 625 (void)endwin(); 626 #endif 627 /* 628 * XXX 629 * Restore the original terminal settings. This is bad -- the 630 * reset can cause character loss from the tty queue. However, 631 * we can't call endwin() in BSD curses implementations, and too 632 * many System V curses implementations don't get it right. 633 */ 634 (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig); 635 636 /* Stop the process group. */ 637 (void)kill(0, SIGTSTP); 638 639 /* Time passes ... */ 640 641 /* 642 * If we received a killer signal, we're done. Leave everything 643 * unchanged. In addition, the terminal has already been reset 644 * correctly, so leave it alone. 645 */ 646 if (clp->killersig) { 647 F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT); 648 return (0); 649 } 650 651 #ifdef HAVE_BSD_CURSES 652 /* Restore terminal settings. */ 653 if (F_ISSET(clp, CL_STDIN_TTY)) 654 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); 655 656 (void)cl_attr(sp, SA_ALTERNATE, 1); 657 #endif 658 659 /* Set the window name. */ 660 (void)cl_rename(sp, sp->frp->name, 1); 661 662 /* Put the cursor keys into application mode. */ 663 (void)keypad(stdscr, TRUE); 664 665 /* Refresh and repaint the screen. */ 666 (void)move(oldy, oldx); 667 (void)cl_refresh(sp, 1); 668 669 /* If the screen changed size, set the SIGWINCH bit. */ 670 if (cl_ssize(sp, 1, NULL, NULL, &changed)) 671 return (1); 672 if (changed) 673 F_SET(CLP(sp), CL_SIGWINCH); 674 675 return (0); 676 } 677 678 /* 679 * cl_usage -- 680 * Print out the curses usage messages. 681 * 682 * PUBLIC: void cl_usage(void); 683 */ 684 void 685 cl_usage() 686 { 687 switch (pmode) { 688 case MODE_EX: 689 (void)fprintf(stderr, "usage: " 690 "ex [-FRrSsv] [-c cmd] [-t tag] [-w size] [file ...]\n"); 691 break; 692 case MODE_VI: 693 (void)fprintf(stderr, "usage: " 694 "vi [-eFRrS] [-c cmd] [-t tag] [-w size] [file ...]\n"); 695 break; 696 case MODE_VIEW: 697 (void)fprintf(stderr, "usage: " 698 "view [-eFrS] [-c cmd] [-t tag] [-w size] [file ...]\n"); 699 break; 700 } 701 } 702 703 #ifdef DEBUG 704 /* 705 * gdbrefresh -- 706 * Stub routine so can flush out curses screen changes using gdb. 707 */ 708 int 709 gdbrefresh() 710 { 711 refresh(); 712 return (0); /* XXX Convince gdb to run it. */ 713 } 714 #endif 715