[BACK]Return to tty.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

File: [local] / src / usr.bin / mg / tty.c (download)

Revision 1.5, Thu Apr 13 06:12:17 2000 UTC (24 years, 1 month ago) by millert
Branch: MAIN
CVS Tags: OPENBSD_2_7_BASE, OPENBSD_2_7
Changes since 1.4: +122 -101 lines

The start of KNF + -Wall.  The code has been run through indent but
needs hand fixup.  I stopped at keymap.c...

/*
 * Terminfo display driver
 *
 * Terminfo is a terminal information database and routines to describe
 * terminals on most modern UNIX systems.  Many other systems have adopted
 * this as a reasonable way to allow for widly varying and ever changing
 * varieties of terminal types.	 This should be used where practical.
 */
/*
 * Known problems: If you have a terminal with no clear to end of screen and
 * memory of lines below the ones visible on the screen, display will be
 * wrong in some cases.  I doubt that any such terminal was ever made, but I
 * thought everyone with delete line would have clear to end of screen too...
 *
 * Code for terminals without clear to end of screen and/or clear to end of line
 * has not been extensivly tested.
 *
 * Cost calculations are very rough.  Costs of insert/delete line may be far
 * from the truth.  This is accentuated by display.c not knowing about
 * multi-line insert/delete.
 *
 * Using scrolling region vs insert/delete line should probably be based on cost
 * rather than the assuption that scrolling region operations look better.
 */
#include	"def.h"

#include	<term.h>

extern int      ttrow;
extern int      ttcol;
extern int      tttop;
extern int      ttbot;
extern int      tthue;

extern int      ttputc();

int             tceeol;		/* Costs are set later */
int             tcinsl;
int             tcdell;

static int      insdel;		/* Do we have both insert & delete line? */
static char    *scroll_fwd;	/* How to scroll forward. */

#ifdef NO_RESIZE
static          setttysize();
#endif

/*
 * Initialize the terminal when the editor
 * gets started up.
 */
VOID
ttinit()
{
	char           *tv_stype;
	char           *t, *p;
#ifndef gettermtype		/* (avoid declaration if #define) */
	char           *gettermtype();	/* system dependent function to
					 * determin terminal type */
#endif

	if ((tv_stype = gettermtype()) == NULL)
		panic("Could not determine terminal type");
	if (setupterm(tv_stype, 1, NULL)) {
		(void) asprintf(&p, "Unknown terminal type: %s", tv_stype);
		panic(p);
	}
	scroll_fwd = scroll_forward;
	if (!scroll_fwd || !*scroll_fwd) {
		/* this is what GNU Emacs does */
		scroll_fwd = parm_down_cursor;
		if (!scroll_fwd || !*scroll_fwd)
			scroll_fwd = "\n";
	}
	if (!cursor_address || !cursor_up)
		panic("This terminal is to stupid to run mg");
	ttresize();		/* set nrow & ncol	 */

	if (!clr_eol)
		tceeol = ncol;
	else
		tceeol = charcost(clr_eol);

	/* Estimate cost of inserting a line */
	if (change_scroll_region && scroll_reverse)
		tcinsl = charcost(change_scroll_region) * 2 +
			charcost(scroll_reverse);
	else if (parm_insert_line)
		tcinsl = charcost(parm_insert_line);
	else if (insert_line)
		tcinsl = charcost(insert_line);
	else
		tcinsl = NROW * NCOL;	/* make this cost high enough */

	/* Estimate cost of deleting a line */
	if (change_scroll_region)
		tcdell = charcost(change_scroll_region) * 2 +
			charcost(scroll_fwd);
	else if (parm_delete_line)
		tcdell = charcost(parm_delete_line);
	else if (delete_line)
		tcdell = charcost(delete_line);
	else
		tcdell = NROW * NCOL;	/* make this cost high enough */

	/* Flag to indicate that we can both insert and delete lines */
	insdel = (insert_line || parm_insert_line) && (delete_line || parm_delete_line);

	if (enter_ca_mode)
		putpad(enter_ca_mode, 1);	/* enter application mode */

	setttysize();
}

/*
 * Re-initialize the terminal when the editor is resumed.
 * The keypad_xmit doesn't really belong here but...
 */
