/* $Id: emulate.c,v 1.2 1997/11/26 02:34:57 jl8z Exp $ */ /* emulate.c -- key parsing for vt102/vt52/h19/etc emulation * * (C) Copyright 1988-1996 by Christopher J. Newman * All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Christopher J. Newman not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Christopher J. Newman makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT * SHALL CHRISTOPHER J. NEWMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. * * Author: Christopher J. Newman * Message: This is a nifty program. * * Doug's contribution: it * "What do you mean? The implementation of scroll bars is trivial." * * Tests to run on real terminals: * - does terminal reset clear saved character sets & styles. * - what does keypad app mode do when switching modes. * - character sets on vt52 & h19 with G0/G1 switching. * - check how setting separate leds with separate codes works * - is clear to end of screen etc. affected by scrolling region * - h19 controls in status line * - cursor vertical movement through double width line * - return on bottom line of display with scroll region bottom above that * * TODO: * - finish converting to new disp-> state variables. * - consider better raster view option. */ #include #include #include "nifty.h" #include "general.h" #include "emulate.h" #include "display.h" #include "term.h" /* for term_write() */ #include "option.h" #include "event.h" #include "siteconfig.h" #ifdef __STDC__ /* prototypes for our routines */ static void emulate_mode(long, long, long); static long decode_escapes(char); static void vtreport(void); static void vtstyle(long); #endif /* __STDC__ */ static char vt100attribs[] = "\033[?1;2c"; #ifdef MAC /* Macintosh specific shortcut */ #include "macnapp.h" #define itos(i) C(longtoPCstr(i)) #ifdef DEBUG #define EDEBUG(x) if (NAapp->debug[2]) NAdebug x #else #define EDEBUG(x) #endif #else #define EDEBUG(x) /* simple procedure to convert decimal number of * less than 20 digits to a string. */ #ifdef __STDC__ char *itos(long i) #else char *itos(i) long i; #endif { static char sbuf[21]; Boolean negflag; ulong val, ten = 10; char *pos = sbuf + sizeof (sbuf) - 1; char *posst; *pos = '\0'; posst = --pos; negflag = false; val = i; if (i < 0) { negflag = true; val = -i; } do { *pos-- = (char) (val % ten) + '0'; } while (val /= ten); if (negflag) { *pos-- = '-'; } return (++pos); } #endif /* cancel current escape mode, cleaning up any temp storage */ static void cancel_escape(disp) display *disp; { if (disp->titlebuf) { ev_free(disp->titlebuf); disp->titlebuf = NULL; } disp->esc = ESC_NONE; } /* (soft) reset the terminal emulator */ void emulate_reset() { display *disp = current_display; cancel_escape(disp); disp->curset = 0; disp->set[0] = ASCII_SET; disp->set[1] = ASCII_SET; disp->ansi_LNM = 0; disp->vtwrap = 0; disp->reportstate = 3; disp->insert = 0; disp->nowrap = 0; disp->origin = 0; disp->hidecrsr = 0; disp->softscroll = 0; disp->CRonLF = 0; disp->LFonCR = 0; disp->scrolltop = 0; disp->scrollrgn = 0; disp->keypad &= ~(KEYPAD_SHIFT | KEYPAD_APP | KEYPAD_CRSRMODE); dt_style(DT_SETSTYLE, PLAIN); dt_defaulttabs(); dt_invert(0); } /* set the current emulation mode */ #ifdef __STDC__ void emulate_set(display *disp, int newemu) #else void emulate_set(disp, newemu) display *disp; int newemu; #endif { disp->emulation = newemu; disp->keypad &= ~KEYPAD_VT52; disp->ansiwrap = 1; if (disp->emulation == EMU_VT100 || disp->emulation == EMU_VT102) { disp->ansiwrap = 0; } if (disp->emulation < EMU_VT100) { disp->keypad |= KEYPAD_VT52; } } /* different terminal modes */ #ifdef __STDC__ static void emulate_mode(long num, long privatem, long on) #else static void emulate_mode(num, privatem, on) long num, privatem, on; #endif { display *disp = current_display; switch (privatem) { case 0: /* standard ansi modes */ /* unimplemented modes: (!) -- available on VT220 * CRM - Control representation * EBM - Editing boundary * ERM - Erasure * FEAM - Format effector action * FETM - Format effector transfer * GATM - Guarded area transfer * HEM - Horizontal editing * KAM (2) - Keyboard action (!) * MATM - Multiple area transfer * PUM - Positioning unit * SATM - Selected area transfer * SRTM - Status reporting transfer * TSM - Tabulation stop * TTM - Transfer termination * VEM - Vertical editing * SRM (12) - Send/Receive (!) */ switch (num) { case 4: /* ANSI IRM (insert/replacement) mode (vt102) */ disp->insert = on; break; case 20: /* ANSI LNM (linefeed/newline) mode */ disp->ansi_LNM = on; break; } break; case 1: /* vt100 privatem modes */ /* unimplemented modes: * DECINLM (9) - interlace mode (I doubt this will ever be practical) */ switch (num) { case 1: /* DECCKM -- Cursor key application mode */ disp->keypad &= ~KEYPAD_CRSRMODE; if (on) disp->keypad |= KEYPAD_CRSRMODE; break; case 2: /* DECANM -- enter VT52 mode * going to H19 mode is added for H19 support */ emulate_set(disp, on ? EMU_H19 : EMU_VT52); break; case 3: /* DECCOLM -- 80/132 column mode */ ev_setsize(on ? 132 : 80, 0); break; case 4: /* DECSCLM -- soft scroll on/off */ disp->softscroll = on; break; case 5: /* DECSCNM -- reverse video display */ dt_invert(on); break; case 6: /* DECOM -- origin mode */ EDEBUG(("Origin mode: %d\r", on)); disp->origin = on; dt_cursorto(0, 0); break; case 7: /* DECAWM -- wrap mode */ disp->nowrap = !on; break; case 8: /* DECARM -- auto-repeat mode */ ev_keyrepeat(on); break; case 25: /* DECTCEM -- hide/show cursor (vt220) */ disp->hidecrsr = !on; break; } break; case 2: /* h19 privatem modes */ /* modes not implemented: * 3 - hold screen mode */ switch (num) { #if STATUS_SUPPORT case 1: /* 25th line status */ dt_statusline(on); break; #endif case 2: /* keyclick on/off */ ev_keyclick(!on); break; case 4: /* underline/block cursor */ disp->cursor = on ? BLOCK : UNDERSCORE; break; case 5: /* invisible/visible cursor */ disp->hidecrsr = on; break; case 6: /* keypad shifted/non-shifted mode */ disp->keypad &= ~KEYPAD_SHIFT; if (on) disp->keypad |= KEYPAD_SHIFT; break; case 7: /* keypad application mode */ disp->keypad &= ~KEYPAD_APP; if (on) disp->keypad |= KEYPAD_APP; break; case 8: /* auto linefeed on CR */ disp->LFonCR = on; break; case 9: /* auto CR on linefeed */ disp->CRonLF = on; break; } break; } } /* handle escape sequences */ #ifdef __STDC__ static long decode_escapes(char c) #else static long decode_escapes(c) char c; #endif { #if RASTER_HACK static uchar *raster = NULL; static long rows, cols, rastpos; #endif display *disp = current_display; long i; char smallbuf[20]; char *cpos; long tempx, tempy; style tstyle; EDEBUG(("Escape char: %c %02x\r", isprint(c) ? c : ' ', (int)(unsigned char)c)); switch (disp->esc) { case ESC_VT102: /* escape key just pressed */ switch (c) { case '[': /* ANSI sequence prefix */ for (i = 0; i <= ANSI_ARGS; i++) disp->arg[i] = 0; disp->esc = ESC_ANSI; disp->privatem = ANSI_OPTION; return (0); case ']': /* xterm titlebar hack */ disp->esc = ESC_XTERM; return (0); case '#': /* DEC privatem line width modes */ disp->esc = ESC_DEC; return (0); case '(': /* SCS: select character set -- for disp->set[0] set */ disp->esc = ESC_SCS1; return (0); case ')': /* SCS: select character set -- for disp->set[1] set */ disp->esc = ESC_SCS2; return (0); case '=': /* DECKPAM: keypad application mode */ disp->keypad |= KEYPAD_APP; break; case '>': /* DECKPNM: keypad numeric mode */ disp->keypad &= ~KEYPAD_APP; break; case 'D': /* IND (index): cursor down with scroll forward */ dt_movecursor(DT_INDEX, 1); break; case 'E': /* NEL (next line): proper return */ dt_movecursor(DT_NEWLINE, 1); break; case 'H': /* HTS horizontal tabulation set */ dt_tabset(); break; case 'M': /* RI (reverse index): cursor up with scroll reverse */ dt_movecursor(DT_RINDEX, 1); break; case 'Z': /* DECID identify terminal */ term_write(vt100attribs, sizeof (vt100attribs) - 1); break; case '7': /* DECSC save cursor position (DEC privatem) */ dt_movecursor(DT_SAVEPOS, 2); disp->savecurset = disp->curset; disp->saveset[0] = disp->set[0]; disp->saveset[1] = disp->set[1]; break; case '8': /* DECRC restore cursor position (DEC privatem) */ dt_movecursor(DT_RESTOREPOS, 2); disp->curset = disp->savecurset; disp->set[0] = disp->saveset[0]; disp->set[1] = disp->saveset[1]; break; case 'c': /* RIS reset to initial state */ emulate_reset(); break; } break; case ESC_ANSI: /* escape [ foo character */ case ESC_XTERM: /* escape ] foo ; */ switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': disp->arg[disp->curarg] *= 10; disp->arg[disp->curarg] += c - '0'; return (0); case '?': /* vt100 ansi mode privatem codes */ disp->privatem = VT100_OPTION; return (0); case '>': /* h19 ansi mode privatem codes */ disp->privatem = H19_OPTION; return (0); case ';': /* get next parameter */ if (disp->esc == ESC_XTERM) { disp->esc = ESC_XTITLE; disp->titlebuf = ev_malloc(MAX_TITLEBUF + 2); disp->curarg = 0; } else if (disp->curarg < ANSI_ARGS) { disp->arg[++disp->curarg] = 0; } return (0); #if RASTER_HACK case ']': /* view raster */ rows = disp->arg[1]; cols = disp->arg[0]; if (disp->curarg == 1 && raster == NULL) { raster = (uchar *) ev_malloc((rows * ((cols + 31) >> 5)) << 2); rastpos = 0; disp->esc = ESC_RASTER; return (0); } break; #endif case 'F': /* CPL cursor previous line */ dt_movecursor(DT_FROMLEFT, 1); case 'A': /* CUU cursor up */ dt_movecursor(DT_UP, disp->arg[0]); break; case 'E': /* CNL cursor next line */ dt_movecursor(DT_FROMLEFT, 1); case 'B': /* CUD cursor down */ dt_movecursor(DT_DOWN, disp->arg[0]); break; case 'C': /* CUF Cursor Forward */ case 'a': /* HPR Horizontal Position Relative */ dt_movecursor(DT_RIGHT, disp->arg[0]); break; case 'D': /* CUB Cursor Backward */ dt_movecursor(DT_LEFT, disp->arg[0]); break; case 'G': /* CHA Cursor Horizontal Absolute */ dt_movecursor(DT_FROMLEFT, disp->arg[0]); break; case 'H': case 'f': /* move cursor to specific position. CUP, HVP */ if (disp->arg[0]) disp->arg[0]--; if (disp->arg[1]) disp->arg[1]--; dt_cursorto(disp->arg[1], disp->arg[0]); break; case 'I': /* CHT - Cursor Horizontal Forward Tabulation */ dt_movecursor(DT_TAB, disp->arg[0]); break; case 'J': /* ED clear to end of display. (erase in display) */ switch (disp->arg[0]) { case 0: dt_clear(DT_CLRTOEOS); break; case 1: dt_clear(DT_CLRTOBOS); break; case 2: dt_clearscreen(); break; } break; case 'K': /* EL clear to end of line. (erase in line) */ switch (disp->arg[0]) { case 0: dt_clear(DT_CLRTOEOL); break; case 1: dt_clear(DT_CLRTOBOL); break; case 2: dt_clear(DT_CLRLINE); break; } break; case 'L': /* IL insert line VT102 */ dt_insertlines(disp->arg[0]); break; case 'M': /* DL delete line VT102 */ dt_deletelines(disp->arg[0]); break; case 'P': /* DCH delete character (VT102) */ dt_deletechars(0, disp->arg[0]); break; case 'X': /* ECH Erase Character VT4xx */ dt_erase(disp->curx, disp->curx + disp->arg[0]); break; case 'Z': /* CBT: backwards tabulation */ dt_movecursor(DT_BACKTAB, disp->arg[0]); break; case '@': /* ICH ansi insert character (VT102) */ dt_insertchars(disp->arg[0]); break; case 'c': /* DA1 Device Attributes request */ if (disp->arg[0] == 0) { term_write(vt100attribs, sizeof (vt100attribs) - 1); } break; case 'g': /* TBC tabulation clear */ for (i = 0; i <= disp->curarg; i++) switch (disp->arg[i]) { case 0: dt_tabclear(); break; case 3: dt_cleartabs(); break; } break; case 'h': /* SM set terminal mode */ for (i = 0; i <= disp->curarg; i++) { emulate_mode(disp->arg[i], disp->privatem, 1); } break; case 'l': /* RM reset terminal mode */ for (i = 0; i <= disp->curarg; i++) { emulate_mode(disp->arg[i], disp->privatem, 0); } break; case 'm': /* SGR styles (select graphic rendition) */ for (i = 0; i <= disp->curarg; i++) { vtstyle(disp->arg[i]); } break; case 'n': /* DSR Device status report */ for (i = 0; i <= disp->curarg; i++) switch (disp->arg[i]) { case 5: term_write("\033[0n", 4); break; case 6: tempx = disp->curx; tempy = disp->cury; if (disp->origin) tempy -= disp->scrolltop; if (tempx == 0 && tempy == 0) { term_write("\033[R", 3); } else { smallbuf[0] = '\033'; smallbuf[1] = '['; (void) strcpy(smallbuf + 2, itos((long) (tempy + 1))); cpos = smallbuf + strlen(smallbuf); *cpos++ = ';'; (void) strcpy(cpos, itos((long) (tempx + 1))); cpos += strlen(cpos); *cpos = 'R'; term_write(smallbuf, cpos - smallbuf + 1); } break; } break; #if LED_SUPPORT case 'q': /* DECLL set LEDs on keyboard */ { int leds = 0; for (i = 0; i <= disp->curarg; i++) { if (!disp->arg[i]) { leds = 0; } else if (disp->arg[i] <= 4) { leds |= 1 << (disp->arg[i] - 1); } } ev_leds(leds); } break; #endif case 'r': /* DECSTBM set top and bottom margins (scrolling range) */ EDEBUG(("Scroll Region: top: %d, bottom: %d\r", disp->arg[0], disp->arg[1])); dt_setscroll(disp->arg[0], disp->arg[1]); break; case 'x': /* DECREQTPARM Request Terminal Parameters */ if (disp->arg[0] < 2) { disp->reportstate = 2 + disp->arg[0]; vtreport(); } break; case '`': /* HPA Horizontal Position Absolute */ dt_movecursor(DT_FROMLEFT, disp->arg[0]); break; } break; case ESC_DEC: /* dec privatem codes for fonts */ switch(c) { case '3': dt_linewidth(TOPHALF); break; case '4': dt_linewidth(BOTHALF); break; case '5': dt_linewidth(PLAIN); break; case '6': dt_linewidth(WIDE); break; case '8': dt_testscreen('E'); break; } break; case ESC_SCS1: case ESC_SCS2: /* SCS: select character set: ESC( or ESC) */ switch (c) { case 'A': case 'B': case '1': /* change to UK/US/other ROM set */ disp->set[disp->esc - ESC_SCS1] = c == 'A' ? UK_SET : ASCII_SET; if (disp->esc - ESC_SCS1 == disp->curset) { dt_style(DT_STYLEOFF, GRAPHIC); /*NOTE: worry about UK_SET */ } break; case '0': case '2': /* change to graphic set/graphic ROM set */ disp->set[disp->esc - ESC_SCS1] = ALT_SET; if (disp->esc - ESC_SCS1 == disp->curset) { dt_style(DT_STYLEON, GRAPHIC); /*NOTE: no UK_SET */ } break; default: disp->esc = ESC_NONE; return (1); } break; #if RASTER_HACK case ESC_RASTER: /* read in a raster */ if (raster != NULL) { raster[rastpos] = disp->privatem ? c : ~c; } if (++rastpos == rows * (((cols + 31) >> 5) << 2)) { disp->esc = 0; if (raster != NULL) { dt_raster((ulong *) raster, rows, cols); ev_free((char *) raster); raster = NULL; } } return (0); #endif case ESC_VT52: /* VT52 emulation -- ESC just hit */ switch (c) { case 'A': /* cursor up */ dt_movecursor(DT_UP, 1); break; case 'B': /* cursor down */ dt_movecursor(DT_DOWN, 1); break; case 'C': /* cursor right */ dt_movecursor(DT_RIGHT, 1); break; case 'D': /* cursor left */ dt_movecursor(DT_LEFT, 1); break; case 'F': /* alternate characters */ dt_style(DT_STYLEON, GRAPHIC); break; case 'G': /* standard characters */ dt_style(DT_STYLEOFF, GRAPHIC); break; case 'H': /* home cursor */ dt_cursorto(0, 0); break; case 'I': /* reverse line feed */ dt_movecursor(DT_RINDEX, 1); break; case 'J': /* erase to end of screen */ dt_clear(DT_CLRTOEOS); break; case 'K': /* erase to end of line */ dt_clear(DT_CLRTOEOL); break; case 'Y': /* move cursor to specific position */ disp->esc = ESC_POSY; return (0); case 'Z': /* Identify terminal sequence */ term_write("\033/Z", 3); /* VT100 emulating a VT52 */ break; case '=': /* Enter alternate keypad mode */ disp->keypad |= KEYPAD_APP; break; case '>': /* Exit alternate keypad mode */ disp->keypad &= ~KEYPAD_APP; break; case '<': /* switch to ANSI mode */ emulate_set(disp, EMU_VT102); break; } break; case ESC_POSY: disp->arg[0] = (c & 0x7f) - ' '; disp->esc = ESC_POSX; return (0); case ESC_POSX: disp->arg[1] = (c & 0x7f) - ' '; dt_cursorto(disp->arg[1], disp->arg[0]); break; case ESC_H19: /* H19 emulation -- ESC just hit */ /* here is a list of unimplemented escapes: * [ enter hold screen mode (implemented as ansi codes) * \ exit hold screen mode * } inhibit keyboard output * { enable keyboard output * ] Transmit 25th line * # Transmit page * r Set baud rate */ switch (c) { case 'A': /* HCUU: cursor up */ dt_movecursor(DT_UP, 1); break; case 'B': /* HCUD: cursor down */ dt_movecursor(DT_DOWN, 1); break; case 'C': /* HCUF: cursor right */ dt_movecursor(DT_RIGHT, 1); break; case 'D': /* HCUB: cursor left */ dt_movecursor(DT_LEFT, 1); break; case 'E': /* HCD: clear screen */ dt_clearscreen(); break; case 'F': /* HEGM: alternate characters */ dt_style(DT_STYLEON, GRAPHIC); break; case 'G': /* HXGM: standard characters */ dt_style(DT_STYLEOFF, GRAPHIC); break; case 'H': /* HCUH: home cursor */ dt_cursorto(0, 0); break; case 'I': /* HRI: reverse line feed */ dt_movecursor(DT_RINDEX, 1); break; case 'J': /* HEOP: erase to end of screen */ dt_clear(DT_CLRTOEOS); break; case 'K': /* HEOL: erase to end of line */ dt_clear(DT_CLRTOEOL); break; case 'L': /* HIL: add new blank line */ dt_insertlines(1); break; case 'M': /* HDL: delete line */ dt_deletelines(1); break; case 'N': /* HDCH: delete character */ dt_deletechars(0, 1); break; case 'O': /* HERM: end insert mode */ disp->insert = 0; break; case 'Y': /* HDCA: move cursor to specific position */ disp->esc = ESC_POSY; return (0); case 'Z': /* HID: Identify terminal sequence */ term_write("\033/K", 3); /* can be vt52 */ break; case '@': /* HEIM: begin insert mode */ disp->insert = 1; break; case '[': /* ANSI controls for fun */ for (i=0; i<= ANSI_ARGS; i++) disp->arg[i]=0; disp->esc = ESC_ANSI; disp->privatem = ANSI_OPTION; return (0); case '=': /* HAKM: enter alternate keypad mode */ disp->keypad |= KEYPAD_APP; break; case '>': /* HXAM: exit alternate keypad mode */ disp->keypad &= ~KEYPAD_APP; case '<': /* ZEAM: switch to ANSI mode */ emulate_set(disp, EMU_ANSI); break; case '-': /* ZCBT: z29 backwards tabulation */ dt_movecursor(DT_BACKTAB, 1); break; case '.': /* z29 tab set/reset prefix */ disp->esc = ESC_TABSET; return (0); case 'b': /* HBD: erase to start of screen */ dt_clear(DT_CLRTOBOS); break; case 'i': /* ZRTT: request terminal type */ disp->esc = ESC_TERMTYPE; return (0); case 'j': /* HSCP: save cursor position */ dt_movecursor(DT_SAVEPOS, 1); break; case 'k': /* HRCP: restore cursor position */ dt_movecursor(DT_RESTOREPOS, 1); break; case 'l': /* HEL: erase the current line */ dt_clear(DT_CLRLINE); break; case 'n': /* HCPR: report cursor position */ smallbuf[0] = '\033'; smallbuf[1] = 'Y'; smallbuf[2] = disp->cury + ' '; smallbuf[3] = disp->curx + ' '; term_write(smallbuf, 4); break; case 'o': /* HEBL: erase to the beginning of the line */ dt_clear(DT_CLRTOBOL); break; case 'p': /* HERV: begin stand out mode */ dt_style(DT_STYLEON, INVERSE); break; case 'q': /* HXRV: end stand out mode */ dt_style(DT_STYLEOFF, INVERSE); break; case 's': /* ZSA -- z29 set attribute */ disp->esc = ESC_SETATTRIB; return (0); case 't': /* HEKS: enter shifted keypad mode */ disp->keypad |= KEYPAD_SHIFT; break; case 'u': /* HXKS: exit shifted keypad mode */ disp->keypad &= ~KEYPAD_SHIFT; break; case 'v': /* HEWA: wrap mode on */ disp->nowrap = 0; break; case 'w': /* HXWA: wrap mode off */ disp->nowrap = 1; break; case 'x': /* HSM: set mode */ disp->esc = ESC_SETMODE; return (0); case 'y': /* HRM: reset mode */ disp->esc = ESC_CLRMODE; return (0); case 'z': /* HRAM: reset to power-up config */ emulate_reset(); break; } break; case ESC_SETMODE: case ESC_CLRMODE: emulate_mode(c - '0', 2, disp->esc == ESC_SETMODE); break; case ESC_TABSET: switch (c) { case '0': /* ZCTCP: clear tab at current position */ dt_tabclear(); break; case '3': /* ZCAT: clear all tabs */ dt_cleartabs(); break; case '8': /* ZSTCP: set tab at current position */ dt_tabset(); break; } break; case ESC_SETATTRIB: tstyle = PLAIN; if (c & 1) tstyle |= INVERSE; if (c & 2) tstyle |= BLINK; if (c & 4) tstyle |= HALFBRITE; if (c & 8) tstyle |= UNDERLINE; if (c & 16) tstyle |= GRAPHIC; dt_style(DT_SETSTYLE, tstyle); break; case ESC_TERMTYPE: if (c == '0') term_write("\033iB0", 4); break; case ESC_XTITLE: if (isprint(c) && disp->curarg < MAX_TITLEBUF) { disp->titlebuf[disp->curarg++] = c; return (0); } cancel_escape(disp); break; } return (disp->esc = ESC_NONE); } /* output characters to display * the buffer text must have at least one extra byte after text+count */ #define FLUSHBUF if (front < text) { dt_puts(front, text - front); } front = text + 1; #ifdef __STDC__ void emulate_write(char *text, long count) #else void emulate_write(text, count) char *text; long count; #endif { display *disp = current_display; char c; char *textend = text + count; char *front; if (disp->logtofile) { ev_logstring(disp,text,count); } for (front = text; text < textend; text++) { /* check for escape sequences */ c = *text; if (disp->esc && (!iscntrl(c) || disp->esc == ESC_RASTER)) { disp->vtwrap = 0; if (!decode_escapes(c)) front++; continue; } /* filter high bit */ if (c & 0x80) *text = (c &= ~0x80); /* check for control characters */ if (iscntrl(c)) { disp->vtwrap = 0; FLUSHBUF; switch (c) { case CTRL('E'): if (disp->answerlen) { term_write(disp->answerback, disp->answerlen); } break; case CTRL('G'): /* BEL: warning bell */ if (disp->esc == ESC_XTITLE) { disp->titlebuf[disp->curarg] = '\0'; if (disp->curarg) { do_option(disp, SYS_WINTITLE, OP_SETCUR, (Optype *) &disp->titlebuf); } cancel_escape(disp); break; } dt_bell(); break; case CTRL('H'): /* BS: backspace */ dt_movecursor(DT_BACKSPACE, 1); break; case CTRL('I'): /* HT: tab */ dt_movecursor(DT_TAB, 1); break; case CTRL('M'): /* CR / newline */ dt_movecursor(DT_FROMLEFT, 1); if (disp->LFonCR) { dt_movecursor(DT_INDEX, 1); } break; case CTRL('J'): /* LF: Linefeed */ case CTRL('K'): /* VT: Vertical tabulation -- treated as LF */ case CTRL('L'): /* FF: Form Feed -- treated as LF */ if (disp->CRonLF || disp->ansi_LNM) { dt_movecursor(DT_FROMLEFT, 1); } dt_movecursor(DT_INDEX, 1); break; case CTRL('N'): /* SI -- shift in alternate */ disp->curset = 1; if (disp->set[1] == ALT_SET || disp->emulation == EMU_VT52) { dt_style(DT_STYLEON, GRAPHIC); } else { dt_style(DT_STYLEOFF, GRAPHIC); } /*XXX: worry about UK_SET */ break; case CTRL('O'): /* SO -- shift out alternate */ disp->curset = 0; if (disp->set[0] == ALT_SET && disp->emulation != EMU_VT52) { dt_style(DT_STYLEON, GRAPHIC); } else { dt_style(DT_STYLEOFF, GRAPHIC); } /*XXX: worry about UK_SET */ break; case CTRL('X'): /* CAN: cancel escape sequence */ case CTRL('Z'): /* SUB: (substitute) interpret as CAN */ cancel_escape(disp); break; case ESC: /* escape key */ switch (disp->emulation) { case EMU_ANSI: case EMU_VT102: case EMU_VT100: disp->esc = ESC_VT102; break; case EMU_VT52: disp->esc = ESC_VT52; break; case EMU_H19: disp->esc = ESC_H19; break; } disp->curarg = 0; break; } } } FLUSHBUF; } /* send a DECREPTPARM report */ static void vtreport() { char report[20]; (void) strcpy(report, "\033[0;1;1;88;88;1;0x"); report[2] = '0' + current_display->reportstate; term_write(report, strlen(report)); } /* arguments for the style commands: SGR -- ESC [ param ; .. ; m */ #ifdef __STDC__ static void vtstyle(long c) #else static void vtstyle(c) long c; #endif { switch (c) { case 1: dt_style(DT_STYLEON, BOLD); break; case 22: dt_style(DT_STYLEOFF, BOLD); break; case 2: dt_style(DT_STYLEON, HALFBRITE); break; case 3: dt_style(DT_STYLEON, ITALIC); break; case 23: dt_style(DT_STYLEOFF, ITALIC); break; case 4: dt_style(DT_STYLEON, UNDERLINE); break; case 24: dt_style(DT_STYLEOFF, UNDERLINE); break; case 5: dt_style(DT_STYLEON, BLINK); break; case 25: dt_style(DT_STYLEOFF, BLINK); break; case 7: dt_style(DT_STYLEON, INVERSE); break; case 27: dt_style(DT_STYLEOFF, INVERSE); break; case 8: dt_style(DT_STYLEON, BLANK); break; case 28: dt_style(DT_STYLEON, BLANK); break; case 0: dt_style(DT_STYLEOFF, ITALIC | BOLD | HALFBRITE | UNDERLINE | BLINK | INVERSE | BLANK); break; case 10: dt_style(DT_STYLEON, GRAPHIC); break; case 11: dt_style(DT_STYLEOFF, GRAPHIC); break; } }