2.9BSD/usr/contrib/jove/jove_curs.c

Compare this file to the similar file:
Show the results in this format:

/*
   Jonathan Payne at Lincoln-Sudbury Regional High School 5-25-83

   jove_curs.c

   The cursor optimization happens here.  You may decide that this
   is going too far with cursor optimization, or perhaps it should
   limit the amount of checking to when the output speed is slow.
   What ever turns you on ...   */

#include "jove.h"
#include "termcap.h"

extern int	CapCol,
		CapLine;

struct cursaddr {
	int	c_numchars,
		(*c_func)();
};

char	*Cmstr;
struct cursaddr	*HorMin,
		*VertMin,
		*DirectMin;

#define	FORWARD		0	/* Move forward */
#define FORTAB		1	/* Forward using tabs */
#define	BACKWARD	2	/* Move backward */
#define RETFORWARD	3	/* Beginning of line and then tabs */
#define NUMHOR		4

#define DOWN		0	/* Move down */
#define UPMOVE		1	/* Move up */
#define NUMVERT		2

#define DIRECT		0	/* Using CM */
#define HOME		1	/* HOME	*/
#define LOWER		2	/* Lower line */
#define NUMDIRECT	3

#define	home()		Placur(0, 0)
#define LowLine()	putpad(LL, 1), CapLine = LI - 1, CapCol = 0
#define PrintHo()	putpad(HO, 1), CapLine = CapCol = 0

struct cursaddr	WarpHor[NUMHOR],
		WarpVert[NUMVERT],
		WarpDirect[NUMDIRECT];

int	phystab = 8;

GoDirect(line, col)
register int	line,
		col;
{
	putpad(Cmstr, 1), CapLine = line, CapCol = col;
}

RetTab(col)
register int	col;
{
	outchar('\r'), CapCol = 0, ForTab(col);
}

HomeGo(line, col)
{
	PrintHo(), DownMotion(line), ForTab(col);
}

BottomUp(line, col)
register int	line,
		col;
{
	LowLine(), UpMotion(line), ForTab(col);
}

ForTab(col)
register int	col;
{
	register int	where,
			ntabs;

	if (TABS) {
		where = col - (col % phystab);	/* Round down. */
		if ((where + phystab) - col < col - where)
			where += phystab; /* Go past and come back. */
		if (where >= CO)
			where -= phystab;	/* Don't tab to last place
						 * or it is likely to screw
						 * up
						 */
		ntabs = (where / phystab) - (CapCol / phystab);
		while (--ntabs >= 0)
			outchar('\t');
		CapCol = where;
	}
	if (CapCol > col)
		BackMotion(col);
	else if (CapCol < col)
		ForMotion(col);
}

extern struct screenline	*Screen;

ForMotion(col)
register int	col;
{
	register int	length = Screen[CapLine].s_length -
					Screen[CapLine].s_line;
	register char	*cp = &Screen[CapLine].s_line[CapCol];

	while (CapCol < col) {

		if (CapCol >= length)
			*cp = ' ';
		outchar(*cp);
		cp++;
		CapCol++;
	}
}

BackMotion(col)
register int	col;
{
	while (CapCol > col) {	/* Go to the left. */
		if (BC)
			putpad(BC, 1);
		else
			outchar('\b');
		CapCol--;
	}
}

DownMotion(line)
register int	line;
{
	while (CapLine < line) {	/* Go down. */
		outchar('\n');
		CapLine++;
	}
}

UpMotion(line)
register int	line;
{
	while (CapLine > line) {	/* Go up. */
		putpad(UP, 1);
		CapLine--;
	}
}

InitCM()
{
	WarpHor[FORWARD].c_func = ForMotion;
	WarpHor[BACKWARD].c_func = BackMotion;
	WarpHor[FORTAB].c_func = ForTab;
	WarpHor[RETFORWARD].c_func = RetTab;

	WarpVert[DOWN].c_func = DownMotion;
	WarpVert[UPMOVE].c_func = UpMotion;

	WarpDirect[DIRECT].c_func = GoDirect;
	WarpDirect[HOME].c_func = HomeGo;
	WarpDirect[LOWER].c_func = BottomUp;

	HomeLen = HO ? strlen(HO) : 1000;
	LowerLen = LL ? strlen(LL) : 1000;
	UpLen = UP ? strlen(UP) : 1000;
}