VOID
ttreinit()
{
	if (enter_ca_mode)
		putpad(enter_ca_mode, 1);	/* enter application mode */
	if (keypad_xmit)
		putpad(keypad_xmit, 1);		/* turn on keypad */

	setttysize();
}

/*
 * Clean up the terminal, in anticipation of
 * a return to the command interpreter. This is a no-op
 * on the ANSI display. On the SCALD display, it sets the
 * window back to half screen scrolling. Perhaps it should
 * query the display for the increment, and put it
 * back to what it was.
 */
VOID
tttidy()
{

#ifdef	XKEYS
	ttykeymaptidy();
#endif
	/* set the term back to normal mode */
	if (exit_ca_mode)
		putpad(exit_ca_mode, 1);
}

/*
 * Move the cursor to the specified
 * origin 0 row and column position. Try to
 * optimize out extra moves; redisplay may
 * have left the cursor in the right
 * location last time!
 */
VOID
ttmove(row, col)
{
	char           *tgoto();

	if (ttrow != row || ttcol != col) {
		putpad(tgoto(cursor_address, col, row), 1);
		ttrow = row;
		ttcol = col;
	}
}

/*
 * Erase to end of line.
 */
VOID
tteeol()
{

	if (clr_eol)
		putpad(clr_eol, 1);
	else {
		int             i = ncol - ttcol;
		while (i--)
			ttputc(' ');
		ttrow = ttcol = HUGE;
	}
}

/*
 * Erase to end of page.
 */
VOID
tteeop()
{
	int             line;

	if (clr_eos)
		putpad(clr_eos, nrow - ttrow);
	else {
		putpad(clr_eol, 1);
		if (insdel)
			ttdell(ttrow + 1, lines, lines - ttrow - 1);
		else {		/* do it by hand */
			for (line = ttrow + 1; line <= lines; ++line) {
				ttmove(line, 0);
				tteeol();
			}
		}
		ttrow = ttcol = HUGE;
	}
}

/*
 * Make a noise.
 */
VOID
ttbeep()
{
	putpad(bell, 1);
	ttflush();
}

/*
 * Insert nchunk blank line(s) onto the
 * screen, scrolling the last line on the
 * screen off the bottom.  Use the scrolling
 * region if possible for a smoother display.
 * If no scrolling region, use a set
 * of insert and delete line sequences
 */
VOID
ttinsl(row, bot, nchunk)
{
	int             i, nl;

	if (row == bot) {	/* Case of one line insert is	 */
		ttmove(row, 0);	/* special			 */
		tteeol();
		return;
	}
	if (change_scroll_region && scroll_reverse) {
		/* Use scroll region and back index	 */
		nl = bot - row;
		ttwindow(row, bot);
		ttmove(row, 0);
		while (nchunk--)
			putpad(scroll_reverse, nl);
		ttnowindow();
		return;
	} else if (insdel) {
		ttmove(1 + bot - nchunk, 0);
		nl = nrow - ttrow;
		if (parm_delete_line)
			putpad(tgoto(parm_delete_line, 0, nchunk), nl);
		else
			/* For all lines in the chunk	 */
			for (i = 0; i < nchunk; i++)
				putpad(delete_line, nl);
		ttmove(row, 0);
		nl = nrow - ttrow;	/* ttmove() changes ttrow */
		if (parm_insert_line)
			putpad(tgoto(parm_insert_line, 0, nchunk), nl);
		else
			/* For all lines in the chunk */
			for (i = 0; i < nchunk; i++)
				putpad(insert_line, nl);
		ttrow = HUGE;
		ttcol = HUGE;
	} else
		panic("ttinsl: Can't insert/delete line");
}

/*
 * Delete nchunk line(s) from "row", replacing the
 * bottom line on the screen with a blank line.
 * Unless we're using the scrolling region, this is
 * done with a crafty sequences of insert and delete
 * lines.  The presence of the echo area makes a
 * boundry condition go away.
 */
