11558Srgrimes/*- 21558Srgrimes * Copyright (c) 1993, 1994 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * Copyright (c) 1993, 1994, 1995, 1996 51558Srgrimes * Keith Bostic. All rights reserved. 61558Srgrimes * 71558Srgrimes * See the LICENSE file for redistribution information. 81558Srgrimes */ 91558Srgrimes 101558Srgrimes#include "config.h" 111558Srgrimes 121558Srgrimes#ifndef lint 131558Srgrimesstatic const char sccsid[] = "$Id: cl_funcs.c,v 10.74 2012/10/11 10:30:16 zy Exp $"; 141558Srgrimes#endif /* not lint */ 151558Srgrimes 161558Srgrimes#include <sys/types.h> 171558Srgrimes#include <sys/queue.h> 181558Srgrimes#include <sys/time.h> 191558Srgrimes 201558Srgrimes#include <bitstring.h> 211558Srgrimes#include <ctype.h> 221558Srgrimes#include <signal.h> 231558Srgrimes#include <stdio.h> 241558Srgrimes#include <stdlib.h> 251558Srgrimes#include <string.h> 261558Srgrimes#ifdef HAVE_TERM_H 271558Srgrimes#include <term.h> 281558Srgrimes#endif 291558Srgrimes#include <termios.h> 301558Srgrimes#include <unistd.h> 311558Srgrimes 321558Srgrimes#include "../common/common.h" 331558Srgrimes#include "../vi/vi.h" 341558Srgrimes#include "cl.h" 351558Srgrimes 361558Srgrimesstatic void cl_rdiv __P((SCR *)); 371558Srgrimes 381558Srgrimesstatic int 391558Srgrimesaddstr4(SCR *sp, void *str, size_t len, int wide) 401558Srgrimes{ 411558Srgrimes CL_PRIVATE *clp; 421558Srgrimes WINDOW *win; 431558Srgrimes size_t y, x; 441558Srgrimes int iv; 451558Srgrimes 461558Srgrimes clp = CLP(sp); 471558Srgrimes win = CLSP(sp) ? CLSP(sp) : stdscr; 481558Srgrimes 491558Srgrimes /* 501558Srgrimes * If ex isn't in control, it's the last line of the screen and 511558Srgrimes * it's a split screen, use inverse video. 521558Srgrimes */ 531558Srgrimes iv = 0; 541558Srgrimes getyx(win, y, x); 551558Srgrimes if (!F_ISSET(sp, SC_SCR_EXWROTE) && 561558Srgrimes y == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) { 571558Srgrimes iv = 1; 581558Srgrimes (void)wstandout(win); 591558Srgrimes } 601558Srgrimes 611558Srgrimes#ifdef USE_WIDECHAR 621558Srgrimes if (wide) { 631558Srgrimes if (waddnwstr(win, str, len) == ERR) 641558Srgrimes return (1); 651558Srgrimes } else 661558Srgrimes#endif 671558Srgrimes if (waddnstr(win, str, len) == ERR) 681558Srgrimes return (1); 691558Srgrimes 701558Srgrimes if (iv) 711558Srgrimes (void)wstandend(win); 721558Srgrimes return (0); 731558Srgrimes} 741558Srgrimes 751558Srgrimes/* 761558Srgrimes * cl_waddstr -- 771558Srgrimes * Add len bytes from the string at the cursor, advancing the cursor. 781558Srgrimes * 791558Srgrimes * PUBLIC: int cl_waddstr __P((SCR *, const CHAR_T *, size_t)); 801558Srgrimes */ 811558Srgrimesint 821558Srgrimescl_waddstr(SCR *sp, const CHAR_T *str, size_t len) 831558Srgrimes{ 841558Srgrimes return addstr4(sp, (void *)str, len, 1); 851558Srgrimes} 861558Srgrimes 871558Srgrimes/* 881558Srgrimes * cl_addstr -- 891558Srgrimes * Add len bytes from the string at the cursor, advancing the cursor. 901558Srgrimes * 911558Srgrimes * PUBLIC: int cl_addstr __P((SCR *, const char *, size_t)); 921558Srgrimes */ 931558Srgrimesint 941558Srgrimescl_addstr(SCR *sp, const char *str, size_t len) 951558Srgrimes{ 961558Srgrimes return addstr4(sp, (void *)str, len, 0); 971558Srgrimes} 981558Srgrimes 991558Srgrimes/* 1001558Srgrimes * cl_attr -- 1011558Srgrimes * Toggle a screen attribute on/off. 1021558Srgrimes * 1031558Srgrimes * PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int)); 1041558Srgrimes */ 1051558Srgrimesint 1061558Srgrimescl_attr(SCR *sp, scr_attr_t attribute, int on) 1071558Srgrimes{ 1081558Srgrimes CL_PRIVATE *clp; 1091558Srgrimes WINDOW *win; 1101558Srgrimes 1111558Srgrimes clp = CLP(sp); 1121558Srgrimes win = CLSP(sp) ? CLSP(sp) : stdscr; 1131558Srgrimes 1141558Srgrimes switch (attribute) { 1151558Srgrimes case SA_ALTERNATE: 1161558Srgrimes /* 1171558Srgrimes * !!! 1181558Srgrimes * There's a major layering violation here. The problem is that the 1191558Srgrimes * X11 xterm screen has what's known as an "alternate" screen. Some 1201558Srgrimes * xterm termcap/terminfo entries include sequences to switch to/from 1211558Srgrimes * that alternate screen as part of the ti/te (smcup/rmcup) strings. 1221558Srgrimes * Vi runs in the alternate screen, so that you are returned to the 1231558Srgrimes * same screen contents on exit from vi that you had when you entered 1241558Srgrimes * vi. Further, when you run :shell, or :!date or similar ex commands, 1251558Srgrimes * you also see the original screen contents. This wasn't deliberate 1261558Srgrimes * on vi's part, it's just that it historically sent terminal init/end 1271558Srgrimes * sequences at those times, and the addition of the alternate screen 1281558Srgrimes * sequences to the strings changed the behavior of vi. The problem 1291558Srgrimes * caused by this is that we don't want to switch back to the alternate 1301558Srgrimes * screen while getting a new command from the user, when the user is 1311558Srgrimes * continuing to enter ex commands, e.g.: 1321558Srgrimes * 1331558Srgrimes * :!date <<< switch to original screen 1341558Srgrimes * [Hit return to continue] <<< prompt user to continue 1351558Srgrimes * :command <<< get command from user 1361558Srgrimes * 1371558Srgrimes * Note that the :command input is a true vi input mode, e.g., input 1381558Srgrimes * maps and abbreviations are being done. So, we need to be able to 1391558Srgrimes * switch back into the vi screen mode, without flashing the screen. 1401558Srgrimes * 1411558Srgrimes * To make matters worse, the curses initscr() and endwin() calls will 1421558Srgrimes * do this automatically -- so, this attribute isn't as controlled by 1431558Srgrimes * the higher level screen as closely as one might like. 1441558Srgrimes */ 1451558Srgrimes if (on) { 1461558Srgrimes if (clp->ti_te != TI_SENT) { 1471558Srgrimes clp->ti_te = TI_SENT; 1481558Srgrimes if (clp->smcup == NULL) 1491558Srgrimes (void)cl_getcap(sp, "smcup", &clp->smcup); 1501558Srgrimes if (clp->smcup != NULL) 1511558Srgrimes (void)tputs(clp->smcup, 1, cl_putchar); 1521558Srgrimes } 1531558Srgrimes } else 1541558Srgrimes if (clp->ti_te != TE_SENT) { 1551558Srgrimes clp->ti_te = TE_SENT; 1561558Srgrimes if (clp->rmcup == NULL) 1571558Srgrimes (void)cl_getcap(sp, "rmcup", &clp->rmcup); 1581558Srgrimes if (clp->rmcup != NULL) 1591558Srgrimes (void)tputs(clp->rmcup, 1, cl_putchar); 1601558Srgrimes (void)fflush(stdout); 1611558Srgrimes } 1621558Srgrimes (void)fflush(stdout); 1631558Srgrimes break; 1641558Srgrimes case SA_INVERSE: 1651558Srgrimes if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) { 1661558Srgrimes if (clp->smso == NULL) 1671558Srgrimes return (1); 1681558Srgrimes if (on) 1691558Srgrimes (void)tputs(clp->smso, 1, cl_putchar); 1701558Srgrimes else 1711558Srgrimes (void)tputs(clp->rmso, 1, cl_putchar); 1721558Srgrimes (void)fflush(stdout); 1731558Srgrimes } else { 1741558Srgrimes if (on) 1751558Srgrimes (void)wstandout(win); 1761558Srgrimes else 1771558Srgrimes (void)wstandend(win); 1781558Srgrimes } 1791558Srgrimes break; 1801558Srgrimes default: 1811558Srgrimes abort(); 1821558Srgrimes } 1831558Srgrimes return (0); 1841558Srgrimes} 1851558Srgrimes 1861558Srgrimes/* 1871558Srgrimes * cl_baud -- 1881558Srgrimes * Return the baud rate. 1891558Srgrimes * 1901558Srgrimes * PUBLIC: int cl_baud __P((SCR *, u_long *)); 1911558Srgrimes */ 1921558Srgrimesint 1931558Srgrimescl_baud(SCR *sp, u_long *ratep) 1941558Srgrimes{ 1951558Srgrimes CL_PRIVATE *clp; 1961558Srgrimes 1971558Srgrimes /* 1981558Srgrimes * XXX 1991558Srgrimes * There's no portable way to get a "baud rate" -- cfgetospeed(3) 2001558Srgrimes * returns the value associated with some #define, which we may 2011558Srgrimes * never have heard of, or which may be a purely local speed. Vi 2021558Srgrimes * only cares if it's SLOW (w300), slow (w1200) or fast (w9600). 2031558Srgrimes * Try and detect the slow ones, and default to fast. 2041558Srgrimes */ 2051558Srgrimes clp = CLP(sp); 2061558Srgrimes switch (cfgetospeed(&clp->orig)) { 2071558Srgrimes case B50: 2081558Srgrimes case B75: 2091558Srgrimes case B110: 2101558Srgrimes case B134: 2111558Srgrimes case B150: 2121558Srgrimes case B200: 2131558Srgrimes case B300: 2141558Srgrimes case B600: 2151558Srgrimes *ratep = 600; 2161558Srgrimes break; 2171558Srgrimes case B1200: 2181558Srgrimes *ratep = 1200; 2191558Srgrimes break; 2201558Srgrimes default: 2211558Srgrimes *ratep = 9600; 2221558Srgrimes break; 2231558Srgrimes } 2241558Srgrimes return (0); 2251558Srgrimes} 2261558Srgrimes 2271558Srgrimes/* 2281558Srgrimes * cl_bell -- 2291558Srgrimes * Ring the bell/flash the screen. 2301558Srgrimes * 2311558Srgrimes * PUBLIC: int cl_bell __P((SCR *)); 2321558Srgrimes */ 2331558Srgrimesint 2341558Srgrimescl_bell(SCR *sp) 2351558Srgrimes{ 2361558Srgrimes if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE | SC_SCR_EX)) 2371558Srgrimes (void)write(STDOUT_FILENO, "\07", 1); /* \a */ 2381558Srgrimes else { 2391558Srgrimes /* 2401558Srgrimes * Vi has an edit option which determines if the terminal 2411558Srgrimes * should be beeped or the screen flashed. 2421558Srgrimes */ 2431558Srgrimes if (O_ISSET(sp, O_FLASH)) 2441558Srgrimes (void)flash(); 2451558Srgrimes else 2461558Srgrimes (void)beep(); 2471558Srgrimes } 2481558Srgrimes return (0); 2491558Srgrimes} 2501558Srgrimes 2511558Srgrimes/* 2521558Srgrimes * cl_clrtoeol -- 2531558Srgrimes * Clear from the current cursor to the end of the line. 2541558Srgrimes * 2551558Srgrimes * PUBLIC: int cl_clrtoeol __P((SCR *)); 2561558Srgrimes */ 2571558Srgrimesint 2581558Srgrimescl_clrtoeol(SCR *sp) 2591558Srgrimes{ 2601558Srgrimes WINDOW *win; 2611558Srgrimes#if 0 2621558Srgrimes size_t spcnt, y, x; 2631558Srgrimes#endif 2641558Srgrimes 2651558Srgrimes win = CLSP(sp) ? CLSP(sp) : stdscr; 2661558Srgrimes 2671558Srgrimes#if 0 2681558Srgrimes if (IS_VSPLIT(sp)) { 2691558Srgrimes /* The cursor must be returned to its original position. */ 2701558Srgrimes getyx(win, y, x); 2711558Srgrimes for (spcnt = (sp->coff + sp->cols) - x; spcnt > 0; --spcnt) 2721558Srgrimes (void)waddch(win, ' '); 2731558Srgrimes (void)wmove(win, y, x); 2741558Srgrimes return (0); 2751558Srgrimes } else 2761558Srgrimes#endif 2771558Srgrimes return (wclrtoeol(win) == ERR); 2781558Srgrimes} 2791558Srgrimes 2801558Srgrimes/* 2811558Srgrimes * cl_cursor -- 2821558Srgrimes * Return the current cursor position. 2831558Srgrimes * 2841558Srgrimes * PUBLIC: int cl_cursor __P((SCR *, size_t *, size_t *)); 285 */ 286int 287cl_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 */ 312int 313cl_deleteln(SCR *sp) 314{ 315 CL_PRIVATE *clp; 316 WINDOW *win; 317 size_t y, x; 318 319 clp = CLP(sp); 320 win = CLSP(sp) ? CLSP(sp) : stdscr; 321 322 /* 323 * This clause is required because the curses screen uses reverse 324 * video to delimit split screens. If the screen does not do this, 325 * this code won't be necessary. 326 * 327 * If the bottom line was in reverse video, rewrite it in normal 328 * video before it's scrolled. 329 */ 330 if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) { 331 getyx(win, y, x); 332 mvwchgat(win, RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL); 333 (void)wmove(win, y, x); 334 } 335 336 /* 337 * The bottom line is expected to be blank after this operation, 338 * and other screens must support that semantic. 339 */ 340 return (wdeleteln(win) == ERR); 341} 342 343/* 344 * cl_discard -- 345 * Discard a screen. 346 * 347 * PUBLIC: int cl_discard __P((SCR *, SCR **)); 348 */ 349int 350cl_discard(SCR *discardp, SCR **acquirep) 351{ 352 CL_PRIVATE *clp; 353 SCR* tsp; 354 355 if (discardp) { 356 clp = CLP(discardp); 357 F_SET(clp, CL_LAYOUT); 358 359 if (CLSP(discardp)) { 360 delwin(CLSP(discardp)); 361 discardp->cl_private = NULL; 362 } 363 } 364 365 /* no screens got a piece; we're done */ 366 if (!acquirep) 367 return 0; 368 369 for (; (tsp = *acquirep) != NULL; ++acquirep) { 370 clp = CLP(tsp); 371 F_SET(clp, CL_LAYOUT); 372 373 if (CLSP(tsp)) 374 delwin(CLSP(tsp)); 375 tsp->cl_private = subwin(stdscr, tsp->rows, tsp->cols, 376 tsp->roff, tsp->coff); 377 } 378 379 /* discardp is going away, acquirep is taking up its space. */ 380 return (0); 381} 382 383/* 384 * cl_ex_adjust -- 385 * Adjust the screen for ex. This routine is purely for standalone 386 * ex programs. All special purpose, all special case. 387 * 388 * PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t)); 389 */ 390int 391cl_ex_adjust(SCR *sp, exadj_t action) 392{ 393 CL_PRIVATE *clp; 394 int cnt; 395 396 clp = CLP(sp); 397 switch (action) { 398 case EX_TERM_SCROLL: 399 /* Move the cursor up one line if that's possible. */ 400 if (clp->cuu1 != NULL) 401 (void)tputs(clp->cuu1, 1, cl_putchar); 402 else if (clp->cup != NULL) 403 (void)tputs(tgoto(clp->cup, 404 0, LINES - 2), 1, cl_putchar); 405 else 406 return (0); 407 /* FALLTHROUGH */ 408 case EX_TERM_CE: 409 /* Clear the line. */ 410 if (clp->el != NULL) { 411 (void)putchar('\r'); 412 (void)tputs(clp->el, 1, cl_putchar); 413 } else { 414 /* 415 * Historically, ex didn't erase the line, so, if the 416 * displayed line was only a single glyph, and <eof> 417 * was more than one glyph, the output would not fully 418 * overwrite the user's input. To fix this, output 419 * the maxiumum character number of spaces. Note, 420 * this won't help if the user entered extra prompt 421 * or <blank> characters before the command character. 422 * We'd have to do a lot of work to make that work, and 423 * it's almost certainly not worth the effort. 424 */ 425 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) 426 (void)putchar('\b'); 427 for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) 428 (void)putchar(' '); 429 (void)putchar('\r'); 430 (void)fflush(stdout); 431 } 432 break; 433 default: 434 abort(); 435 } 436 return (0); 437} 438 439/* 440 * cl_insertln -- 441 * Push down the current line, discarding the bottom line. 442 * 443 * PUBLIC: int cl_insertln __P((SCR *)); 444 */ 445int 446cl_insertln(SCR *sp) 447{ 448 WINDOW *win; 449 win = CLSP(sp) ? CLSP(sp) : stdscr; 450 /* 451 * The current line is expected to be blank after this operation, 452 * and the screen must support that semantic. 453 */ 454 return (winsertln(win) == ERR); 455} 456 457/* 458 * cl_keyval -- 459 * Return the value for a special key. 460 * 461 * PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *)); 462 */ 463int 464cl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep) 465{ 466 CL_PRIVATE *clp; 467 468 /* 469 * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990, 470 * VWERASE is a 4BSD extension. 471 */ 472 clp = CLP(sp); 473 switch (val) { 474 case KEY_VEOF: 475 *dnep = (*chp = clp->orig.c_cc[VEOF]) == _POSIX_VDISABLE; 476 break; 477 case KEY_VERASE: 478 *dnep = (*chp = clp->orig.c_cc[VERASE]) == _POSIX_VDISABLE; 479 break; 480 case KEY_VKILL: 481 *dnep = (*chp = clp->orig.c_cc[VKILL]) == _POSIX_VDISABLE; 482 break; 483#ifdef VWERASE 484 case KEY_VWERASE: 485 *dnep = (*chp = clp->orig.c_cc[VWERASE]) == _POSIX_VDISABLE; 486 break; 487#endif 488 default: 489 *dnep = 1; 490 break; 491 } 492 return (0); 493} 494 495/* 496 * cl_move -- 497 * Move the cursor. 498 * 499 * PUBLIC: int cl_move __P((SCR *, size_t, size_t)); 500 */ 501int 502cl_move(SCR *sp, size_t lno, size_t cno) 503{ 504 WINDOW *win; 505 win = CLSP(sp) ? CLSP(sp) : stdscr; 506 /* See the comment in cl_cursor. */ 507 if (wmove(win, RLNO(sp, lno), RCNO(sp, cno)) == ERR) { 508 msgq(sp, M_ERR, "Error: move: l(%zu + %zu) c(%zu + %zu)", 509 lno, sp->roff, cno, sp->coff); 510 return (1); 511 } 512 return (0); 513} 514 515/* 516 * cl_refresh -- 517 * Refresh the screen. 518 * 519 * PUBLIC: int cl_refresh __P((SCR *, int)); 520 */ 521int 522cl_refresh(SCR *sp, int repaint) 523{ 524 GS *gp; 525 CL_PRIVATE *clp; 526 WINDOW *win; 527 SCR *psp, *tsp; 528 size_t y, x; 529 530 gp = sp->gp; 531 clp = CLP(sp); 532 win = CLSP(sp) ? CLSP(sp) : stdscr; 533 534 /* 535 * If we received a killer signal, we're done, there's no point 536 * in refreshing the screen. 537 */ 538 if (clp->killersig) 539 return (0); 540 541 /* 542 * If repaint is set, the editor is telling us that we don't know 543 * what's on the screen, so we have to repaint from scratch. 544 * 545 * If repaint set or the screen layout changed, we need to redraw 546 * any lines separating vertically split screens. If the horizontal 547 * offsets are the same, then the split was vertical, and need to 548 * draw a dividing line. 549 */ 550 if (repaint || F_ISSET(clp, CL_LAYOUT)) { 551 getyx(stdscr, y, x); 552 for (psp = sp; psp != NULL; psp = TAILQ_NEXT(psp, q)) 553 for (tsp = TAILQ_NEXT(psp, q); tsp != NULL; 554 tsp = TAILQ_NEXT(tsp, q)) 555 if (psp->roff == tsp->roff) { 556 if (psp->coff + psp->cols + 1 == tsp->coff) 557 cl_rdiv(psp); 558 else 559 if (tsp->coff + tsp->cols + 1 == psp->coff) 560 cl_rdiv(tsp); 561 } 562 (void)wmove(stdscr, y, x); 563 F_CLR(clp, CL_LAYOUT); 564 } 565 566 /* 567 * In the curses library, doing wrefresh(curscr) is okay, but the 568 * screen flashes when we then apply the refresh() to bring it up 569 * to date. So, use clearok(). 570 */ 571 if (repaint) 572 clearok(curscr, 1); 573 /* 574 * Only do an actual refresh, when this is the focus window, 575 * i.e. the one holding the cursor. This assumes that refresh 576 * is called for that window after refreshing the others. 577 * This prevents the cursor being drawn in the other windows. 578 */ 579 return (wnoutrefresh(stdscr) == ERR || 580 wnoutrefresh(win) == ERR || 581 (sp == clp->focus && doupdate() == ERR)); 582} 583 584/* 585 * cl_rdiv -- 586 * Draw a dividing line between two vertically split screens. 587 */ 588static void 589cl_rdiv(SCR *sp) 590{ 591#ifdef __NetBSD__ 592 mvvline(sp->roff, sp->cols + sp->coff, '|', sp->rows); 593#else 594 mvvline(sp->roff, sp->cols + sp->coff, ACS_VLINE, sp->rows); 595#endif 596} 597 598/* 599 * cl_rename -- 600 * Rename the file. 601 * 602 * PUBLIC: int cl_rename __P((SCR *, char *, int)); 603 */ 604int 605cl_rename(SCR *sp, char *name, int on) 606{ 607 GS *gp; 608 CL_PRIVATE *clp; 609 FILE *pfp; 610 char buf[256], *s, *e; 611 char * wid; 612 char cmd[64]; 613 614 gp = sp->gp; 615 clp = CLP(sp); 616 617 /* 618 * XXX 619 * We can only rename windows for xterm. 620 */ 621 if (on) { 622 clp->focus = sp; 623 if (!F_ISSET(clp, CL_RENAME_OK) || 624 strncmp(OG_STR(gp, GO_TERM), "xterm", 5)) 625 return (0); 626 627 if (clp->oname == NULL && (wid = getenv("WINDOWID"))) { 628 snprintf(cmd, sizeof(cmd), "xprop -id %s WM_NAME", wid); 629 if ((pfp = popen(cmd, "r")) == NULL) 630 goto rename; 631 if (fgets(buf, sizeof(buf), pfp) == NULL) { 632 pclose(pfp); 633 goto rename; 634 } 635 pclose(pfp); 636 if ((s = strchr(buf, '"')) != NULL && 637 (e = strrchr(buf, '"')) != NULL) 638 clp->oname = strndup(s + 1, e - s - 1); 639 } 640 641rename: cl_setname(gp, name); 642 643 F_SET(clp, CL_RENAME); 644 } else 645 if (F_ISSET(clp, CL_RENAME)) { 646 cl_setname(gp, clp->oname); 647 648 F_CLR(clp, CL_RENAME); 649 } 650 return (0); 651} 652 653/* 654 * cl_setname -- 655 * Set a X11 icon/window name. 656 * 657 * PUBLIC: void cl_setname __P((GS *, char *)); 658 */ 659void 660cl_setname(GS *gp, char *name) 661{ 662/* X11 xterm escape sequence to rename the icon/window. */ 663#define XTERM_RENAME "\033]0;%s\007" 664 665 (void)printf(XTERM_RENAME, name == NULL ? OG_STR(gp, GO_TERM) : name); 666 (void)fflush(stdout); 667#undef XTERM_RENAME 668} 669 670/* 671 * cl_split -- 672 * Split a screen. 673 * 674 * PUBLIC: int cl_split __P((SCR *, SCR *)); 675 */ 676int 677cl_split(SCR *origp, SCR *newp) 678{ 679 CL_PRIVATE *clp; 680 681 clp = CLP(origp); 682 F_SET(clp, CL_LAYOUT); 683 684 if (CLSP(origp)) 685 delwin(CLSP(origp)); 686 687 origp->cl_private = subwin(stdscr, origp->rows, origp->cols, 688 origp->roff, origp->coff); 689 newp->cl_private = subwin(stdscr, newp->rows, newp->cols, 690 newp->roff, newp->coff); 691 692 /* origp is the original screen, giving up space to newp. */ 693 return (0); 694} 695 696/* 697 * cl_suspend -- 698 * Suspend a screen. 699 * 700 * PUBLIC: int cl_suspend __P((SCR *, int *)); 701 */ 702int 703cl_suspend(SCR *sp, int *allowedp) 704{ 705 struct termios t; 706 CL_PRIVATE *clp; 707 WINDOW *win; 708 GS *gp; 709 size_t y, x; 710 int changed; 711 712 gp = sp->gp; 713 clp = CLP(sp); 714 win = CLSP(sp) ? CLSP(sp) : stdscr; 715 *allowedp = 1; 716 717 /* 718 * The ex implementation of this function isn't needed by screens not 719 * supporting ex commands that require full terminal canonical mode 720 * (e.g. :suspend). 721 * 722 * The vi implementation of this function isn't needed by screens not 723 * supporting vi process suspension, i.e. any screen that isn't backed 724 * by a UNIX shell. 725 * 726 * Setting allowedp to 0 will cause the editor to reject the command. 727 */ 728 if (F_ISSET(sp, SC_EX)) { 729 /* Save the terminal settings, and restore the original ones. */ 730 if (F_ISSET(clp, CL_STDIN_TTY)) { 731 (void)tcgetattr(STDIN_FILENO, &t); 732 (void)tcsetattr(STDIN_FILENO, 733 TCSASOFT | TCSADRAIN, &clp->orig); 734 } 735 736 /* Stop the process group. */ 737 (void)kill(0, SIGTSTP); 738 739 /* Time passes ... */ 740 741 /* Restore terminal settings. */ 742 if (F_ISSET(clp, CL_STDIN_TTY)) 743 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); 744 return (0); 745 } 746 747 /* 748 * Move to the lower left-hand corner of the screen. 749 * 750 * XXX 751 * Not sure this is necessary in System V implementations, but it 752 * shouldn't hurt. 753 */ 754 getyx(win, y, x); 755 (void)wmove(win, LINES - 1, 0); 756 (void)wrefresh(win); 757 758 /* 759 * Temporarily end the screen. System V introduced a semantic where 760 * endwin() could be restarted. We use it because restarting curses 761 * from scratch often fails in System V. 4BSD curses didn't support 762 * restarting after endwin(), so we have to do what clean up we can 763 * without calling it. 764 */ 765 /* Save the terminal settings. */ 766 (void)tcgetattr(STDIN_FILENO, &t); 767 768 /* Restore the cursor keys to normal mode. */ 769 (void)keypad(stdscr, FALSE); 770 771 /* Restore the window name. */ 772 (void)cl_rename(sp, NULL, 0); 773 774 (void)endwin(); 775 776 /* 777 * XXX 778 * Restore the original terminal settings. This is bad -- the 779 * reset can cause character loss from the tty queue. However, 780 * we can't call endwin() in BSD curses implementations, and too 781 * many System V curses implementations don't get it right. 782 */ 783 (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig); 784 785 /* Stop the process group. */ 786 (void)kill(0, SIGTSTP); 787 788 /* Time passes ... */ 789 790 /* 791 * If we received a killer signal, we're done. Leave everything 792 * unchanged. In addition, the terminal has already been reset 793 * correctly, so leave it alone. 794 */ 795 if (clp->killersig) { 796 F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT); 797 return (0); 798 } 799 800 /* Restore terminal settings. */ 801 wrefresh(win); /* Needed on SunOs/Solaris ? */ 802 if (F_ISSET(clp, CL_STDIN_TTY)) 803 (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); 804 805 /* Set the window name. */ 806 (void)cl_rename(sp, sp->frp->name, 1); 807 808 /* Put the cursor keys into application mode. */ 809 (void)keypad(stdscr, TRUE); 810 811 /* Refresh and repaint the screen. */ 812 (void)wmove(win, y, x); 813 (void)cl_refresh(sp, 1); 814 815 /* If the screen changed size, set the SIGWINCH bit. */ 816 if (cl_ssize(sp, 1, NULL, NULL, &changed)) 817 return (1); 818 if (changed) 819 F_SET(CLP(sp), CL_SIGWINCH); 820 821 return (0); 822} 823 824/* 825 * cl_usage -- 826 * Print out the curses usage messages. 827 * 828 * PUBLIC: void cl_usage __P((void)); 829 */ 830void 831cl_usage(void) 832{ 833#define USAGE "\ 834usage: ex [-eFRrSsv] [-c command] [-t tag] [-w size] [file ...]\n\ 835usage: vi [-eFlRrSv] [-c command] [-t tag] [-w size] [file ...]\n" 836 (void)fprintf(stderr, "%s", USAGE); 837#undef USAGE 838} 839 840#ifdef DEBUG 841/* 842 * gdbrefresh -- 843 * Stub routine so can flush out curses screen changes using gdb. 844 */ 845static int 846 __attribute__((unused)) 847gdbrefresh(void) 848{ 849 refresh(); 850 return (0); /* XXX Convince gdb to run it. */ 851} 852#endif 853