extern int	InMode;

DoPlacur(line, col)
{
	int	dline,		/* Number of lines to move */
		dcol;		/* Number of columns to move */
	register int	best,
			i;
	register struct cursaddr	*cp;

#define CursMin(which,addrs,max) \
	for (best = 0, cp = &addrs[1], i = 1; i < max; i++, cp++) \
		if (cp->c_numchars < addrs[best].c_numchars) \
			best = i; \
	which = &addrs[best]; \

	if (line == CapLine && col == CapCol)
		return;		/* We are already there. */

	if (InMode)
		putstr(EI), InMode = 0;
	dline = line - CapLine;
	dcol = col - CapCol;

	/* Number of characters to move horizontally for each case.
	 * 1: Just move forward by typing the right character on the screen
	 * 2: Print the correct number of back spaces
	 * 3: Try tabbing to the correct place
	 * 4: Try going to the beginning of the line, and then tab
	 */

	if (dcol == 1 || dcol == 0) {		/* Most common case */
		HorMin = &WarpHor[FORWARD];
		HorMin->c_numchars = dcol;
	} else {
		WarpHor[FORWARD].c_numchars = dcol >= 0 ? dcol : 1000;
		WarpHor[BACKWARD].c_numchars = dcol < 0 ? -dcol : 1000;
		WarpHor[FORTAB].c_numchars = dcol >= 0 && TABS ?
				ForNum(CapCol, col) : 1000;
		WarpHor[RETFORWARD].c_numchars = (1 + (TABS ? ForNum(0, col) : col));

		/* Which is the shortest of the bunch */

		CursMin(HorMin, WarpHor, NUMHOR);
	}

	/* Moving vertically is more simple. */

	WarpVert[DOWN].c_numchars = dline >= 0 ? dline : 1000;
	WarpVert[UPMOVE].c_numchars = dline < 0 ? ((-dline) * UpLen) : 1000;

	/* Which of these is simpler */
	CursMin(VertMin, WarpVert, NUMVERT);

	/* Homing first and lowering first are considered 
	   direct motions.
	   Homing first's total is the sum of the cost of homing
	   and the sum of tabbing (if possible) to the right. */
	
	if (VertMin->c_numchars + HorMin->c_numchars <= 3) {
		DirectMin = &WarpDirect[DIRECT];	/* A dummy ... */
		DirectMin->c_numchars = 100;
	}		
	WarpDirect[DIRECT].c_numchars = CM ?
				strlen(Cmstr = tgoto(CM, col, line)) : 1000;
	WarpDirect[HOME].c_numchars = HomeLen + line +
				WarpHor[RETFORWARD].c_numchars;
	WarpDirect[LOWER].c_numchars = LowerLen + ((LI - line - 1) * UpLen) +
				WarpHor[RETFORWARD].c_numchars;

	CursMin(DirectMin, WarpDirect, NUMDIRECT);

	if (HorMin->c_numchars + VertMin->c_numchars < DirectMin->c_numchars) {
		if (line != CapLine)
			(*VertMin->c_func)(line);
		if (col != CapCol)
			(*HorMin->c_func)(col);
	} else
		(*DirectMin->c_func)(line, col);
}

#define abs(x)	((x) >= 0 ? (x) : -(x))

ForNum(from, to)
register int	from,
		to;
{
	register int	where;
	int		numchars = 0;

	if (from > to)
		return from - to;
	if (TABS) {
		where = to - (to % phystab);   /* Round down. */
		if ((where + phystab) - to < to - where)
			where += phystab;
		if (where >= CO)
			where -= phystab;	/* Don't tab to last place
						 * or it is likely to screw
						 * up
						 */
		numchars = (where / phystab) - (from / phystab);
		from = where;
	}
	return numchars + abs(from - to);
}