Metropoli BBS
VIEWER: tv925.c MODE: TEXT (ASCII)
/*
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);
}

[ RETURN TO DIRECTORY ]