VOID
ttdell(row, bot, nchunk)
{
	int             i, nl;

	if (row == bot) {	/* One line special case	 */
		ttmove(row, 0);
		tteeol();
		return;
	}
	if (change_scroll_region) {	/* scrolling region		 */
		nl = bot - row;
		ttwindow(row, bot);
		ttmove(bot, 0);
		while (nchunk--)
			putpad(scroll_fwd, nl);
		ttnowindow();
	} else if (insdel) {
		ttmove(row, 0);	/* Else use insert/delete line	 */
		nl = nrow - ttrow;
		if (parm_delete_line)
			putpad(tgoto(parm_delete_line, 0, nchunk), nl);
		else
			/* For all lines in the chunk	 */
			for (i = 0; i < nchunk; i++)
				putpad(delete_line, nl);
		ttmove(1 + bot - nchunk, 0);
		nl = nrow - ttrow;	/* ttmove() changes ttrow */
		if (parm_insert_line)
			putpad(tgoto(parm_insert_line, 0, nchunk), nl);
		else
			/* For all lines in the chunk */
			for (i = 0; i < nchunk; i++)
				putpad(insert_line, nl);
		ttrow = HUGE;
		ttcol = HUGE;
	} else
		panic("ttdell: Can't insert/delete line");
}

/*
 * This routine sets the scrolling window
 * on the display to go from line "top" to line
 * "bot" (origin 0, inclusive). The caller checks
 * for the pathalogical 1 line scroll window that
 * doesn't work right, and avoids it. The "ttrow"
 * and "ttcol" variables are set to a crazy value
 * to ensure that the next call to "ttmove" does
 * not turn into a no-op (the window adjustment
 * moves the cursor).
 *
 */
VOID
ttwindow(top, bot)
{
	if (change_scroll_region && (tttop != top || ttbot != bot)) {
		putpad(tgoto(change_scroll_region, bot, top), nrow - ttrow);
		ttrow = HUGE;	/* Unknown.		 */
		ttcol = HUGE;
		tttop = top;	/* Remember region.	 */
		ttbot = bot;
	}
}

/*
 * Switch to full screen scroll. This is
 * used by "spawn.c" just before is suspends the
 * editor, and by "display.c" when it is getting ready
 * to exit.  This function gets to full screen scroll
 * by telling the terminal to set a scrolling regin
 * that is lines or nrow rows high, whichever is larger.
 * This behavior seems to work right on systems
 * where you can set your terminal size.
 */
VOID
ttnowindow()
{
	if (change_scroll_region) {
		putpad(tgoto(change_scroll_region,
		       (nrow > lines ? nrow : lines) - 1, 0), nrow - ttrow);
		ttrow = HUGE;	/* Unknown.		 */
		ttcol = HUGE;
		tttop = HUGE;	/* No scroll region.	 */
		ttbot = HUGE;
	}
}

/*
 * Set the current writing color to the
 * specified color. Watch for color changes that are
 * not going to do anything (the color is already right)
 * and don't send anything to the display.
 * The rainbow version does this in putline.s on a
 * line by line basis, so don't bother sending
 * out the color shift.
 */
VOID
ttcolor(color)
	int             color;
{

	if (color != tthue) {
		if (color == CTEXT)	/* Normal video.	 */
			putpad(exit_standout_mode, 1);
		else if (color == CMODE)	/* Reverse video.	 */
			putpad(enter_standout_mode, 1);
		tthue = color;	/* Save the color.	 */
	}
}

/*
 * This routine is called by the
 * "refresh the screen" command to try and resize
 * the display. The new size, which must be deadstopped
 * to not exceed the NROW and NCOL limits, it stored
 * back into "nrow" and "ncol". Display can always deal
 * with a screen NROW by NCOL. Look in "window.c" to
 * see how the caller deals with a change.
 */
VOID
ttresize()
{

	setttysize();		/* found in "ttyio.c",	 */
	/* ask OS for tty size	 */
	if (nrow < 1)		/* Check limits.	 */
		nrow = 1;
	else if (nrow > NROW)
		nrow = NROW;
	if (ncol < 1)
		ncol = 1;
	else if (ncol > NCOL)
		ncol = NCOL;
}

#ifdef NO_RESIZE
static
setttysize()
{
	nrow = lines;
	ncol = columns;
}
#endif

static int      cci;

/* ARGSUSED */
static int			/* fake char output for charcost() */
fakec(c)
	char            c;
{
	cci++;
}

/* calculate the cost of doing string s */
charcost(s)
	char           *s;
{
	cci = 0;

	tputs(s, nrow, fakec);
	return (cci);
}