/*
Copyright (C) Magna Carta Software, Inc. 1990. All Rights Reserved.
C COMMUNICATIONS TOOLKIT
TV925.C -- Televideo 912/920/925 terminal emulation routines.
t->mode is encoded as:
Bit 0: 1=protect mode set;
Bit 1: 1=in protect mode;
*/
#define CCT_DEVELOPMENT
#if (defined(CCTW) || defined(_WINDOWS))
#include <windows.h>
#endif
#include <string.h>
#include <comm.h>
#include <tv.h>
#include <ctype.h>
#include <stdlib.h>
static BYTE chbuf[24][80]; /* screen buffer holds character bytes */
static BYTE attbuf[24][80]; /* screen buffer holds attribute bytes */
static BYTE probuf[24][80]; /* screen buffer holds protection flags */
short tv_update_att_(TERMINAL *t, short att);
/*
TV925_INIT -- Memory initialization of TELEVIDEO 925.
*/
void tv925_init(TERMINAL *t)
{
t->type = TV_925;
t->append = TRUE;
t->att = 15;
t->csi = 0X1B;
t->cur_pos = tv_cur_pos_;
t->cur_size = tv_cur_att_;
t->d_att = ATT(15, 0);
t->d_rows = 24;
t->d_cols = 80;
t->delim1 = 0;
t->dispatch_ctrl = tv_dispatch_ctrl_;
t->erase = tv_erase_;
t->mode = 0;
t->offset = 1;
t->parse_cmd = tv_parse_cmd_;
t->parse_parms = term_binary_parse_parms_;
t->reset_mode = (void (*)(TERMINAL *, short)) NULL;
t->set_mode = (void (*)(TERMINAL *, short)) NULL;
t->sgr = tv_sgr_;
/* MAP THE KEYBOARD */
if (enhanced_kbd) {
/* IF THE ENHANCED KEYBOARD IS PRESENT AND HAS BIOS SUPPORT, USE IT */
term_assign_key(t, GREY_UP_ARROW, 0, "\xB");
term_assign_key(t, GREY_DOWN_ARROW, 0, "\x16");
term_assign_key(t, GREY_RIGHT_ARROW, 0, "\xC");
term_assign_key(t, GREY_LEFT_ARROW, 0, "\x8");
term_assign_key(t, GREY_HOME, 0, "\x1E");
term_assign_key(t, KP_ENTER, 0, "\x1F");
}
else {
term_assign_key(t, S_UP_ARROW, 0, "\xB");
term_assign_key(t, S_DOWN_ARROW, 0, "\x16");
term_assign_key(t, S_RIGHT_ARROW, 0, "\xC");
term_assign_key(t, S_LEFT_ARROW, 0, "\x8");
term_assign_key(t, HOME, 0, "\x1E");
term_assign_key(t, PLUS, 0, "\x1F");
}
term_assign_key(t, F1, 0, "\x1@\r");
term_assign_key(t, F2, 0, "\x1" "A\r");
term_assign_key(t, F3, 0, "\x1" "B\r");
term_assign_key(t, F4, 0, "\x1" "C\r");
term_assign_key(t, F5, 0, "\x1" "D\r");
term_assign_key(t, F6, 0, "\x1" "E\r");
term_assign_key(t, F7, 0, "\x1" "F\r");
term_assign_key(t, F8, 0, "\x1" "G\r");
term_assign_key(t, F9, 0, "\x1" "H\r");
term_assign_key(t, F10, 0, "\x1" "I\r");
term_assign_key(t, F11, 0, "\x1" "J\r");
term_assign_key(t, S_F1, 0, "\x1" "`\r");
term_assign_key(t, S_F2, 0, "\x1" "a\r");
term_assign_key(t, S_F3, 0, "\x1" "b\r");
term_assign_key(t, S_F4, 0, "\x1" "c\r");
term_assign_key(t, S_F5, 0, "\x1" "d\r");
term_assign_key(t, S_F6, 0, "\x1" "e\r");
term_assign_key(t, S_F7, 0, "\x1" "f\r");
term_assign_key(t, S_F8, 0, "\x1" "g\r");
term_assign_key(t, S_F9, 0, "\x1" "h\r");
term_assign_key(t, S_F10, 0, "\x1" "i\r");
term_assign_key(t, S_F11, 0, "\x1" "j\r");
term_assign_key(t, DELETE, 0, "\x1BW"); /* char delete */
term_assign_key(t, S_DELETE, 0, "\x1BR"); /* line delete */
term_assign_key(t, BACKSPACE, 0, "\x7F");
/* RECEIVED COMMANDS */
/* CURSOR CONTROL */
term_assign_cmd(t, CA, ".%", tv_cur_att_, NULL); /* cursor attributes */
term_assign_cmd(t, HVP, "=%%",tv_cur_pos_, NULL); /* cursor position */
/* CHARACTER ATTRIBUTES */
term_assign_cmd(t, SGR, "G%", (void (*)(TERMINAL *, short)) tv_sgr_, NULL); /* char. attributes */
term_assign_cmd(t, SPM, ")", (void (*)(TERMINAL *, short)) tv_spm_, NULL); /* set ptrotect mode */
term_assign_cmd(t, RPM, "(", (void (*)(TERMINAL *, short)) tv_rpm_, NULL); /* reset protect mode */
term_assign_cmd(t, USER2, "&", (void (*)(TERMINAL *, short)) tv_spm_, NULL); /* set protect mode */
term_assign_cmd(t, USER3, "'", (void (*)(TERMINAL *, short)) tv_rpm_, NULL); /* reset protect mode */
/* CURSOR ADDRESSING */
term_assign_cmd(t, CPR, "?", (void (*)(TERMINAL *, short)) tv_cpr_, NULL); /* cursor position report */
/* ERASE IN DISPLAY */
term_assign_cmd(t, EED0, "Y", tv_erase_, NULL); /* erase to EOD (SP) */
term_assign_cmd(t, EED1, "y", tv_erase_, NULL); /* erase to EOD (NUL) */
term_assign_cmd(t, ED, ":", tv_erase_, NULL); /* erase unprotected to NULs */
/* ERASE IN LINE */
term_assign_cmd(t, EEL0, "T", tv_erase_, NULL); /* erase to EOL (SP) */
term_assign_cmd(t, EEL1, "t", tv_erase_, NULL); /* erase to EOL (NUL) */
term_assign_cmd(t, EL, "R", tv_erase_, NULL); /* erase line */
term_assign_cmd(t, ECH, "W", tv_erase_, NULL); /* erase character */
term_assign_cmd(t, USER1, "*", tv_erase_, NULL); /* clear all data to NULs */
/* INITIALIZE BUFFERS */
memset(chbuf, 0X0, sizeof(chbuf));
memset(attbuf, t->d_att, sizeof(attbuf));
}
/*
TV_CPR -- Send a cursor position report from an TELEVIDEO terminal.
*/
void tv_cpr_(TERMINAL *t)
{
char *pa, asc[4];
term_write(t, t->csi);
itoa((*t->cur_get_row)(t)+0X1F, asc, 10);
pa = asc;
while (*pa) term_write(t, *pa++);
term_write(t, t->delim1);
itoa((*t->cur_get_col)(t)+0X1F, asc, 10);
pa = asc;
while (*pa) term_write(t, *pa++);
}
/*
TV_CUR_POS_ -- Handle terminal movement commands.
*/
void tv_cur_pos_(TERMINAL *t, short cmd)
{
switch(cmd) {
case CUB: /* cursor back */
if (t->ccol > t->lmargin) {
t->ccol = (t->num[1]==0) ? t->ccol-1 : max(t->ccol-t->num[1], t->lmargin);
}
break;
case CUD:
if (t->crow < t->bmargin) {
t->crow = (t->num[0] == 0) ? t->crow+1 : min(t->crow+t->num[0], t->bmargin);
}
break;
case CUF:
if (t->ccol < t->rmargin) {
t->ccol = (t->num[1] == 0) ? t->ccol+1 : min(t->ccol+t->num[1], t->rmargin);
}
break;
case CUP:
case HVP:
t->crow = (t->num[0] == 0) ? t->tmargin : t->tmargin + t->num[0] - 0X20;
t->ccol = (t->num[1] == 0) ? t->lmargin : t->lmargin + t->num[1] - 0X20;
break;
case CUU:
if (t->crow > t->tmargin) {
t->crow = (t->num[0] == 0) ? t->crow-1 : max(t->crow-t->num[0], t->tmargin);
}
break;
case IND: /* index */
if (t->crow == t->bmargin) (*t->scroll)(t, t->lmargin, t->tmargin, t->rmargin, t->bmargin, t->att, 1);
else t->crow++;
break;
case NEL: /* next line */
if (t->crow == t->bmargin) (*t->scroll)(t, t->lmargin, t->tmargin, t->rmargin, t->bmargin, t->att, 1);
else t->crow++;
t->ccol = 0;
break;
case TRI: /* reverse index */
if (t->crow == t->tmargin) (*t->scroll)(t, t->lmargin, t->tmargin, t->rmargin, t->bmargin, t->att, -1);
else t->crow--;
break;
default:
#if XDEBUG
printf("Unrecognized term_cursor() command %d", cmd);
#endif
break;
}
(*t->cur_pos_)(t, t->ccol, t->crow);
}
/*
TV_DISPATCH_CTRL_ -- Deal with control characters sent from the host.
This function is used by all TELEVIDEO series terminals and
emulators.
*/
short tv_dispatch_ctrl_(TERMINAL *t, short ch)
{
short ret = 0;
#if XDEBUG
(*t->putc_)(ch, FG(t->att | 8), BG(t->att));
#endif
switch(ch) {
case BEL: /* BEL, sounds speaker */
set_sound_on(1175, 250);
break;
case BS: /* BS, moves cursor left */
if (t->ccol > t->lmargin) (*t->cur_pos_)(t, --t->ccol, t->crow);
break;
case LF:
if (t->crow < t->bmargin) (*t->cur_pos_)(t, t->ccol, ++t->crow);
else (*t->scroll)(t, t->lmargin, t->tmargin, t->rmargin, t->bmargin, t->att, 1);
break;
case VT: /* VT, move to next row */
if (t->crow) (*t->cur_pos)(t, CUU);
break;
case FF: /* CTRL-L move cursor right */
(*t->cur_pos)(t, CUF);
break;
case CR: /* CR, move to left margin */
(*t->cur_pos_)(t, 0, t->crow);
/* CHECK IF IN PRINTER CONTROLLER MODE */
break;
case SYN: /* CTRL-V move cursor down */
if (t->crow) (*t->cur_pos)(t, CUD);
break;
case SUB:
tv_erase_(t, ED);
break;
case RS: /* CTRL-^ sends cursor home */
(*t->cur_pos_)(t, 0, 0);
break;
case US:
(*t->con_putc)(t, ch, t->att);
/* CHECK IF IN PRINTER CONTROLLER MODE */
if (t->crow == t->bmargin) (*t->scroll)(t, t->lmargin, t->tmargin, t->rmargin, t->bmargin, t->att, 1);
else (*t->con_putc)(t, ch, t->att);
break;
case DEL: /* DEL, ignore on input */
break;
default:
break;
}
return (ret);
}
/*
TV_CUR_ATT_ -- Set the cursor attribute on TV terminals.
*/
void tv_cur_att_(TERMINAL *t, short cmd)
{
switch (cmd) {
case 0: /* cursor off */
(*t->cur_size_)(t, CURSIZE(0, 0));
break;
case 1: /* blinking block */
(*t->cur_size_)(t, CURSIZE(0, 7));
break;
case 2: /* steady block (not steady) */
(*t->cur_size_)(t, CURSIZE(0, 7));
break;
case 3: /* blinking underline */
(*t->cur_size_)(t, CURSIZE(6, 7));
break;
case 4: /* steady underline (not steady) */
(*t->cur_size_)(t, CURSIZE(6, 7));
break;
default:
#if XDEBUG
printf("Unrecognized term_erase() command %d", cmd);
#endif
break;
}
}
/*
TV_ERASE_ -- Generic function to handle several erase commands for TELEVIDEO
terminals.
*/
void tv_erase_(TERMINAL *t, short cmd)
{
short i = t->ccol, j = t->crow;
switch (cmd) {
case EBD: /* erase from start of display to active posn. */
(*t->ebd)(t, SP, t->d_att);
break;
case ECH:
(*t->ech)(t, SP, t->d_att, 1);
break;
case ED: /* ":" clear unprotected to NUL */
(*t->scroll)(t, 0, 0, t->d_cols, t->d_rows, SP, 0);
break;
case EED0: /* "Y" erase from active pos. to end of display (SP) */
(*t->eed)(t, SP, t->att);
break;
case EED1: /* "y" erase from active pos. to end of display (NUL) */
(*t->eed)(t, SP, t->att);
break;
case USER1: /* "*" erase all of display to NULs */
(*t->scroll)(t, 0, 0, t->d_cols, t->d_rows, t->d_att, 0);
memset(chbuf, NUL, sizeof(chbuf));
memset(attbuf, t->d_att, sizeof(attbuf));
(*t->cur_pos_)(t, 0, 0);
break;
case EL: /* "R" erase all of line */
(*t->eil)(t, SP, t->att);
break;
case EEL0: /* "T" erase from active pos. to EOL with SP */
(*t->eel)(t, SP, t->att);
for (;j <= t->rmargin; j++) {
attbuf[i][j] = (BYTE) t->att;
chbuf[i][j] = (BYTE) SP;
}
break;
case EEL1: /* "t" erase from active pos. to EOL with NULs */
(*t->eel)(t, NUL, t->att);
break;
case EBL: /* erase from start of line to active posn. */
(*t->ebl)(t, SP, t->d_att);
break;
default:
#if XDEBUG
printf("Unrecognized term_erase() command %d", cmd);
#endif
break;
}
}
/*
TV_PARSE_CMD_ -- Search forward through the the set of strings that may be
received from the host for the one in the command buffer.
Ignore parameter specifications ('%').
If the string is not found, return EOF, else return
*/
short tv_parse_cmd_(TERMINAL *t, const char *n)
{
short i, j, k;
TERM_RESPONSE *h = t->tr;
BYTE ch;
if (*n != '\0') {
for (i=0; i < MAX_TERM_CMDS; i++) {
if (h[i].sh2t[0] == '\0') continue;
for (j=0, k=0; j < MAX_PARM_LEN && k < MAX_PARM_LEN; j++, k++) {
#if 0
if (i == SGR && strchr(n, 'G'))
i = i;
#endif
ch = h[i].sh2t[j];
if (ch == '\0') return (i);
if (t->delim1) while (n[k] == (char) t->delim1 || n[k] == (char) t->csi) k++;
else while (n[k] == (char) t->csi) k++;
if (ch == '%' || ch == (BYTE) t->delim1) {
if (t->delim1) while (h[i].sh2t[j] == '%' || h[i].sh2t[j] == (char) t->delim1) j++;
else while (h[i].sh2t[j] == '%') j++;
if (t->delim1) while (isdigit(n[k]) || n[k] == (char) t->delim1) k++;
else while (isdigit(n[k])) k++;
}
if (h[i].sh2t[j] == n[k]) continue;
else break;
}
}
}
return (EOF);
}
/*
TV_PUTC_ -- Write a character and attribute to the screen under TVxxx
emulation.
Update screen image buffer.
Update attribute buffer.
*/
short tv_putc_(TERMINAL *t, short ch, short att)
{
/* BYTE oldatt; */
short i = t->crow, j = t->ccol;
att = att; /* nuke compiler warning */
chbuf[i][j] = (BYTE) ch;
probuf[i][j] = (BYTE) ((isprotected(t)) ? '\x1': '\0');
(*t->con_putc)(t, ch, attbuf[i][j]);
#if 0
if (i != 0 && j != 0) {
oldatt = * (&attbuf[i][j] - 1);
if (attbuf[i][j] != oldatt) tv_update_att_(t, oldatt);
}
#endif
return (0);
}
void tv_sgr_(TERMINAL *t)
{
short fc, bc;
short bright, reverse, blink, underscore; /* ATTRIBUTES */
WORD att;
blink = bright = reverse = underscore = FALSE;
fc = FG(t->d_att);
bc = BG(t->d_att);
switch (t->num[0]) {
case '0':
fc = FG(t->d_att); bc = BG(t->d_att);
bright = reverse = underscore = blink = FALSE;
break;
case '1':
fc = 0; bc = 0;
break;
case '2':
blink = TRUE;
break;
case '3': /* invisible blink */
blink = TRUE;
break;
case '4': /* reverse video */
reverse = TRUE;
break;
case '5': /* invisible reverse */
reverse = TRUE;
break;
case '6': /* reverse blink */
reverse = TRUE;
blink = TRUE;
break;
case '7': /* invisible reverse blink */
reverse = TRUE;
blink = TRUE;
break;
case '8':
underscore = TRUE;
break;
case '9': /* invisible underline */
underscore = TRUE;
break;
case ':': /* underline blink */
underscore = TRUE;
blink = TRUE;
break;
case ';': /* invisible underline blink */
underscore = TRUE;
blink = TRUE;
break;
case '<': /* underline reverse */
underscore = TRUE;
reverse = TRUE;
break;
case '=': /* invisible underline reverse */
underscore = TRUE;
reverse = TRUE;
break;
case '>': /* underline reverse blink */
underscore = TRUE;
reverse = TRUE;
blink = TRUE;
break;
case '?': /* invisible underline reverse blink */
underscore = TRUE;
reverse = TRUE;
blink = TRUE;
break;
case ')': /* half intensity on */
bright = FALSE;
break;
case '(': /* half intensity off */
bright = TRUE;
break;
default:
break;
}
if (reverse) {
fc = BG(t->d_att);
bc = FG(t->d_att);
}
if (bright) fc |= 0X08;
else fc &= 0X7;
if (blink) bc |= 0X08;
else bc &= 0X7;
if (underscore) fc |= 0X1;
att = ATT(fc, bc);
if (att != t->att) {
/* UPDATE SCREEN WITH NEW ATTRIBUTE */
t->att = 0; /* necessary to fix a TC v2.0 bug */
t->att = ATT(fc, bc); /* update terminal structure */
tv_update_att_(t, att);
}
(*t->con_putc)(t, SP, att);
if (++t->ccol <= t->rmargin) (*t->cur_pos_)(t, ++t->ccol, t->crow);
else (*t->cur_pos_)(t, 0, ++t->crow);
}
/*
TV_RPM_ -- Reset Televideo protect mode.
*/
void tv_rpm_(TERMINAL *t)
{
if (t->cmdbuf[1] == '(') t->mode &= ~ISPROTECTED;
if (t->cmdbuf[1] == '\'') t->mode &= ~INPROTECTMODE;
t->att = t->d_att; /* turn on intensity */
}
/*
TV_SPM_ -- Set Televideo protect mode.
*/
void tv_spm_(TERMINAL *t)
{
t = t; /* nuke compiler warning */
#if 0
if (t->cmdbuf[1] == ')') t->mode |= ISPROTECTED;
if (t->cmdbuf[1] == '&') t->mode |= INPROTECTMODE;
t->att &= ~0X8; /* turn off intensity */
#endif
}
short tv_update_att_(TERMINAL *t, short att)
{
BYTE oldatt;
WORD DONE;
short i = t->crow, j = t->ccol;
oldatt = attbuf[i][j];
DONE = FALSE;
for (;i <= t->bmargin && !DONE; i++) {
for (;j <= t->rmargin && !DONE; j++) {
if (!probuf[i][j]) {
(*t->con_put)(t, j, i, chbuf[i][j], att);
if (attbuf[i][j] != oldatt) DONE = TRUE;
attbuf[i][j] = (BYTE) att;
}
}
j = 0;
}
return (0);
}