/* 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 #endif #include #include #include #include #include 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); }