[net.emacs] CIT500 driver for EMACS

dan@rna.UUCP (Dan Ts'o) (06/25/84)

HI,
	Having received a number of requests for the CIT500 driver for
EMACS, here it is. Actually it should be quite suitable for most full-featured
ANSI terminals with functions such as line delete and insert and change scroll
region. (VT100's don't have line insert and delete).
	I made a number of decisions in favor of my view of esthetics. For
multiwindowed displays, I feel that change scrolling region updates look better
than line-insert/delete, although more costly. Code is present for both,
however, so if you disagree, just comment out the change scroll code.
	I'd appreciate any feedback since I know there probably is much room
for improvement. I know that the padding is probably not quite correct, but then
the CIT500 has a large buffer. In any case, this driver performs much better
than TrmTERM.c for the CIT500.

					Cheers,
					Dan Ts'o
					...cmcl2!rna!dan

P.S.
	Once one is used to a 64-line terminal, 24-lines is puny.

/*
 * terminal control module for CIT 500
 *	based on originally on TrmBitG.c
 *	Dan Ts'o 4/84
 *	Should be fine for many ANSI-like terminals.
 *	Uses delete character, delete line, insert character, insert line,
 *		change scrolling region, set/reset insert mode, inverse
 *		video, some private functions like set/reset automargins,
 *		as well as the usual cursor addressing, clear screen, etc.
 */

#include <stdio.h>
#include "Trm.h"
#define	AM_IS_NORMAL	1	/* Define if Autowrap is always on,
				 *	undefine if uncertain
				 */

static
int	curX, curY;

static int   Baud;

static int   CIT_LI = 64,
#ifdef	AM_IS_NORMAL
	CIT_CO = 80;
#else
	CIT_CO = 79;
#endif
static int   WindowSize;

static
enum IDmode { m_insert = 1, m_overwrite = 0}
	DesiredMode, CurrentMode;

#define	PAD(n,f)	if(Baud>9600)pad(n,f)

static
INSmode (new)
enum IDmode new; {
	DesiredMode = new;
};

static
setmode ()
{
	if (DesiredMode == CurrentMode)
		return;
	if (DesiredMode == m_insert)
		printf("\033[4h");
	else
		printf("\033[4l");
	CurrentMode = DesiredMode;
}

static
CurHL, DesHL;

static
HLmode (new) {
	DesHL = new;
}

static
SetHL (OverRide) {
	register LDes = OverRide ? 0 : DesHL;
	if (LDes == CurHL)
		return;
	printf (LDes ? "\033[7m" : "\033[m");
	CurHL = LDes;
}

static
inslines (n)
register int n;
{
	SetHL (1);
	/* Esthetics - CS motions look better than insert/delete motions
	 * with multiple windows
	 * Check for multi-windowed display
	 */
	if (WindowSize != tt.t_length) {
		printf("\033[%d;%dr\033[%dH", curY, WindowSize, curY);
		curX = 1;
/*
		while (--n >= 0) {
			printf("\033M");
			PAD(1, 20.);
		}
 */
		printf (n <= 1 ? "\033[L" : "\033[%dL", n);
		PAD (CIT_LI-curY-n, 3.0);
		printf("\033[r");
		PAD(1, 2.);
		curX = curY = 1;
		return;
	}
	printf (n <= 1 ? "\033[L" : "\033[%dL", n);
	PAD (CIT_LI-curY-n, 3.0);
};

static
dellines (n)
register int n;
{
	SetHL (1);
	/* Check for multi-windowed display */
	if (WindowSize != tt.t_length) {
/*
		printf("\033[%d;%dr\033[%dH", curY, WindowSize, WindowSize);
		curX = 1;
		curY = WindowSize;
		while (--n >= 0) {
			printf("\033E");
			PAD(1, 20.);
		}
 */
		printf("\033[%d;%dr\033[%dH", curY, WindowSize, curY);
		curX = 1;
		printf (n <= 1 ? "\033[M" : "\033[%dM", n);
		PAD (CIT_LI-curY, 3.0);
		printf("\033[r");
		PAD(1, 2.);
		curX = curY = 1;
		return;
	};
	printf (n <= 1 ? "\033[M" : "\033[%dM", n);
	PAD (CIT_LI-curY, 3.0);
};

static
writechars (start, end)
register char *start,
	      *end; {
	register p = end-start+1;

	SetHL (0);
	setmode();
/*
	if (DesiredMode == m_insert) {
		printf ("\033[%d@", p);
		PAD (1, 3.0);
	}
 */
	curX += p;
	while (start <= end)
		putchar (*start++);
	PAD (p, .6);
};

static
blanks (n) {
	if (n > 0) {
		setmode();
		SetHL (0);
/*
		if (DesiredMode == m_insert) {
			printf ("\033[%d@", n);
			PAD (1, 3.0);
		}
 */
		curX += n;
		while (--n >= 0) putchar (' ');
/*
 		putchar (' ');
		if (--n)
			printf ("\b\033[%d@", n);
		else
			curX++;
 */
	}
	PAD (n, .6);
};

static float BaudFactor;

static pad(n,f)
float   f; {
	register k;

	k = n * f * BaudFactor;
	while (--k >= 0)
		putchar (0);
};

static
topos (row, column) {
	if (curY == row) {
		if (curX == column)
			return;
		if (curX == column + 1) {
			putchar ('\b');
			goto done;
		}
	}
	if (curY+1 == row && (column == 1 || column == curX)) {
		if (column != curX) putchar (015);
		putchar (012);
		goto done;
	}
	if (curY == row+1 && column == curX) {
		printf ("\033M");
		goto done;
	}
	if (row == 1 && column == 1) {
		printf ("\033[H");
		goto done;
	}
	if (column == 1) {
		printf ("\033[%dH", row);
		goto done;
	}
	printf ("\033[%d;%dH", row, column);
done: 
	curX = column;
	curY = row;
};

static
init (BaudRate) {
	Baud = BaudRate;
	BaudFactor = ((float) BaudRate) / 10000.;
};

static
reset () {
	/* Home, clear, no HL, keypad mode */
	printf ("\033[H\033[2J\033[m\033[r\033=");
#ifdef	AM_IS_NORMAL
	printf ("\033[?7l");
#endif
	WindowSize = tt.t_length;
	curX = curY = 1;
	CurHL = 0;
	DesiredMode = m_overwrite;
	CurrentMode = m_insert;
};

static
cleanup () {
	SetHL (1);
	topos (WindowSize, 1);
	printf("\033>");		/* Exit keypad mode */
#ifdef	AM_IS_NORMAL
	printf("\033[?7h");
#endif
	DesiredMode = m_overwrite;
	CurrentMode = m_insert;
	setmode();
};

static
wipeline () {
	SetHL (1);
	printf ("\033[K");
	PAD (1, 6.0);
};

static
wipescreen () {
	SetHL (1);
	printf("\033[2J");
	PAD (1, 10.0);
};

static
window (n)
register int n;
{
	if (n <= 0 || n > tt.t_length)
		n = tt.t_length;
	WindowSize = n;
}

static
delchars (n) {
	if (n<=0) return;
	SetHL (1);
	printf(n == 1 ? "\033[P" : "\033[%dP", n);
	PAD (1, 3.0);
};

static
flash () {
	printf ("\033[?5%c", InverseVideo ? 'h' : 'l');
	pad (1, 100.0);

	printf ("\033[?5%c", InverseVideo ? 'l' : 'h');
	pad (1, 100.0);		/* this is REALLY slow!! */
}

TrmCIT500 (term)
char *term;
{
	register char *s;
	char *getenv();
	char tbuf[1024];

	if (tgetent (tbuf, term) <= 0) {
		tt.t_length = CIT_LI = tgetnum("li");
		tt.t_width = CIT_CO = tgetnum("co")
#ifdef	AM_IS_NORMAL
			;
#else
			- (tgetflag("am") ? 1 : 0);
#endif
	}
	else {
		tt.t_length = CIT_LI;
		tt.t_width = CIT_CO;
	}
		
	tt.t_INSmode = INSmode;
	tt.t_HLmode = HLmode;
	tt.t_inslines = inslines;
	tt.t_dellines = dellines;
	tt.t_blanks = blanks;
	tt.t_init = init;
	tt.t_cleanup = cleanup;
	tt.t_wipeline = wipeline;
	tt.t_wipescreen = wipescreen;
	tt.t_topos = topos;
	tt.t_reset = reset;
	tt.t_delchars = delchars;
	tt.t_writechars = writechars;
	tt.t_flash = flash;
	tt.t_window = window;
	tt.t_ILmf = 0;
	tt.t_ILov = 5;
	tt.t_ICmf = 0;
	tt.t_ICov = 5;
	tt.t_DCmf = 0;
	tt.t_DCov = 5;
};

chris@umcp-cs.UUCP (07/02/84)

Just got around to looking at rna!dan's CIT500 terminal driver.  I noticed
one odd thing in the code.  In TrmCIT500(), there is the following:

	if (tgetent (tbuf, term) <= 0) {
		tt.t_length = CIT_LI = tgetnum("li");
		tt.t_width = CIT_CO = tgetnum("co")
		.
		.
		.

Now, I don't know about your tgetent, but ours (4.1BSD) returns 1 if
the tgetent succeeded.  So it seems to me that the code should say

	if (tgetent (tbuf, term) > 0) {
		.
		.
		.

Other than that, it looks reasonable.  By the way, for Emacs #264
you'd want to change all the padding calls to use fltofixp and
friends.  (For mine, you'd use the `pad' routine in display.c with
`long' values in terms of microseconds, but then you don't have mine.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci (301) 454-7690
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland