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