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