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
1319304Speterstatic const char sccsid[] = "@(#)cl_funcs.c	10.50 (Berkeley) 9/24/96";
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 <curses.h>
2319304Speter#include <signal.h>
2419304Speter#include <stdio.h>
2519304Speter#include <stdlib.h>
2619304Speter#include <string.h>
2719304Speter#include <termios.h>
2819304Speter#include <unistd.h>
2919304Speter
3019304Speter#include "../common/common.h"
3119304Speter#include "../vi/vi.h"
3219304Speter#include "cl.h"
3319304Speter
3419304Speter/*
3519304Speter * cl_addstr --
3619304Speter *	Add len bytes from the string at the cursor, advancing the cursor.
3719304Speter *
3819304Speter * PUBLIC: int cl_addstr __P((SCR *, const char *, size_t));
3919304Speter */
4019304Speterint
4119304Spetercl_addstr(sp, str, len)
4219304Speter	SCR *sp;
4319304Speter	const char *str;
4419304Speter	size_t len;
4519304Speter{
4619304Speter	CL_PRIVATE *clp;
4719304Speter	size_t oldy, oldx;
4819304Speter	int iv;
4919304Speter
5019304Speter	clp = CLP(sp);
5119304Speter
5219304Speter	/*
5319304Speter	 * If ex isn't in control, it's the last line of the screen and
5419304Speter	 * it's a split screen, use inverse video.
5519304Speter	 */
5619304Speter	iv = 0;
5719304Speter	getyx(stdscr, oldy, oldx);
5819304Speter	if (!F_ISSET(sp, SC_SCR_EXWROTE) &&
5919304Speter	    oldy == RLNO(sp, LASTLINE(sp)) && IS_SPLIT(sp)) {
6019304Speter		iv = 1;
6119304Speter		(void)standout();
6219304Speter	}
6319304Speter
6419304Speter	if (addnstr(str, len) == ERR)
6519304Speter		return (1);
6619304Speter
6719304Speter	if (iv)
6819304Speter		(void)standend();
6919304Speter	return (0);
7019304Speter}
7119304Speter
7219304Speter/*
7319304Speter * cl_attr --
7419304Speter *	Toggle a screen attribute on/off.
7519304Speter *
7619304Speter * PUBLIC: int cl_attr __P((SCR *, scr_attr_t, int));
7719304Speter */
7819304Speterint
7919304Spetercl_attr(sp, attribute, on)
8019304Speter	SCR *sp;
8119304Speter	scr_attr_t attribute;
8219304Speter	int on;
8319304Speter{
8419304Speter	CL_PRIVATE *clp;
8519304Speter
8619304Speter	clp = CLP(sp);
8719304Speter
8819304Speter	switch (attribute) {
8919304Speter	case SA_ALTERNATE:
9019304Speter	/*
9119304Speter	 * !!!
9219304Speter	 * There's a major layering violation here.  The problem is that the
9319304Speter	 * X11 xterm screen has what's known as an "alternate" screen.  Some
9419304Speter	 * xterm termcap/terminfo entries include sequences to switch to/from
9519304Speter	 * that alternate screen as part of the ti/te (smcup/rmcup) strings.
9619304Speter	 * Vi runs in the alternate screen, so that you are returned to the
9719304Speter	 * same screen contents on exit from vi that you had when you entered
9819304Speter	 * vi.  Further, when you run :shell, or :!date or similar ex commands,
9919304Speter	 * you also see the original screen contents.  This wasn't deliberate
10019304Speter	 * on vi's part, it's just that it historically sent terminal init/end
10119304Speter	 * sequences at those times, and the addition of the alternate screen
10219304Speter	 * sequences to the strings changed the behavior of vi.  The problem
10319304Speter	 * caused by this is that we don't want to switch back to the alternate
10419304Speter	 * screen while getting a new command from the user, when the user is
10519304Speter	 * continuing to enter ex commands, e.g.:
10619304Speter	 *
10719304Speter	 *	:!date				<<< switch to original screen
10819304Speter	 *	[Hit return to continue]	<<< prompt user to continue
10919304Speter	 *	:command			<<< get command from user
11019304Speter	 *
11119304Speter	 * Note that the :command input is a true vi input mode, e.g., input
11219304Speter	 * maps and abbreviations are being done.  So, we need to be able to
11319304Speter	 * switch back into the vi screen mode, without flashing the screen.
11419304Speter	 *
11519304Speter	 * To make matters worse, the curses initscr() and endwin() calls will
11619304Speter	 * do this automatically -- so, this attribute isn't as controlled by
11719304Speter	 * the higher level screen as closely as one might like.
11819304Speter	 */
11919304Speter	if (on) {
12019304Speter		if (clp->ti_te != TI_SENT) {
12119304Speter			clp->ti_te = TI_SENT;
12219304Speter			if (clp->smcup == NULL)
12319304Speter				(void)cl_getcap(sp, "smcup", &clp->smcup);
12419304Speter			if (clp->smcup != NULL)
12519304Speter				(void)tputs(clp->smcup, 1, cl_putchar);
12619304Speter		}
12719304Speter	} else
12819304Speter		if (clp->ti_te != TE_SENT) {
12919304Speter			clp->ti_te = TE_SENT;
13019304Speter			if (clp->rmcup == NULL)
13119304Speter				(void)cl_getcap(sp, "rmcup", &clp->rmcup);
13219304Speter			if (clp->rmcup != NULL)
13319304Speter				(void)tputs(clp->rmcup, 1, cl_putchar);
13419304Speter			(void)fflush(stdout);
13519304Speter		}
13619304Speter		(void)fflush(stdout);
13719304Speter		break;
13819304Speter	case SA_INVERSE:
13919304Speter		if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
14019304Speter			if (clp->smso == NULL)
14119304Speter				return (1);
14219304Speter			if (on)
14319304Speter				(void)tputs(clp->smso, 1, cl_putchar);
14419304Speter			else
14519304Speter				(void)tputs(clp->rmso, 1, cl_putchar);
14619304Speter			(void)fflush(stdout);
14719304Speter		} else {
14819304Speter			if (on)
14919304Speter				(void)standout();
15019304Speter			else
15119304Speter				(void)standend();
15219304Speter		}
15319304Speter		break;
15419304Speter	default:
15519304Speter		abort();
15619304Speter	}
15719304Speter	return (0);
15819304Speter}
15919304Speter
16019304Speter/*
16119304Speter * cl_baud --
16219304Speter *	Return the baud rate.
16319304Speter *
16419304Speter * PUBLIC: int cl_baud __P((SCR *, u_long *));
16519304Speter */
16619304Speterint
16719304Spetercl_baud(sp, ratep)
16819304Speter	SCR *sp;
16919304Speter	u_long *ratep;
17019304Speter{
17119304Speter	CL_PRIVATE *clp;
17219304Speter
17319304Speter	/*
17419304Speter	 * XXX
17519304Speter	 * There's no portable way to get a "baud rate" -- cfgetospeed(3)
17619304Speter	 * returns the value associated with some #define, which we may
17719304Speter	 * never have heard of, or which may be a purely local speed.  Vi
17819304Speter	 * only cares if it's SLOW (w300), slow (w1200) or fast (w9600).
17919304Speter	 * Try and detect the slow ones, and default to fast.
18019304Speter	 */
18119304Speter	clp = CLP(sp);
18219304Speter	switch (cfgetospeed(&clp->orig)) {
18319304Speter	case B50:
18419304Speter	case B75:
18519304Speter	case B110:
18619304Speter	case B134:
18719304Speter	case B150:
18819304Speter	case B200:
18919304Speter	case B300:
19019304Speter	case B600:
19119304Speter		*ratep = 600;
19219304Speter		break;
19319304Speter	case B1200:
19419304Speter		*ratep = 1200;
19519304Speter		break;
19619304Speter	default:
19719304Speter		*ratep = 9600;
19819304Speter		break;
19919304Speter	}
20019304Speter	return (0);
20119304Speter}
20219304Speter
20319304Speter/*
20419304Speter * cl_bell --
20519304Speter *	Ring the bell/flash the screen.
20619304Speter *
20719304Speter * PUBLIC: int cl_bell __P((SCR *));
20819304Speter */
20919304Speterint
21019304Spetercl_bell(sp)
21119304Speter	SCR *sp;
21219304Speter{
21319304Speter	if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE))
21419304Speter		(void)write(STDOUT_FILENO, "\07", 1);		/* \a */
21519304Speter	else {
21619304Speter		/*
21719304Speter		 * Vi has an edit option which determines if the terminal
21819304Speter		 * should be beeped or the screen flashed.
21919304Speter		 */
22019304Speter		if (O_ISSET(sp, O_FLASH))
22119304Speter			(void)flash();
22219304Speter		else
22319304Speter			(void)beep();
22419304Speter	}
22519304Speter	return (0);
22619304Speter}
22719304Speter
22819304Speter/*
22919304Speter * cl_clrtoeol --
23019304Speter *	Clear from the current cursor to the end of the line.
23119304Speter *
23219304Speter * PUBLIC: int cl_clrtoeol __P((SCR *));
23319304Speter */
23419304Speterint
23519304Spetercl_clrtoeol(sp)
23619304Speter	SCR *sp;
23719304Speter{
23819304Speter	return (clrtoeol() == ERR);
23919304Speter}
24019304Speter
24119304Speter/*
24219304Speter * cl_cursor --
24319304Speter *	Return the current cursor position.
24419304Speter *
24519304Speter * PUBLIC: int cl_cursor __P((SCR *, size_t *, size_t *));
24619304Speter */
24719304Speterint
24819304Spetercl_cursor(sp, yp, xp)
24919304Speter	SCR *sp;
25019304Speter	size_t *yp, *xp;
25119304Speter{
25219304Speter	/*
25319304Speter	 * The curses screen support splits a single underlying curses screen
25419304Speter	 * into multiple screens to support split screen semantics.  For this
25519304Speter	 * reason the returned value must be adjusted to be relative to the
25619304Speter	 * current screen, and not absolute.  Screens that implement the split
25719304Speter	 * using physically distinct screens won't need this hack.
25819304Speter	 */
25919304Speter	getyx(stdscr, *yp, *xp);
26019304Speter	*yp -= sp->woff;
26119304Speter	return (0);
26219304Speter}
26319304Speter
26419304Speter/*
26519304Speter * cl_deleteln --
26619304Speter *	Delete the current line, scrolling all lines below it.
26719304Speter *
26819304Speter * PUBLIC: int cl_deleteln __P((SCR *));
26919304Speter */
27019304Speterint
27119304Spetercl_deleteln(sp)
27219304Speter	SCR *sp;
27319304Speter{
27419304Speter	CHAR_T ch;
27519304Speter	CL_PRIVATE *clp;
27619304Speter	size_t col, lno, spcnt, oldy, oldx;
27719304Speter
27819304Speter	clp = CLP(sp);
27919304Speter
28019304Speter	/*
28119304Speter	 * This clause is required because the curses screen uses reverse
28219304Speter	 * video to delimit split screens.  If the screen does not do this,
28319304Speter	 * this code won't be necessary.
28419304Speter	 *
28519304Speter	 * If the bottom line was in reverse video, rewrite it in normal
28619304Speter	 * video before it's scrolled.
28719304Speter	 *
28819304Speter	 * Check for the existence of a chgat function; XSI requires it, but
28919304Speter	 * historic implementations of System V curses don't.   If it's not
29019304Speter	 * a #define, we'll fall back to doing it by hand, which is slow but
29119304Speter	 * acceptable.
29219304Speter	 *
29319304Speter	 * By hand means walking through the line, retrieving and rewriting
29419304Speter	 * each character.  Curses has no EOL marker, so track strings of
29519304Speter	 * spaces, and copy the trailing spaces only if there's a non-space
29619304Speter	 * character following.
29719304Speter	 */
29819304Speter	if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) {
29919304Speter		getyx(stdscr, oldy, oldx);
30019304Speter#ifdef mvchgat
30119304Speter		mvchgat(RLNO(sp, LASTLINE(sp)), 0, -1, A_NORMAL, 0, NULL);
30219304Speter#else
30319304Speter		for (lno = RLNO(sp, LASTLINE(sp)), col = spcnt = 0;;) {
30419304Speter			(void)move(lno, col);
30519304Speter			ch = winch(stdscr);
30619304Speter			if (isblank(ch))
30719304Speter				++spcnt;
30819304Speter			else {
30919304Speter				(void)move(lno, col - spcnt);
31019304Speter				for (; spcnt > 0; --spcnt)
31119304Speter					(void)addch(' ');
31219304Speter				(void)addch(ch);
31319304Speter			}
31419304Speter			if (++col >= sp->cols)
31519304Speter				break;
31619304Speter		}
31719304Speter#endif
31819304Speter		(void)move(oldy, oldx);
31919304Speter	}
32019304Speter
32119304Speter	/*
32219304Speter	 * The bottom line is expected to be blank after this operation,
32319304Speter	 * and other screens must support that semantic.
32419304Speter	 */
32519304Speter	return (deleteln() == ERR);
32619304Speter}
32719304Speter
32819304Speter/*
32919304Speter * cl_ex_adjust --
33019304Speter *	Adjust the screen for ex.  This routine is purely for standalone
33119304Speter *	ex programs.  All special purpose, all special case.
33219304Speter *
33319304Speter * PUBLIC: int cl_ex_adjust __P((SCR *, exadj_t));
33419304Speter */
33519304Speterint
33619304Spetercl_ex_adjust(sp, action)
33719304Speter	SCR *sp;
33819304Speter	exadj_t action;
33919304Speter{
34019304Speter	CL_PRIVATE *clp;
34119304Speter	int cnt;
34219304Speter
34319304Speter	clp = CLP(sp);
34419304Speter	switch (action) {
34519304Speter	case EX_TERM_SCROLL:
34619304Speter		/* Move the cursor up one line if that's possible. */
34719304Speter		if (clp->cuu1 != NULL)
34819304Speter			(void)tputs(clp->cuu1, 1, cl_putchar);
34919304Speter		else if (clp->cup != NULL)
35019304Speter			(void)tputs(tgoto(clp->cup,
35119304Speter			    0, LINES - 2), 1, cl_putchar);
35219304Speter		else
35319304Speter			return (0);
35419304Speter		/* FALLTHROUGH */
35519304Speter	case EX_TERM_CE:
35619304Speter		/* Clear the line. */
35719304Speter		if (clp->el != NULL) {
35819304Speter			(void)putchar('\r');
35919304Speter			(void)tputs(clp->el, 1, cl_putchar);
36019304Speter		} else {
36119304Speter			/*
36219304Speter			 * Historically, ex didn't erase the line, so, if the
36319304Speter			 * displayed line was only a single glyph, and <eof>
36419304Speter			 * was more than one glyph, the output would not fully
36519304Speter			 * overwrite the user's input.  To fix this, output
36619304Speter			 * the maxiumum character number of spaces.  Note,
36719304Speter			 * this won't help if the user entered extra prompt
36819304Speter			 * or <blank> characters before the command character.
36919304Speter			 * We'd have to do a lot of work to make that work, and
37019304Speter			 * it's almost certainly not worth the effort.
37119304Speter			 */
37219304Speter			for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
37319304Speter				(void)putchar('\b');
37419304Speter			for (cnt = 0; cnt < MAX_CHARACTER_COLUMNS; ++cnt)
37519304Speter				(void)putchar(' ');
37619304Speter			(void)putchar('\r');
37719304Speter			(void)fflush(stdout);
37819304Speter		}
37919304Speter		break;
38019304Speter	default:
38119304Speter		abort();
38219304Speter	}
38319304Speter	return (0);
38419304Speter}
38519304Speter
38619304Speter/*
38719304Speter * cl_insertln --
38819304Speter *	Push down the current line, discarding the bottom line.
38919304Speter *
39019304Speter * PUBLIC: int cl_insertln __P((SCR *));
39119304Speter */
39219304Speterint
39319304Spetercl_insertln(sp)
39419304Speter	SCR *sp;
39519304Speter{
39619304Speter	/*
39719304Speter	 * The current line is expected to be blank after this operation,
39819304Speter	 * and the screen must support that semantic.
39919304Speter	 */
40019304Speter	return (insertln() == ERR);
40119304Speter}
40219304Speter
40319304Speter/*
40419304Speter * cl_keyval --
40519304Speter *	Return the value for a special key.
40619304Speter *
40719304Speter * PUBLIC: int cl_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *));
40819304Speter */
40919304Speterint
41019304Spetercl_keyval(sp, val, chp, dnep)
41119304Speter	SCR *sp;
41219304Speter	scr_keyval_t val;
41319304Speter	CHAR_T *chp;
41419304Speter	int *dnep;
41519304Speter{
41619304Speter	CL_PRIVATE *clp;
41719304Speter
41819304Speter	/*
41919304Speter	 * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990,
42019304Speter	 * VWERASE is a 4BSD extension.
42119304Speter	 */
42219304Speter	clp = CLP(sp);
42319304Speter	switch (val) {
42419304Speter	case KEY_VEOF:
42519304Speter		*dnep = (*chp = clp->orig.c_cc[VEOF]) == _POSIX_VDISABLE;
42619304Speter		break;
42719304Speter	case KEY_VERASE:
42819304Speter		*dnep = (*chp = clp->orig.c_cc[VERASE]) == _POSIX_VDISABLE;
42919304Speter		break;
43019304Speter	case KEY_VKILL:
43119304Speter		*dnep = (*chp = clp->orig.c_cc[VKILL]) == _POSIX_VDISABLE;
43219304Speter		break;
43319304Speter#ifdef VWERASE
43419304Speter	case KEY_VWERASE:
43519304Speter		*dnep = (*chp = clp->orig.c_cc[VWERASE]) == _POSIX_VDISABLE;
43619304Speter		break;
43719304Speter#endif
43819304Speter	default:
43919304Speter		*dnep = 1;
44019304Speter		break;
44119304Speter	}
44219304Speter	return (0);
44319304Speter}
44419304Speter
44519304Speter/*
44619304Speter * cl_move --
44719304Speter *	Move the cursor.
44819304Speter *
44919304Speter * PUBLIC: int cl_move __P((SCR *, size_t, size_t));
45019304Speter */
45119304Speterint
45219304Spetercl_move(sp, lno, cno)
45319304Speter	SCR *sp;
45419304Speter	size_t lno, cno;
45519304Speter{
45619304Speter	/* See the comment in cl_cursor. */
45719304Speter	if (move(RLNO(sp, lno), cno) == ERR) {
45819304Speter		msgq(sp, M_ERR,
45919304Speter		    "Error: move: l(%u) c(%u) o(%u)", lno, cno, sp->woff);
46019304Speter		return (1);
46119304Speter	}
46219304Speter	return (0);
46319304Speter}
46419304Speter
46519304Speter/*
46619304Speter * cl_refresh --
46719304Speter *	Refresh the screen.
46819304Speter *
46919304Speter * PUBLIC: int cl_refresh __P((SCR *, int));
47019304Speter */
47119304Speterint
47219304Spetercl_refresh(sp, repaint)
47319304Speter	SCR *sp;
47419304Speter	int repaint;
47519304Speter{
47619304Speter	CL_PRIVATE *clp;
47719304Speter
47819304Speter	clp = CLP(sp);
47919304Speter
48019304Speter	/*
48119304Speter	 * If we received a killer signal, we're done, there's no point
48219304Speter	 * in refreshing the screen.
48319304Speter	 */
48419304Speter	if (clp->killersig)
48519304Speter		return (0);
48619304Speter
48719304Speter	/*
48819304Speter	 * If repaint is set, the editor is telling us that we don't know
48919304Speter	 * what's on the screen, so we have to repaint from scratch.
49019304Speter	 *
49119304Speter	 * In the curses library, doing wrefresh(curscr) is okay, but the
49219304Speter	 * screen flashes when we then apply the refresh() to bring it up
49319304Speter	 * to date.  So, use clearok().
49419304Speter	 */
49519304Speter	if (repaint)
49619304Speter		clearok(curscr, 1);
49719304Speter	return (refresh() == ERR);
49819304Speter}
49919304Speter
50019304Speter/*
50119304Speter * cl_rename --
50219304Speter *	Rename the file.
50319304Speter *
50419304Speter * PUBLIC: int cl_rename __P((SCR *, char *, int));
50519304Speter */
50619304Speterint
50719304Spetercl_rename(sp, name, on)
50819304Speter	SCR *sp;
50919304Speter	char *name;
51019304Speter	int on;
51119304Speter{
51219304Speter	GS *gp;
51319304Speter	CL_PRIVATE *clp;
51419304Speter	char *ttype;
51519304Speter
51619304Speter	gp = sp->gp;
51719304Speter	clp = CLP(sp);
51819304Speter
51919304Speter	ttype = OG_STR(gp, GO_TERM);
52019304Speter
52119304Speter	/*
52219304Speter	 * XXX
52319304Speter	 * We can only rename windows for xterm.
52419304Speter	 */
52519304Speter	if (on) {
52619304Speter		if (F_ISSET(clp, CL_RENAME_OK) &&
52719304Speter		    !strncmp(ttype, "xterm", sizeof("xterm") - 1)) {
52819304Speter			F_SET(clp, CL_RENAME);
52919304Speter			(void)printf(XTERM_RENAME, name);
53019304Speter			(void)fflush(stdout);
53119304Speter		}
53219304Speter	} else
53319304Speter		if (F_ISSET(clp, CL_RENAME)) {
53419304Speter			F_CLR(clp, CL_RENAME);
53519304Speter			(void)printf(XTERM_RENAME, ttype);
53619304Speter			(void)fflush(stdout);
53719304Speter		}
53819304Speter	return (0);
53919304Speter}
54019304Speter
54119304Speter/*
54219304Speter * cl_suspend --
54319304Speter *	Suspend a screen.
54419304Speter *
54519304Speter * PUBLIC: int cl_suspend __P((SCR *, int *));
54619304Speter */
54719304Speterint
54819304Spetercl_suspend(sp, allowedp)
54919304Speter	SCR *sp;
55019304Speter	int *allowedp;
55119304Speter{
55219304Speter	struct termios t;
55319304Speter	CL_PRIVATE *clp;
55419304Speter	GS *gp;
55519304Speter	size_t oldy, oldx;
55619304Speter	int changed;
55719304Speter
55819304Speter	gp = sp->gp;
55919304Speter	clp = CLP(sp);
56019304Speter	*allowedp = 1;
56119304Speter
56219304Speter	/*
56319304Speter	 * The ex implementation of this function isn't needed by screens not
56419304Speter	 * supporting ex commands that require full terminal canonical mode
56519304Speter	 * (e.g. :suspend).
56619304Speter	 *
56719304Speter	 * The vi implementation of this function isn't needed by screens not
56819304Speter	 * supporting vi process suspension, i.e. any screen that isn't backed
56919304Speter	 * by a UNIX shell.
57019304Speter	 *
57119304Speter	 * Setting allowedp to 0 will cause the editor to reject the command.
57219304Speter	 */
57319304Speter	if (F_ISSET(sp, SC_EX)) {
57419304Speter		/* Save the terminal settings, and restore the original ones. */
57519304Speter		if (F_ISSET(clp, CL_STDIN_TTY)) {
57619304Speter			(void)tcgetattr(STDIN_FILENO, &t);
57719304Speter			(void)tcsetattr(STDIN_FILENO,
57819304Speter			    TCSASOFT | TCSADRAIN, &clp->orig);
57919304Speter		}
58019304Speter
58119304Speter		/* Stop the process group. */
58219304Speter		(void)kill(0, SIGTSTP);
58319304Speter
58419304Speter		/* Time passes ... */
58519304Speter
58619304Speter		/* Restore terminal settings. */
58719304Speter		if (F_ISSET(clp, CL_STDIN_TTY))
58819304Speter			(void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
58919304Speter		return (0);
59019304Speter	}
59119304Speter
59219304Speter	/*
59319304Speter	 * Move to the lower left-hand corner of the screen.
59419304Speter	 *
59519304Speter	 * XXX
59619304Speter	 * Not sure this is necessary in System V implementations, but it
59719304Speter	 * shouldn't hurt.
59819304Speter	 */
59919304Speter	getyx(stdscr, oldy, oldx);
60019304Speter	(void)move(LINES - 1, 0);
60119304Speter	(void)refresh();
60219304Speter
60319304Speter	/*
60419304Speter	 * Temporarily end the screen.  System V introduced a semantic where
60519304Speter	 * endwin() could be restarted.  We use it because restarting curses
60619304Speter	 * from scratch often fails in System V.  4BSD curses didn't support
60719304Speter	 * restarting after endwin(), so we have to do what clean up we can
60819304Speter	 * without calling it.
60919304Speter	 */
61019304Speter#ifdef HAVE_BSD_CURSES
61119304Speter	/* Save the terminal settings. */
61219304Speter	(void)tcgetattr(STDIN_FILENO, &t);
61319304Speter#endif
61419304Speter
61519304Speter	/* Restore the cursor keys to normal mode. */
61619304Speter	(void)keypad(stdscr, FALSE);
61719304Speter
61819304Speter	/* Restore the window name. */
61919304Speter	(void)cl_rename(sp, NULL, 0);
62019304Speter
62119304Speter#ifdef HAVE_BSD_CURSES
62219304Speter	(void)cl_attr(sp, SA_ALTERNATE, 0);
62319304Speter#else
62419304Speter	(void)endwin();
62519304Speter#endif
62619304Speter	/*
62719304Speter	 * XXX
62819304Speter	 * Restore the original terminal settings.  This is bad -- the
62919304Speter	 * reset can cause character loss from the tty queue.  However,
63019304Speter	 * we can't call endwin() in BSD curses implementations, and too
63119304Speter	 * many System V curses implementations don't get it right.
63219304Speter	 */
63319304Speter	(void)tcsetattr(STDIN_FILENO, TCSADRAIN | TCSASOFT, &clp->orig);
63419304Speter
63519304Speter	/* Stop the process group. */
63619304Speter	(void)kill(0, SIGTSTP);
63719304Speter
63819304Speter	/* Time passes ... */
63919304Speter
64019304Speter	/*
64119304Speter	 * If we received a killer signal, we're done.  Leave everything
64219304Speter	 * unchanged.  In addition, the terminal has already been reset
64319304Speter	 * correctly, so leave it alone.
64419304Speter	 */
64519304Speter	if (clp->killersig) {
64619304Speter		F_CLR(clp, CL_SCR_EX_INIT | CL_SCR_VI_INIT);
64719304Speter		return (0);
64819304Speter	}
64919304Speter
65019304Speter#ifdef HAVE_BSD_CURSES
65119304Speter	/* Restore terminal settings. */
65219304Speter	if (F_ISSET(clp, CL_STDIN_TTY))
65319304Speter		(void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);
65419304Speter
65519304Speter	(void)cl_attr(sp, SA_ALTERNATE, 1);
65619304Speter#endif
65719304Speter
65819304Speter	/* Set the window name. */
65919304Speter	(void)cl_rename(sp, sp->frp->name, 1);
66019304Speter
66119304Speter	/* Put the cursor keys into application mode. */
66219304Speter	(void)keypad(stdscr, TRUE);
66319304Speter
66419304Speter	/* Refresh and repaint the screen. */
66519304Speter	(void)move(oldy, oldx);
66619304Speter	(void)cl_refresh(sp, 1);
66719304Speter
66819304Speter	/* If the screen changed size, set the SIGWINCH bit. */
66919304Speter	if (cl_ssize(sp, 1, NULL, NULL, &changed))
67019304Speter		return (1);
67119304Speter	if (changed)
67219304Speter		F_SET(CLP(sp), CL_SIGWINCH);
67319304Speter
67419304Speter	return (0);
67519304Speter}
67619304Speter
67719304Speter/*
67819304Speter * cl_usage --
67919304Speter *	Print out the curses usage messages.
68019304Speter *
68119304Speter * PUBLIC: void cl_usage __P((void));
68219304Speter */
68319304Spetervoid
68419304Spetercl_usage()
68519304Speter{
68619304Speter#define	USAGE "\
68719304Speterusage: ex [-eFRrSsv] [-c command] [-t tag] [-w size] [file ...]\n\
68819304Speterusage: vi [-eFlRrSv] [-c command] [-t tag] [-w size] [file ...]\n"
68919304Speter	(void)fprintf(stderr, "%s", USAGE);
69019304Speter#undef	USAGE
69119304Speter}
69219304Speter
69319304Speter#ifdef DEBUG
69419304Speter/*
69519304Speter * gdbrefresh --
69619304Speter *	Stub routine so can flush out curses screen changes using gdb.
69719304Speter */
69819304Speterint
69919304Spetergdbrefresh()
70019304Speter{
70119304Speter	refresh();
70219304Speter	return (0);		/* XXX Convince gdb to run it. */
70319304Speter}
70419304Speter#endif
705