119304Speter/*- 219304Speter * Copyright (c) 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: cl_funcs.c,v 10.74 2012/10/11 10:30:16 zy Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/types.h> 1719304Speter#include <sys/queue.h> 1819304Speter#include <sys/time.h> 1919304Speter 2019304Speter#include <bitstring.h> 2119304Speter#include <ctype.h> 2219304Speter#include <signal.h> 2319304Speter#include <stdio.h> 2419304Speter#include <stdlib.h> 2519304Speter#include <string.h> 26254225Speter#ifdef HAVE_TERM_H 27254225Speter#include <term.h> 28254225Speter#endif 2919304Speter#include <termios.h> 3019304Speter#include <unistd.h> 3119304Speter 3219304Speter#include "../common/common.h" 3319304Speter#include "../vi/vi.h" 3419304Speter#include "cl.h" 3519304Speter 36254225Speterstatic void cl_rdiv __P((SCR *)); 37254225Speter 38254225Speterstatic int 39254225Speteraddstr4(SCR *sp, void *str, size_t len, int wide) 4019304Speter{ 4119304Speter CL_PRIVATE *clp; 42254225Speter WINDOW *win; 43254225Speter size_t y, x; 4419304Speter int iv; 4519304Speter 4619304Speter clp = CLP(sp); 47254225Speter win = CLSP(sp) ? CLSP(sp) : stdscr; 4819304Speter 4919304Speter /* 5019304Speter * If ex isn't in control, it's the last line of the screen and 5119304Speter * it's a split screen, use inverse video. 5219304Speter */ 5319304Speter iv = 0; 54254225Speter getyx(win, y, x); 5519304Speter if (!F_ISSET(sp, SC_SCR_EXWROTE) && 56254225Speter y == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) { 5719304Speter iv = 1; 58254225Speter (void)wstandout(win); 5919304Speter } 6019304Speter 61254225Speter#ifdef USE_WIDECHAR 62254225Speter if (wide) { 63254225Speter if (waddnwstr(win, str, len) == ERR) 6419304Speter return (1); 65254225Speter } else 66254225Speter#endif 67254225Speter if (waddnstr(win, str, len) == ERR) 68254225Speter return (1); 6919304Speter 7019304Speter if (iv) 71254225Speter (void)wstandend(win); 7219304Speter return (0); 7319304Speter} 7419304Speter 7519304Speter/* 76254225Speter * cl_waddstr -- 77254225Speter * Add len bytes from the string at the cursor, advancing the cursor. 78254225Speter * 79254225Speter * PUBLIC: int cl_waddstr __P((SCR *, const CHAR_T *, size_t)); 80254225Speter */ 81254225Speterint 82254225Spetercl_waddstr(SCR *sp, const CHAR_T *str, size_t len) 83254225Speter{ 84254225Speter return addstr4(sp, (void *)str, len, 1); 85254225Speter} 86254225Speter 87254225Speter/* 88254225Speter * cl_addstr -- 89254225Speter * Add len bytes from the string at the cursor, advancing the cursor. 90254225Speter * 91254225Speter * PUBLIC: int cl_addstr __P((SCR *, const char *, size_t)); 92254225Speter */ 93254225Speterint 94254225Spetercl_addstr(SCR *sp, const char *str, size_t len) 95254225Speter{ 96254225Speter return addstr4(sp, (void *)str, len, 0); 97254225Speter} 98254225Speter 99254225Speter/* 10019304Speter * cl_attr -- 10119304Speter * Toggle a screen attribute on/off. 10219304Speter * 10319304Speter * PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int)); 10419304Speter */ 10519304Speterint 106254225Spetercl_attr(SCR *sp, scr_attr_t attribute, int on) 10719304Speter{ 10819304Speter CL_PRIVATE *clp; 109254225Speter WINDOW *win; 11019304Speter 11119304Speter clp = CLP(sp); 112254225Speter win = CLSP(sp) ? CLSP(sp) : stdscr; 11319304Speter 11419304Speter switch (attribute) { 11519304Speter case SA_ALTERNATE: 11619304Speter /* 11719304Speter * !!! 11819304Speter * There's a major layering violation here. The problem is that the 11919304Speter * X11 xterm screen has what's known as an "alternate" screen. Some 12019304Speter * xterm termcap/terminfo entries include sequences to switch to/from 12119304Speter * that alternate screen as part of the ti/te (smcup/rmcup) strings. 12219304Speter * Vi runs in the alternate screen, so that you are returned to the 12319304Speter * same screen contents on exit from vi that you had when you entered 12419304Speter * vi. Further, when you run :shell, or :!date or similar ex commands, 12519304Speter * you also see the original screen contents. This wasn't deliberate 12619304Speter * on vi's part, it's just that it historically sent terminal init/end 12719304Speter * sequences at those times, and the addition of the alternate screen 12819304Speter * sequences to the strings changed the behavior of vi. The problem 12919304Speter * caused by this is that we don't want to switch back to the alternate 13019304Speter * screen while getting a new command from the user, when the user is 13119304Speter * continuing to enter ex commands, e.g.: 13219304Speter * 13319304Speter * :!date <<< switch to original screen 13419304Speter * [Hit return to continue] <<< prompt user to continue 13519304Speter * :command <<< get command from user 13619304Speter * 13719304Speter * Note that the :command input is a true vi input mode, e.g., input 13819304Speter * maps and abbreviations are being done. So, we need to be able to 13919304Speter * switch back into the vi screen mode, without flashing the screen. 14019304Speter * 14119304Speter * To make matters worse, the curses initscr() and endwin() calls will 14219304Speter * do this automatically -- so, this attribute isn't as controlled by 14319304Speter * the higher level screen as closely as one might like. 14419304Speter */ 14519304Speter if (on) { 14619304Speter if (clp->ti_te != TI_SENT) { 14719304Speter clp->ti_te = TI_SENT; 14819304Speter if (clp->smcup == NULL) 14919304Speter (void)cl_getcap(sp, "smcup", &clp->smcup); 15019304Speter if (clp->smcup != NULL) 15119304Speter (void)tputs(clp->smcup, 1, cl_putchar); 15219304Speter } 15319304Speter } else 15419304Speter if (clp->ti_te != TE_SENT) { 15519304Speter clp->ti_te = TE_SENT; 15619304Speter if (clp->rmcup == NULL) 15719304Speter (void)cl_getcap(sp, "rmcup", &clp->rmcup); 15819304Speter if (clp->rmcup != NULL) 15919304Speter (void)tputs(clp->rmcup, 1, cl_putchar); 16019304Speter (void)fflush(stdout); 16119304Speter } 16219304Speter (void)fflush(stdout); 16319304Speter break; 16419304Speter case SA_INVERSE: 16519304Speter if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) { 16619304Speter if (clp->smso == NULL) 16719304Speter return (1); 16819304Speter if (on) 16919304Speter (void)tputs(clp->smso, 1, cl_putchar); 17019304Speter else 17119304Speter (void)tputs(clp->rmso, 1, cl_putchar); 17219304Speter (void)fflush(stdout); 17319304Speter } else { 17419304Speter if (on) 175254225Speter (void)wstandout(win); 17619304Speter else 177254225Speter (void)wstandend(win); 17819304Speter } 17919304Speter break; 18019304Speter default: 18119304Speter abort(); 18219304Speter } 18319304Speter return (0); 18419304Speter} 18519304Speter 18619304Speter/* 18719304Speter * cl_baud -- 18819304Speter * Return the baud rate. 18919304Speter * 19019304Speter * PUBLIC: int cl_baud __P((SCR *, u_long *)); 19119304Speter */ 19219304Speterint 193254225Spetercl_baud(SCR *sp, u_long *ratep) 19419304Speter{ 19519304Speter CL_PRIVATE *clp; 19619304Speter 19719304Speter /* 19819304Speter * XXX 19919304Speter * There's no portable way to get a "baud rate" -- cfgetospeed(3) 20019304Speter * returns the value associated with some #define, which we may 20119304Speter * never have heard of, or which may be a purely local speed. Vi 20219304Speter * only cares if it's SLOW (w300), slow (w1200) or fast (w9600). 20319304Speter * Try and detect the slow ones, and default to fast. 20419304Speter */ 20519304Speter clp = CLP(sp); 20619304Speter switch (cfgetospeed(&clp->orig)) { 20719304Speter case B50: 20819304Speter case B75: 20919304Speter case B110: 21019304Speter case B134: 21119304Speter case B150: 21219304Speter case B200: 21319304Speter case B300: 21419304Speter case B600: 21519304Speter *ratep = 600; 21619304Speter break; 21719304Speter case B1200: 21819304Speter *ratep = 1200; 21919304Speter break; 22019304Speter default: 22119304Speter *ratep = 9600; 22219304Speter break; 22319304Speter } 22419304Speter return (0); 22519304Speter} 22619304Speter 22719304Speter/* 22819304Speter * cl_bell -- 22919304Speter * Ring the bell/flash the screen. 23019304Speter * 23119304Speter * PUBLIC: int cl_bell __P((SCR *)); 23219304Speter */ 23319304Speterint 234254225Spetercl_bell(SCR *sp) 23519304Speter{ 236254225Speter if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE | SC_SCR_EX)) 23719304Speter (void)write(STDOUT_FILENO, "\07", 1); /* \a */ 23819304Speter else { 23919304Speter /* 24019304Speter * Vi has an edit option which determines if the terminal 24119304Speter * should be beeped or the screen flashed. 24219304Speter */ 24319304Speter if (O_ISSET(sp, O_FLASH)) 24419304Speter (void)flash(); 24519304Speter else 24619304Speter (void)beep(); 24719304Speter } 24819304Speter return (0); 24919304Speter} 25019304Speter 25119304Speter/* 25219304Speter * cl_clrtoeol -- 25319304Speter * Clear from the current cursor to the end of the line. 25419304Speter * 25519304Speter * PUBLIC: int cl_clrtoeol __P((SCR *)); 25619304Speter */ 25719304Speterint 258254225Spetercl_clrtoeol(SCR *sp) 25919304Speter{ 260254225Speter WINDOW *win; 261254225Speter#if 0 262254225Speter size_t spcnt, y, x; 263254225Speter#endif 264254225Speter 265254225Speter win = CLSP(sp) ? CLSP(sp) : stdscr; 266254225Speter 267254225Speter#if 0 268254225Speter if (IS_VSPLIT(sp)) { 269254225Speter /* The cursor must be returned to its original position. */ 270254225Speter getyx(win, y, x); 271254225Speter for (spcnt = (sp->coff + sp->cols) - x; spcnt > 0; --spcnt) 272254225Speter (void)waddch(win, ' '); 273254225Speter (void)wmove(win, y, x); 274254225Speter return (0); 275254225Speter } else 276254225Speter#endif 277254225Speter return (wclrtoeol(win) == ERR); 27819304Speter} 27919304Speter 28019304Speter/* 28119304Speter * cl_cursor -- 28219304Speter * Return the current cursor position. 28319304Speter * 28419304Speter * PUBLIC: int cl_cursor __P((SCR *, size_t *, size_t *)); 28519304Speter */ 28619304Speterint 287254225Spetercl_cursor(SCR *sp, size_t *yp, size_t *xp) 28819304Speter{ 289254225Speter WINDOW *win; 290254225Speter win = CLSP(sp) ? CLSP(sp) : stdscr; 29119304Speter /* 29219304Speter * The curses screen support splits a single underlying curses screen 29319304Speter * into multiple screens to support split screen semantics. For this 29419304Speter * reason the returned value must be adjusted to be relative to the 29519304Speter * current screen, and not absolute. Screens that implement the split 29619304Speter * using physically distinct screens won't need this hack. 29719304Speter */ 298254225Speter getyx(win, *yp, *xp); 299254225Speter /* 300254225Speter *yp -= sp->roff; 301254225Speter *xp -= sp->coff; 302254225Speter */ 30319304Speter return (0); 30419304Speter} 30519304Speter 30619304Speter/* 30719304Speter * cl_deleteln -- 30819304Speter * Delete the current line, scrolling all lines below it. 30919304Speter * 31019304Speter * PUBLIC: int cl_deleteln __P((SCR *)); 31119304Speter */ 31219304Speterint 313254225Spetercl_deleteln(SCR *sp) 31419304Speter{ 31519304Speter CL_PRIVATE *clp; 316254225Speter WINDOW *win; 317254225Speter size_t y, x; 31819304Speter 31919304Speter clp = CLP(sp); 320254225Speter win = CLSP(sp) ? CLSP(sp) : stdscr; 32119304Speter 32219304Speter /* 32319304Speter * This clause is required because the curses screen uses reverse 32419304Speter * video to delimit split screens. If the screen does not do this, 32519304Speter * this code won't be necessary. 32619304Speter * 32719304Speter * If the bottom line was in reverse video, rewrite it in normal 32819304Speter * video before it's scrolled. 32919304Speter */ 33019304Speter if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) { 331254225Speter getyx(win, y, x); 332254225Speter mvwchgat(win, RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL); 333254225Speter (void)wmove(win, y, x); 33419304Speter } 33519304Speter 33619304Speter /* 33719304Speter * The bottom line is expected to be blank after this operation, 33819304Speter * and other screens must support that semantic. 33919304Speter */ 340254225Speter return (wdeleteln(win) == ERR); 34119304Speter} 34219304Speter 34319304Speter/* 344254225Speter * cl_discard -- 345254225Speter * Discard a screen. 346254225Speter * 347254225Speter * PUBLIC: int cl_discard __P((SCR *, SCR **)); 348254225Speter */ 349254225Speterint 350254225Spetercl_discard(SCR *discardp, SCR **acquirep) 351254225Speter{ 352254225Speter CL_PRIVATE *clp; 353254225Speter SCR* tsp; 354254225Speter 355254225Speter if (discardp) { 356254225Speter clp = CLP(discardp); 357254225Speter F_SET(clp, CL_LAYOUT); 358254225Speter 359254225Speter if (CLSP(discardp)) { 360254225Speter delwin(CLSP(discardp)); 361254225Speter discardp->cl_private = NULL; 362254225Speter } 363254225Speter } 364254225Speter 365254225Speter /* no screens got a piece; we're done */ 366254225Speter if (!acquirep) 367254225Speter return 0; 368254225Speter 369254225Speter for (; (tsp = *acquirep) != NULL; ++acquirep) { 370254225Speter clp = CLP(tsp); 371254225Speter F_SET(clp, CL_LAYOUT); 372254225Speter 373254225Speter if (CLSP(tsp)) 374254225Speter delwin(CLSP(tsp)); 375254225Speter tsp->cl_private = subwin(stdscr, tsp->rows, tsp->cols, 376254225Speter tsp->roff, tsp->coff); 377254225Speter } 378254225Speter 379254225Speter /* discardp is going away, acquirep is taking up its space. */ 380254225Speter return (0); 381254225Speter} 382254225Speter 383254225Speter/* 38419304Speter * cl_ex_adjust -- 38519304Speter * Adjust the screen for ex. This routine is purely for standalone 38619304Speter * ex programs. All special purpose, all special case. 38719304Speter * 38819304Speter * PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t)); 38919304Speter */ 39019304Speterint 391254225Spetercl_ex_adjust(SCR *sp, exadj_t action) 39219304Speter{ 39319304Speter CL_PRIVATE *clp; 39419304Speter int cnt; 39519304Speter 39619304Speter clp = CLP(sp); 39719304Speter switch (action) { 39819304Speter case EX_TERM_SCROLL: 39919304Speter /* Move the cursor up one line if that's possible. */ 40019304Speter if (clp->cuu1 != NULL) 40119304Speter (void)tputs(clp->cuu1, 1, cl_putchar); 40219304Speter else if (clp->cup != NULL) 40319304Speter (void)tputs(tgoto(clp->cup, 40419304Speter 0, LINES - 2), 1, cl_putchar); 40519304Speter else 40619304Speter return (0); 40719304Speter /* FALLTHROUGH */ 40819304Speter case EX_TERM_CE: 40919304Speter /* Clear the line. */ 41019304Speter if (clp->el != NULL) { 41119304Speter (void)putchar('\r'); 41219304Speter (void)tputs(clp->el, 1, cl_putchar); 41319304Speter } else { 41419304Speter /* 41519304Speter * Historically, ex didn't erase the line, so, if the 41619304Speter * displayed line was only a single glyph, and <eof> 41719304Speter * was more than one glyph, the output would not fully 41819304Speter * overwrite the user's input. To fix this, output 41919304Speter * the maxiumum character number of spaces. Note, 42019304Speter * this won't help if the user entered extra prompt 42119304Speter * or <blank> characters before the command character. 42219304Speter * We'd have to do a lot of work to make that work, and 42319304Speter * it's almost certainly not worth the effort. 42419304Speter */ 42519304Speter for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) 42619304Speter (void)putchar('\b'); 42719304Speter for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt) 42819304Speter (void)putchar(' '); 42919304Speter (void)putchar('\r'); 43019304Speter (void)fflush(stdout); 43119304Speter } 43219304Speter break; 43319304Speter default: 43419304Speter abort(); 43519304Speter } 43619304Speter return (0); 43719304Speter} 43819304Speter 43919304Speter/* 44019304Speter * cl_insertln -- 44119304Speter * Push down the current line, discarding the bottom line. 44219304Speter * 44319304Speter * PUBLIC: int cl_insertln __P((SCR *)); 44419304Speter */ 44519304Speterint 446254225Spetercl_insertln(SCR *sp) 44719304Speter{ 448254225Speter WINDOW *win; 449254225Speter win = CLSP(sp) ? CLSP(sp) : stdscr; 45019304Speter /* 45119304Speter * The current line is expected to be blank after this operation, 45219304Speter * and the screen must support that semantic. 45319304Speter */ 454254225Speter return (winsertln(win) == ERR); 45519304Speter} 45619304Speter 45719304Speter/* 45819304Speter * cl_keyval -- 45919304Speter * Return the value for a special key. 46019304Speter * 46119304Speter * PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *)); 46219304Speter */ 46319304Speterint 464254225Spetercl_keyval(SCR *sp, scr_keyval_t val, CHAR_T *chp, int *dnep) 46519304Speter{ 46619304Speter CL_PRIVATE *clp; 46719304Speter 46819304Speter /* 46919304Speter * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990, 47019304Speter * VWERASE is a 4BSD extension. 47119304Speter */ 47219304Speter clp = CLP(sp); 47319304Speter switch (val) { 47419304Speter case KEY_VEOF: 47519304Speter *dnep = (*chp = clp->orig.c_cc[VEOF]) == _POSIX_VDISABLE; 47619304Speter break; 47719304Speter case KEY_VERASE: 47819304Speter *dnep = (*chp = clp->orig.c_cc[VERASE]) == _POSIX_VDISABLE; 47919304Speter break; 48019304Speter case KEY_VKILL: 48119304Speter *dnep = (*chp = clp->orig.c_cc[VKILL]) == _POSIX_VDISABLE; 48219304Speter break; 48319304Speter#ifdef VWERASE 48419304Speter case KEY_VWERASE: 48519304Speter *dnep = (*chp = clp->orig.c_cc[VWERASE]) == _POSIX_VDISABLE; 48619304Speter break; 48719304Speter#endif 48819304Speter default: 48919304Speter *dnep = 1; 49019304Speter break; 49119304Speter } 49219304Speter return (0); 49319304Speter} 49419304Speter 49519304Speter/* 49619304Speter * cl_move -- 49719304Speter * Move the cursor. 49819304Speter * 49919304Speter * PUBLIC: int cl_move __P((SCR *, size_t, size_t)); 50019304Speter */ 50119304Speterint 502254225Spetercl_move(SCR *sp, size_t lno, size_t cno) 50319304Speter{ 504254225Speter WINDOW *win; 505254225Speter win = CLSP(sp) ? CLSP(sp) : stdscr; 50619304Speter /* See the comment in cl_cursor. */ 507254225Speter if (wmove(win, RLNO(sp, lno), RCNO(sp, cno)) == ERR) { 508254225Speter msgq(sp, M_ERR, "Error: move: l(%zu + %zu) c(%zu + %zu)", 509254225Speter lno, sp->roff, cno, sp->coff); 51019304Speter return (1); 51119304Speter } 51219304Speter return (0); 51319304Speter} 51419304Speter 51519304Speter/* 51619304Speter * cl_refresh -- 51719304Speter * Refresh the screen. 51819304Speter * 51919304Speter * PUBLIC: int cl_refresh __P((SCR *, int)); 52019304Speter */ 52119304Speterint 522254225Spetercl_refresh(SCR *sp, int repaint) 52319304Speter{ 524254225Speter GS *gp; 52519304Speter CL_PRIVATE *clp; 526254225Speter WINDOW *win; 527254225Speter SCR *psp, *tsp; 528254225Speter size_t y, x; 52919304Speter 530254225Speter gp = sp->gp; 53119304Speter clp = CLP(sp); 532254225Speter win = CLSP(sp) ? CLSP(sp) : stdscr; 53319304Speter 53419304Speter /* 53519304Speter * If we received a killer signal, we're done, there's no point 53619304Speter * in refreshing the screen. 53719304Speter */ 53819304Speter if (clp->killersig) 53919304Speter return (0); 54019304Speter 54119304Speter /* 54219304Speter * If repaint is set, the editor is telling us that we don't know 54319304Speter * what's on the screen, so we have to repaint from scratch. 54419304Speter * 545254225Speter * If repaint set or the screen layout changed, we need to redraw 546254225Speter * any lines separating vertically split screens. If the horizontal 547254225Speter * offsets are the same, then the split was vertical, and need to 548254225Speter * draw a dividing line. 549254225Speter */ 550254225Speter if (repaint || F_ISSET(clp, CL_LAYOUT)) { 551254225Speter getyx(stdscr, y, x); 552254225Speter for (psp = sp; psp != NULL; psp = TAILQ_NEXT(psp, q)) 553254225Speter for (tsp = TAILQ_NEXT(psp, q); tsp != NULL; 554254225Speter tsp = TAILQ_NEXT(tsp, q)) 555254225Speter if (psp->roff == tsp->roff) { 556254225Speter if (psp->coff + psp->cols + 1 == tsp->coff) 557254225Speter cl_rdiv(psp); 558254225Speter else 559254225Speter if (tsp->coff + tsp->cols + 1 == psp->coff) 560254225Speter cl_rdiv(tsp); 561254225Speter } 562254225Speter (void)wmove(stdscr, y, x); 563254225Speter F_CLR(clp, CL_LAYOUT); 564254225Speter } 565254225Speter 566254225Speter /* 56719304Speter * In the curses library, doing wrefresh(curscr) is okay, but the 56819304Speter * screen flashes when we then apply the refresh() to bring it up 56919304Speter * to date. So, use clearok(). 57019304Speter */ 57119304Speter if (repaint) 57219304Speter clearok(curscr, 1); 573254225Speter /* 574254225Speter * Only do an actual refresh, when this is the focus window, 575254225Speter * i.e. the one holding the cursor. This assumes that refresh 576254225Speter * is called for that window after refreshing the others. 577254225Speter * This prevents the cursor being drawn in the other windows. 578254225Speter */ 579254225Speter return (wnoutrefresh(stdscr) == ERR || 580254225Speter wnoutrefresh(win) == ERR || 581254225Speter (sp == clp->focus && doupdate() == ERR)); 58219304Speter} 58319304Speter 58419304Speter/* 585254225Speter * cl_rdiv -- 586254225Speter * Draw a dividing line between two vertically split screens. 587254225Speter */ 588254225Speterstatic void 589254225Spetercl_rdiv(SCR *sp) 590254225Speter{ 591254225Speter#ifdef __NetBSD__ 592254225Speter mvvline(sp->roff, sp->cols + sp->coff, '|', sp->rows); 593254225Speter#else 594254225Speter mvvline(sp->roff, sp->cols + sp->coff, ACS_VLINE, sp->rows); 595254225Speter#endif 596254225Speter} 597254225Speter 598254225Speter/* 59919304Speter * cl_rename -- 60019304Speter * Rename the file. 60119304Speter * 60219304Speter * PUBLIC: int cl_rename __P((SCR *, char *, int)); 60319304Speter */ 60419304Speterint 605254225Spetercl_rename(SCR *sp, char *name, int on) 60619304Speter{ 60719304Speter GS *gp; 60819304Speter CL_PRIVATE *clp; 609254225Speter FILE *pfp; 610254225Speter char buf[256], *s, *e; 611254225Speter char * wid; 612254225Speter char cmd[64]; 61319304Speter 61419304Speter gp = sp->gp; 61519304Speter clp = CLP(sp); 61619304Speter 61719304Speter /* 61819304Speter * XXX 61919304Speter * We can only rename windows for xterm. 62019304Speter */ 62119304Speter if (on) { 622254225Speter clp->focus = sp; 623254225Speter if (!F_ISSET(clp, CL_RENAME_OK) || 624254225Speter strncmp(OG_STR(gp, GO_TERM), "xterm", 5)) 625254225Speter return (0); 626254225Speter 627254225Speter if (clp->oname == NULL && (wid = getenv("WINDOWID"))) { 628254225Speter snprintf(cmd, sizeof(cmd), "xprop -id %s WM_NAME", wid); 629254225Speter if ((pfp = popen(cmd, "r")) == NULL) 630254225Speter goto rename; 631254225Speter if (fgets(buf, sizeof(buf), pfp) == NULL) { 632254225Speter pclose(pfp); 633254225Speter goto rename; 634254225Speter } 635254225Speter pclose(pfp); 636254225Speter if ((s = strchr(buf, '"')) != NULL && 637254225Speter (e = strrchr(buf, '"')) != NULL) 638254225Speter clp->oname = strndup(s + 1, e - s - 1); 63919304Speter } 640254225Speter 641254225Speterrename: cl_setname(gp, name); 642254225Speter 643254225Speter F_SET(clp, CL_RENAME); 64419304Speter } else 64519304Speter if (F_ISSET(clp, CL_RENAME)) { 646254225Speter cl_setname(gp, clp->oname); 647254225Speter 64819304Speter F_CLR(clp, CL_RENAME); 64919304Speter } 65019304Speter return (0); 65119304Speter} 65219304Speter 65319304Speter/* 654254225Speter * cl_setname -- 655254225Speter * Set a X11 icon/window name. 656254225Speter * 657254225Speter * PUBLIC: void cl_setname __P((GS *, char *)); 658254225Speter */ 659254225Spetervoid 660254225Spetercl_setname(GS *gp, char *name) 661254225Speter{ 662254225Speter/* X11 xterm escape sequence to rename the icon/window. */ 663254225Speter#define XTERM_RENAME "\033]0;%s\007" 664254225Speter 665254225Speter (void)printf(XTERM_RENAME, name == NULL ? OG_STR(gp, GO_TERM) : name); 666254225Speter (void)fflush(stdout); 667254225Speter#undef XTERM_RENAME 668254225Speter} 669254225Speter 670254225Speter/* 671254225Speter * cl_split -- 672254225Speter * Split a screen. 673254225Speter * 674254225Speter * PUBLIC: int cl_split __P((SCR *, SCR *)); 675254225Speter */ 676254225Speterint 677254225Spetercl_split(SCR *origp, SCR *newp) 678254225Speter{ 679254225Speter CL_PRIVATE *clp; 680254225Speter 681254225Speter clp = CLP(origp); 682254225Speter F_SET(clp, CL_LAYOUT); 683254225Speter 684254225Speter if (CLSP(origp)) 685254225Speter delwin(CLSP(origp)); 686254225Speter 687254225Speter origp->cl_private = subwin(stdscr, origp->rows, origp->cols, 688254225Speter origp->roff, origp->coff); 689254225Speter newp->cl_private = subwin(stdscr, newp->rows, newp->cols, 690254225Speter newp->roff, newp->coff); 691254225Speter 692254225Speter /* origp is the original screen, giving up space to newp. */ 693254225Speter return (0); 694254225Speter} 695254225Speter 696254225Speter/* 69719304Speter * cl_suspend -- 69819304Speter * Suspend a screen. 69919304Speter * 70019304Speter * PUBLIC: int cl_suspend __P((SCR *, int *)); 70119304Speter */ 70219304Speterint 703254225Spetercl_suspend(SCR *sp, int *allowedp) 70419304Speter{ 70519304Speter struct termios t; 70619304Speter CL_PRIVATE *clp; 707254225Speter WINDOW *win; 70819304Speter GS *gp; 709254225Speter size_t y, x; 71019304Speter int changed; 71119304Speter 71219304Speter gp = sp->gp; 71319304Speter clp = CLP(sp); 714254225Speter win = CLSP(sp) ? CLSP(sp) : stdscr; 71519304Speter *allowedp = 1; 71619304Speter 71719304Speter /* 71819304Speter * The ex implementation of this function isn't needed by screens not 71919304Speter * supporting ex commands that require full terminal canonical mode 72019304Speter * (e.g. :suspend). 72119304Speter * 72219304Speter * The vi implementation of this function isn't needed by screens not 72319304Speter * supporting vi process suspension, i.e. any screen that isn't backed 72419304Speter * by a UNIX shell. 72519304Speter * 72619304Speter * Setting allowedp to 0 will cause the editor to reject the command. 72719304Speter */ 72819304Speter if (F_ISSET(sp, SC_EX)) { 72919304Speter /* Save the terminal settings, and restore the original ones. */ 73019304Speter if (F_ISSET(clp, CL_STDIN_TTY)) { 73119304Speter (void)tcgetattr(STDIN_FILENO, &t); 73219304Speter (void)tcsetattr(STDIN_FILENO, 73319304Speter TCSASOFT | TCSADRAIN, &clp->orig); 73419304Speter } 73519304Speter 73619304Speter /* Stop the process group. */ 73719304Speter (void)kill(0, SIGTSTP); 73819304Speter 73919304Speter /* Time passes ... */ 74019304Speter 74119304Speter /* Restore terminal settings. */ 74219304Speter if (F_ISSET(clp, CL_STDIN_TTY)) 74319304Speter (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); 74419304Speter return (0); 74519304Speter } 74619304Speter 74719304Speter /* 74819304Speter * Move to the lower left-hand corner of the screen. 74919304Speter * 75019304Speter * XXX 75119304Speter * Not sure this is necessary in System V implementations, but it 75219304Speter * shouldn't hurt. 75319304Speter */ 754254225Speter getyx(win, y, x); 755254225Speter (void)wmove(win, LINES - 1, 0); 756254225Speter (void)wrefresh(win); 75719304Speter 75819304Speter /* 75919304Speter * Temporarily end the screen. System V introduced a semantic where 76019304Speter * endwin() could be restarted. We use it because restarting curses 76119304Speter * from scratch often fails in System V. 4BSD curses didn't support 76219304Speter * restarting after endwin(), so we have to do what clean up we can 76319304Speter * without calling it. 76419304Speter */ 76519304Speter /* Save the terminal settings. */ 76619304Speter (void)tcgetattr(STDIN_FILENO, &t); 76719304Speter 76819304Speter /* Restore the cursor keys to normal mode. */ 76919304Speter (void)keypad(stdscr, FALSE); 77019304Speter 77119304Speter /* Restore the window name. */ 77219304Speter (void)cl_rename(sp, NULL, 0); 77319304Speter 77419304Speter (void)endwin(); 775254225Speter 77619304Speter /* 77719304Speter * XXX 77819304Speter * Restore the original terminal settings. This is bad -- the 77919304Speter * reset can cause character loss from the tty queue. However, 78019304Speter * we can't call endwin() in BSD curses implementations, and too 78119304Speter * many System V curses implementations don't get it right. 78219304Speter */ 78319304Speter (void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig); 78419304Speter 78519304Speter /* Stop the process group. */ 78619304Speter (void)kill(0, SIGTSTP); 78719304Speter 78819304Speter /* Time passes ... */ 78919304Speter 79019304Speter /* 79119304Speter * If we received a killer signal, we're done. Leave everything 79219304Speter * unchanged. In addition, the terminal has already been reset 79319304Speter * correctly, so leave it alone. 79419304Speter */ 79519304Speter if (clp->killersig) { 79619304Speter F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT); 79719304Speter return (0); 79819304Speter } 79919304Speter 80019304Speter /* Restore terminal settings. */ 801254225Speter wrefresh(win); /* Needed on SunOs/Solaris ? */ 80219304Speter if (F_ISSET(clp, CL_STDIN_TTY)) 80319304Speter (void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t); 80419304Speter 80519304Speter /* Set the window name. */ 80619304Speter (void)cl_rename(sp, sp->frp->name, 1); 80719304Speter 80819304Speter /* Put the cursor keys into application mode. */ 80919304Speter (void)keypad(stdscr, TRUE); 81019304Speter 81119304Speter /* Refresh and repaint the screen. */ 812254225Speter (void)wmove(win, y, x); 81319304Speter (void)cl_refresh(sp, 1); 81419304Speter 81519304Speter /* If the screen changed size, set the SIGWINCH bit. */ 81619304Speter if (cl_ssize(sp, 1, NULL, NULL, &changed)) 81719304Speter return (1); 81819304Speter if (changed) 81919304Speter F_SET(CLP(sp), CL_SIGWINCH); 82019304Speter 82119304Speter return (0); 82219304Speter} 82319304Speter 82419304Speter/* 82519304Speter * cl_usage -- 82619304Speter * Print out the curses usage messages. 82719304Speter * 82819304Speter * PUBLIC: void cl_usage __P((void)); 82919304Speter */ 83019304Spetervoid 831254225Spetercl_usage(void) 83219304Speter{ 83319304Speter#define USAGE "\ 83419304Speterusage: ex [-eFRrSsv] [-c command] [-t tag] [-w size] [file ...]\n\ 83519304Speterusage: vi [-eFlRrSv] [-c command] [-t tag] [-w size] [file ...]\n" 83619304Speter (void)fprintf(stderr, "%s", USAGE); 83719304Speter#undef USAGE 83819304Speter} 83919304Speter 84019304Speter#ifdef DEBUG 84119304Speter/* 84219304Speter * gdbrefresh -- 84319304Speter * Stub routine so can flush out curses screen changes using gdb. 84419304Speter */ 845254225Speterstatic int 846254225Speter __attribute__((unused)) 847254225Spetergdbrefresh(void) 84819304Speter{ 84919304Speter refresh(); 85019304Speter return (0); /* XXX Convince gdb to run it. */ 85119304Speter} 85219304Speter#endif 853