You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

803 lines
35 KiB

/* ------------------------------------------------------------------------- */
/* */
/* [vt102emu.cpp] VT102 Terminal Emulation */
/* */
/* ------------------------------------------------------------------------- */
/* */
/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */
/* */
/* This file is part of Konsole - an X terminal for KDE */
/* */
/* ------------------------------------------------------------------------- */
/* \class
This class is responsible to scan the escapes sequences of the terminal
emulation and to map it to their corresponding semantic complements.
Thus this module knows mainly about decoding escapes sequences and
is a stateless device w.r.t. the semantics.
It is also responsible to refresh the TEWidget by certain rules.
\sa TEWidget \sa TEScreen
*/
/* FIXME
- For strange reasons, the extend of the rendition attributes ranges over
all screens and not over the actual screen. We have to find out the
precise extend.
*/
//NOTE: search for 'NotImplemented' and IGNORED to find unimplemented features.
//TODO: we have no means yet, to change the emulation on the fly.
#include "TEmuVt102.h"
#include "TEWidget.h"
#include "TEScreen.h"
#include <stdio.h>
#include <unistd.h>
#include <qkeycode.h>
#include <assert.h>
#include "TEmuVt102.moc"
#define ESC 27
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define HERE printf("%s(%d): here\n",__FILE__,__LINE__)
/* ------------------------------------------------------------------------- */
/* */
/* Emulation */
/* */
/* ------------------------------------------------------------------------- */
#define CNTL(c) ((c)-'@')
/*!
*/
int maxHistLines = 100;
//#define MAXHISTLINES 100 // natural constant for now.
VT102Emulation::VT102Emulation(TEWidget* gui, const char* term) : Emulation(gui)
{
screen[0] = scr;
screen[0]->setHistMaxLines(maxHistLines);
screen[1] = new TEScreen(gui->Lines(),gui->Columns());
// note that the application screen has not history buffer.
QObject::connect(gui,SIGNAL(mouseSignal(int,int,int)),
this,SLOT(onMouse(int,int,int)));
tableInit();
resetTerminal();
setMode(MODE_BsHack);
emulation = term;
}
void VT102Emulation::resetTerminal()
{
reset();
resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000);
resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys);
resetMode(MODE_AppScreen); saveMode(MODE_AppScreen);
resetMode(MODE_NewLine);
setMode(MODE_Ansi);
screen[0]->reset();
screen[1]->reset();
}
/*!
*/
VT102Emulation::~VT102Emulation()
{
scr = screen[0];
delete screen[1];
}
void VT102Emulation::onImageSizeChange(int lines, int columns)
{
if (scr != screen[0]) screen[0]->resizeImage(lines,columns);
if (scr != screen[1]) screen[1]->resizeImage(lines,columns);
Emulation::onImageSizeChange(lines,columns);
}
void VT102Emulation::NewLine()
{
scr->NewLine(); bulkNewline();
}
void VT102Emulation::setColumns(int columns)
{
emit changeColumns(columns); // this goes strange ways
}
// Interpreting Codes ---------------------------------------------------------
/*
This section deals with decoding the incoming character stream.
Decoding means here, that the stream is first seperated into `tokens'
which are then mapped to a `meaning' provided as operations by the
`Screen' class.
The tokens are defined below. They are:
- CHR - Printable characters (32..255 but DEL (=127))
- CTL - Control characters (0..31 but ESC (= 27), DEL)
- ESC - Escape codes of the form <ESC><CHR but `[]()+*#'>
- ESC_DE - Escape codes of the form <ESC><any of `()+*#'> C
- CSI_PN - Escape codes of the form <ESC>'[' {Pn} ';' {Pn} C
- CSI_PS - Escape codes of the form <ESC>'[' {Pn} ';' ... C
- CSI_PR - Escape codes of the form <ESC>'[' '?' {Pn} ';' ... C
- VT52 - VT52 escape codes
- <ESC><Chr>
- <ESC>'Y'{Pc}{Pc}
- XTE_HA - Xterm hacks <ESC>`]' {Pn} `;' {Text} <BEL>
note that this is handled differently
The last two forms allow list of arguments. Since the elements of
the lists are treated individually the same way, they are passed
as individual tokens to the interpretation. Further, because the
meaning of the parameters are names (althought represented as numbers),
they are includes within the token ('N').
*/
#define TY_CONSTR(T,A,N) ( ((((int)N) & 0xffff) << 16) | ((((int)A) & 0xff) << 8) | (((int)T) & 0xff) )
#define TY_CHR___( ) TY_CONSTR(0,0,0)
#define TY_CTL___(A ) TY_CONSTR(1,A,0)
#define TY_ESC___(A ) TY_CONSTR(2,A,0)
#define TY_ESC_CS( ) TY_CONSTR(3,0,0)
#define TY_ESC_DE(A ) TY_CONSTR(4,A,0)
#define TY_CSI_PS(A,N) TY_CONSTR(5,A,N)
#define TY_CSI_PN(A ) TY_CONSTR(6,A,0)
#define TY_CSI_PR(A,N) TY_CONSTR(7,A,N)
#define TY_VT52__(A ) TY_CONSTR(8,A,0)
//FIXME: include recognition of remaining VT100 codes.
// this are printing modes, ESC[{ps}i (printing) and VT52 printing.
void VT102Emulation::tau( int code, int p, int q )
{
//scan_buffer_report();
//if (code == TY_CHR___()) printf("%c",p); else
//printf("tau(%d,%d,%d, %d,%d)\n",(code>>0)&0xff,(code>>8)&0xff,(code>>16)&0xffff,p,q);
switch (code)
{
case TY_CHR___( ) : scr->ShowCharacter (p ); break; //VT100
//FIXME: 127 DEL : ignored on input?
case TY_CTL___(CNTL('@')) : /* NUL: ignored */ break;
case TY_CTL___(CNTL('A')) : /* SOH: ignored */ break;
case TY_CTL___(CNTL('B')) : /* STX: ignored */ break;
case TY_CTL___(CNTL('C')) : /* ETX: ignored */ break;
case TY_CTL___(CNTL('D')) : /* EOT: ignored */ break;
case TY_CTL___(CNTL('E')) : reportAnswerBack ( ); break; //VT100
case TY_CTL___(CNTL('F')) : /* ACK: ignored */ break;
case TY_CTL___(CNTL('G')) : gui->Bell ( ); break; //VT100
case TY_CTL___(CNTL('H')) : scr->BackSpace ( ); break; //VT100
case TY_CTL___(CNTL('I')) : scr->Tabulate ( ); break; //VT100
case TY_CTL___(CNTL('J')) : NewLine ( ); break; //VT100
case TY_CTL___(CNTL('K')) : NewLine ( ); break; //VT100
case TY_CTL___(CNTL('L')) : NewLine ( ); break; //VT100
case TY_CTL___(CNTL('M')) : scr->Return ( ); break; //VT100
case TY_CTL___(CNTL('N')) : scr->useCharset ( 1); break; //VT100
case TY_CTL___(CNTL('O')) : scr->useCharset ( 0); break; //VT100
case TY_CTL___(CNTL('P')) : /* DLE: ignored */ break;
case TY_CTL___(CNTL('Q')) : /* DC1: FIXME: XON continue */ break; //VT100
case TY_CTL___(CNTL('R')) : /* DC2: ignored */ break;
case TY_CTL___(CNTL('S')) : /* DC3: XOFF halt */ break; //VT100
case TY_CTL___(CNTL('T')) : /* DC4: ignored */ break;
case TY_CTL___(CNTL('U')) : /* NAK: ignored */ break;
case TY_CTL___(CNTL('V')) : /* SYN: ignored */ break;
case TY_CTL___(CNTL('W')) : /* ETB: ignored */ break;
case TY_CTL___(CNTL('X')) : scr->ShowCharacter ( 2); break; //VT100
case TY_CTL___(CNTL('Y')) : /* EM : ignored */ break;
case TY_CTL___(CNTL('Z')) : scr->ShowCharacter ( 2); break; //VT100
case TY_CTL___(CNTL('[')) : /* ESC: cannot be seen here. */ break;
case TY_CTL___(CNTL('\\')): /* FS : ignored */ break;
case TY_CTL___(CNTL(']')) : /* GS : ignored */ break;
case TY_CTL___(CNTL('^')) : /* RS : ignored */ break;
case TY_CTL___(CNTL('_')) : /* US : ignored */ break;
case TY_ESC___('D' ) : scr->index ( ); break; //VT100
case TY_ESC___('E' ) : scr->NextLine ( ); break; //VT100
case TY_ESC___('H' ) : scr->changeTabStop (TRUE ); break; //VT100
case TY_ESC___('M' ) : scr->reverseIndex ( ); break; //VT100
case TY_ESC___('Z' ) : reportTerminalType ( ); break;
case TY_ESC___('c' ) : resetTerminal ( ); break;
case TY_ESC___('n' ) : scr->useCharset ( 2); break;
case TY_ESC___('o' ) : scr->useCharset ( 3); break;
case TY_ESC___('7' ) : scr->saveCursor ( ); break;
case TY_ESC___('8' ) : scr->restoreCursor ( ); break;
case TY_ESC___('=' ) : setMode (MODE_AppKeyPad); break;
case TY_ESC___('>' ) : resetMode (MODE_AppKeyPad); break;
case TY_ESC___('<' ) : setMode (MODE_Ansi ); break; //VT100
case TY_ESC_CS( ) : setCharset (p-'(', q); break; //VT100
case TY_ESC_DE('3' ) : /* IGNORED: double high, top half */ break;
case TY_ESC_DE('4' ) : /* IGNORED: double high, bottom half */ break;
case TY_ESC_DE('5' ) : /* IGNORED: single width, single high*/ break;
case TY_ESC_DE('6' ) : /* IGNORED: double width, single high*/ break;
case TY_ESC_DE('8' ) : scr->helpAlign ( ); break;
case TY_CSI_PS('K', 0) : scr->clearToEndOfLine ( ); break;
case TY_CSI_PS('K', 1) : scr->clearToBeginOfLine ( ); break;
case TY_CSI_PS('K', 2) : scr->clearEntireLine ( ); break;
case TY_CSI_PS('J', 0) : scr->clearToEndOfScreen ( ); break;
case TY_CSI_PS('J', 1) : scr->clearToBeginOfScreen ( ); break;
case TY_CSI_PS('J', 2) : scr->clearEntireScreen ( ); break;
case TY_CSI_PS('g', 0) : scr->changeTabStop (FALSE ); break; //VT100
case TY_CSI_PS('g', 3) : scr->clearTabStops ( ); break; //VT100
case TY_CSI_PS('h', 4) : scr-> setMode (MODE_Insert ); break;
case TY_CSI_PS('h', 20) : setMode (MODE_NewLine ); break;
case TY_CSI_PS('i', 0) : /* */ break; //VT100
case TY_CSI_PS('l', 4) : scr-> resetMode (MODE_Insert ); break;
case TY_CSI_PS('l', 20) : resetMode (MODE_NewLine ); break;
case TY_CSI_PS('m', 0) : scr->setDefaultRendition ( ); break;
case TY_CSI_PS('m', 1) : scr-> setRendition (RE_BOLD ); break; //VT100
case TY_CSI_PS('m', 4) : scr-> setRendition (RE_UNDERLINE); break; //VT100
case TY_CSI_PS('m', 5) : scr-> setRendition (RE_BLINK ); break; //VT100
case TY_CSI_PS('m', 7) : scr-> setRendition (RE_REVERSE ); break;
case TY_CSI_PS('m', 10) : /* IGNORED: mapping related */ break; //LINUX
case TY_CSI_PS('m', 11) : /* IGNORED: mapping related */ break; //LINUX
case TY_CSI_PS('m', 12) : /* IGNORED: mapping related */ break; //LINUX
case TY_CSI_PS('m', 22) : scr->resetRendition (RE_BOLD ); break;
case TY_CSI_PS('m', 24) : scr->resetRendition (RE_UNDERLINE); break;
case TY_CSI_PS('m', 25) : scr->resetRendition (RE_BLINK ); break;
case TY_CSI_PS('m', 27) : scr->resetRendition (RE_REVERSE ); break;
case TY_CSI_PS('m', 30) : scr->setForeColor ( 0); break;
case TY_CSI_PS('m', 31) : scr->setForeColor ( 1); break;
case TY_CSI_PS('m', 32) : scr->setForeColor ( 2); break;
case TY_CSI_PS('m', 33) : scr->setForeColor ( 3); break;
case TY_CSI_PS('m', 34) : scr->setForeColor ( 4); break;
case TY_CSI_PS('m', 35) : scr->setForeColor ( 5); break;
case TY_CSI_PS('m', 36) : scr->setForeColor ( 6); break;
case TY_CSI_PS('m', 37) : scr->setForeColor ( 7); break;
case TY_CSI_PS('m', 39) : scr->setForeColorToDefault( ); break;
case TY_CSI_PS('m', 40) : scr->setBackColor ( 0); break;
case TY_CSI_PS('m', 41) : scr->setBackColor ( 1); break;
case TY_CSI_PS('m', 42) : scr->setBackColor ( 2); break;
case TY_CSI_PS('m', 43) : scr->setBackColor ( 3); break;
case TY_CSI_PS('m', 44) : scr->setBackColor ( 4); break;
case TY_CSI_PS('m', 45) : scr->setBackColor ( 5); break;
case TY_CSI_PS('m', 46) : scr->setBackColor ( 6); break;
case TY_CSI_PS('m', 47) : scr->setBackColor ( 7); break;
case TY_CSI_PS('m', 49) : scr->setBackColorToDefault( ); break;
case TY_CSI_PS('m', 90) : scr->setForeColor ( 8); break;
case TY_CSI_PS('m', 91) : scr->setForeColor ( 9); break;
case TY_CSI_PS('m', 92) : scr->setForeColor ( 10); break;
case TY_CSI_PS('m', 93) : scr->setForeColor ( 11); break;
case TY_CSI_PS('m', 94) : scr->setForeColor ( 12); break;
case TY_CSI_PS('m', 95) : scr->setForeColor ( 13); break;
case TY_CSI_PS('m', 96) : scr->setForeColor ( 14); break;
case TY_CSI_PS('m', 97) : scr->setForeColor ( 15); break;
case TY_CSI_PS('m', 100) : scr->setBackColor ( 8); break;
case TY_CSI_PS('m', 101) : scr->setBackColor ( 9); break;
case TY_CSI_PS('m', 102) : scr->setBackColor ( 10); break;
case TY_CSI_PS('m', 103) : scr->setBackColor ( 11); break;
case TY_CSI_PS('m', 104) : scr->setBackColor ( 12); break;
case TY_CSI_PS('m', 105) : scr->setBackColor ( 13); break;
case TY_CSI_PS('m', 106) : scr->setBackColor ( 14); break;
case TY_CSI_PS('m', 107) : scr->setBackColor ( 15); break;
case TY_CSI_PS('n', 5) : reportStatus ( ); break;
case TY_CSI_PS('n', 6) : reportCursorPosition ( ); break;
case TY_CSI_PS('q', 0) : /* IGNORED: LEDs off */ break; //VT100
case TY_CSI_PS('q', 1) : /* IGNORED: LED1 on */ break; //VT100
case TY_CSI_PS('q', 2) : /* IGNORED: LED2 on */ break; //VT100
case TY_CSI_PS('q', 3) : /* IGNORED: LED3 on */ break; //VT100
case TY_CSI_PS('q', 4) : /* IGNORED: LED4 on */ break; //VT100
case TY_CSI_PS('x', 0) : reportTerminalParms ( 2); break; //VT100
case TY_CSI_PS('x', 1) : reportTerminalParms ( 3); break; //VT100
case TY_CSI_PN('@' ) : scr->insertChars (p ); break;
case TY_CSI_PN('A' ) : scr->cursorUp (p ); break; //VT100
case TY_CSI_PN('B' ) : scr->cursorDown (p ); break; //VT100
case TY_CSI_PN('C' ) : scr->cursorRight (p ); break; //VT100
case TY_CSI_PN('D' ) : scr->cursorLeft (p ); break; //VT100
case TY_CSI_PN('G' ) : scr->setCursorX (p ); break; //LINUX
case TY_CSI_PN('H' ) : scr->setCursorYX (p, q); break; //VT100
case TY_CSI_PN('L' ) : scr->insertLines (p ); break;
case TY_CSI_PN('M' ) : scr->deleteLines (p ); break;
case TY_CSI_PN('P' ) : scr->deleteChars (p ); break;
case TY_CSI_PN('X' ) : scr->eraseChars (p ); break;
case TY_CSI_PN('c' ) : reportTerminalType ( ); break; //VT100
case TY_CSI_PN('d' ) : scr->setCursorY (p ); break; //LINUX
case TY_CSI_PN('f' ) : scr->setCursorYX (p, q); break; //VT100
case TY_CSI_PN('r' ) : scr->setMargins (p, q); break; //VT100
case TY_CSI_PN('y' ) : /* IGNORED: Confidence test */ break; //VT100
//FIXME: experimental, evtl. we can shrink this a little. (hlsr as parm?)
case TY_CSI_PR('h', 1) : setMode (MODE_AppCuKeys); break; //VT100
case TY_CSI_PR('l', 1) : resetMode (MODE_AppCuKeys); break; //VT100
case TY_CSI_PR('s', 1) : saveMode (MODE_AppCuKeys); break; //FIXME
case TY_CSI_PR('r', 1) : restoreMode (MODE_AppCuKeys); break; //FIXME
case TY_CSI_PR('l', 2) : resetMode (MODE_Ansi ); break; //VT100
case TY_CSI_PR('h', 3) : setColumns ( 132); break; //VT100
case TY_CSI_PR('l', 3) : setColumns ( 80); break; //VT100
case TY_CSI_PR('h', 4) : /* IGNORED: soft scrolling */ break; //VT100
case TY_CSI_PR('l', 4) : /* IGNORED: soft scrolling */ break; //VT100
case TY_CSI_PR('h', 5) : scr-> setMode (MODE_Screen ); break; //VT100
case TY_CSI_PR('l', 5) : scr-> resetMode (MODE_Screen ); break; //VT100
case TY_CSI_PR('h', 6) : scr-> setMode (MODE_Origin ); break; //VT100
case TY_CSI_PR('l', 6) : scr-> resetMode (MODE_Origin ); break; //VT100
case TY_CSI_PR('s', 6) : scr-> saveMode (MODE_Origin ); break; //FIXME
case TY_CSI_PR('r', 6) : scr->restoreMode (MODE_Origin ); break; //FIXME
case TY_CSI_PR('h', 7) : scr-> setMode (MODE_Wrap ); break; //VT100
case TY_CSI_PR('l', 7) : scr-> resetMode (MODE_Wrap ); break; //VT100
case TY_CSI_PR('s', 7) : scr-> saveMode (MODE_Wrap ); break; //FIXME
case TY_CSI_PR('r', 7) : scr->restoreMode (MODE_Wrap ); break; //FIXME
case TY_CSI_PR('h', 8) : /* IGNORED: autorepeat on */ break; //VT100
case TY_CSI_PR('l', 8) : /* IGNORED: autorepeat off */ break; //VT100
case TY_CSI_PR('h', 9) : /* IGNORED: interlace */ break; //VT100
case TY_CSI_PR('l', 9) : /* IGNORED: interlace */ break; //VT100
case TY_CSI_PR('h', 25) : setMode (MODE_Cursor ); break; //VT100
case TY_CSI_PR('l', 25) : resetMode (MODE_Cursor ); break; //VT100
case TY_CSI_PR('h', 47) : setMode (MODE_AppScreen); break; //VT100
case TY_CSI_PR('l', 47) : resetMode (MODE_AppScreen); break; //VT100
case TY_CSI_PR('h', 1000) : setMode (MODE_Mouse1000); break; //XTERM
case TY_CSI_PR('l', 1000) : resetMode (MODE_Mouse1000); break; //XTERM
case TY_CSI_PR('s', 1000) : saveMode (MODE_Mouse1000); break; //XTERM
case TY_CSI_PR('r', 1000) : restoreMode (MODE_Mouse1000); break; //XTERM
case TY_CSI_PR('h', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM
case TY_CSI_PR('l', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM
case TY_CSI_PR('s', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM
case TY_CSI_PR('r', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM
case TY_CSI_PR('h', 1047) : setMode (MODE_AppScreen); break; //XTERM
case TY_CSI_PR('l', 1047) : resetMode (MODE_AppScreen); break; //XTERM
case TY_CSI_PR('h', 1048) : scr->saveCursor ( ); break; //XTERM
case TY_CSI_PR('l', 1048) : scr->restoreCursor ( ); break; //XTERM
//FIXME: when changing between vt52 and ansi mode evtl do some resetting.
case TY_VT52__('A' ) : scr->cursorUp ( 1); break; //VT52
case TY_VT52__('B' ) : scr->cursorDown ( 1); break; //VT52
case TY_VT52__('C' ) : scr->cursorRight ( 1); break; //VT52
case TY_VT52__('D' ) : scr->cursorLeft ( 1); break; //VT52
case TY_VT52__('F' ) : scr->setAndUseCharset (0, '0'); break; //VT52
case TY_VT52__('G' ) : scr->setAndUseCharset (0, 'B'); break; //VT52
case TY_VT52__('H' ) : scr->setCursorYX (1,1 ); break; //VT52
case TY_VT52__('I' ) : scr->reverseIndex ( ); break; //VT52
case TY_VT52__('J' ) : scr->clearToEndOfScreen ( ); break; //VT52
case TY_VT52__('K' ) : scr->clearToEndOfLine ( ); break; //VT52
case TY_VT52__('Y' ) : scr->setCursorYX (p-31,q-31 ); break; //VT52
case TY_VT52__('Z' ) : reportTerminalType ( ); break; //VT52
case TY_VT52__('<' ) : setMode (MODE_Ansi ); break; //VT52
case TY_VT52__('=' ) : setMode (MODE_AppKeyPad); break; //VT52
case TY_VT52__('>' ) : resetMode (MODE_AppKeyPad); break; //VT52
default : ReportErrorToken(); break;
};
}
// -----------------------------------------------------------------------------
//
// Scanner / Transducer
//
// -----------------------------------------------------------------------------
//FIXME: evtl. we have to straiten the scanner a bit.
// Scanning -------------------------------------------------------------------
void VT102Emulation::reset()
{
ppos = 0; argc = 0; argv[0] = 0; argv[1] = 0;
}
#define CTL 1
#define CHR 2
#define CPN 4
#define DIG 8
#define SCS 16
#define GRP 32
void VT102Emulation::tableInit()
{ int i; UINT8* s;
for(i = 0; i < 256; i++) tbl[ i] = 0;
for(i = 0; i < 32; i++) tbl[ i] |= CTL;
for(i = 32; i < 256; i++) tbl[ i] |= CHR;
for(s = (UINT8*)"@ABCDGHLMPXcdfry"; *s; s++) tbl[*s] |= CPN;
for(s = (UINT8*)"0123456789" ; *s; s++) tbl[*s] |= DIG;
for(s = (UINT8*)"()+*" ; *s; s++) tbl[*s] |= SCS;
for(s = (UINT8*)"()+*#[]" ; *s; s++) tbl[*s] |= GRP;
}
/* Ok, here comes the nasty part of the decoder.
The following defines do not abstract nor explain anything,
they are only introduced to shorten the lines in the following
routine, which is their only application.
- P is the length of the token scanned so far.
- L (often P-1) is the position on which contents we base a decision.
- C is a character or a group of characters (taken from 'tbl').
*/
#define lec(P,L,C) (p == (P) && s[(L)] == (C))
#define les(P,L,C) (p == (P) && (tbl[s[(L)]] & (C)) == (C))
#define eec(C) (p >= 3 && cc == (C))
#define ees(C) (p >= 3 && (tbl[ cc ] & (C)) == (C))
#define eps(C) (p >= 3 && s[2] != '?' && (tbl[ cc ] & (C)) == (C))
#define epp( ) (p >= 3 && s[2] == '?' )
#define Xpe (ppos>=2 && pbuf[1] == ']' )
#define Xte (Xpe && cc == 7 )
#define ces(C) ( (tbl[ cc ] & (C)) == (C) && !Xte)
#define Dig a[n] = 10*a[n] + cc - '0';
#define Arg argc = MIN(argc+1,MAXARGS-1); argv[argc] = 0;
//FIXME: introduce real states.
//
//
void VT102Emulation::onRcvByte(int c)
{ unsigned char cc = c; int i;
if (cc == 127) return; //VT100: ignore.
if (ces( CTL))
{
if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) reset(); //VT100: CAN or SUB
if (cc != ESC) { tau( TY_CTL___(cc ), 0, 0); return; }
}
pbuf[ppos] = cc; ppos = MIN(ppos+1,MAXPBUF-1);
unsigned char* s = pbuf;
int p = ppos;
int * a = argv;
int n = argc;
if (getMode(MODE_Ansi))
{
if (lec(1,0,ESC)) { return; }
if (les(2,1,GRP)) { return; }
if (Xte ) { XtermHack(); reset(); return; }
if (Xpe ) { return; }
if (lec(3,2,'?')) { return; }
if (les(1,0,CHR)) { tau( TY_CHR___( ), s[0], 0); reset(); return; }
if (lec(2,0,ESC)) { tau( TY_ESC___(s[1] ), 0, 0); reset(); return; }
if (les(3,1,SCS)) { tau( TY_ESC_CS( ), s[1],s[2]); reset(); return; }
if (lec(3,1,'#')) { tau( TY_ESC_DE(s[2] ), 0, 0); reset(); return; }
if (eps( CPN)) { tau( TY_CSI_PN(cc ), a[0],a[1]); reset(); return; }
if (ees( DIG)) { Dig return; }
if (eec( ';')) { Arg return; }
for (i=0;i<=n;i++)
if (epp( )) tau( TY_CSI_PR(cc,a[i]), 0, 0); else
tau( TY_CSI_PS(cc,a[i]), 0, 0);
reset();
}
else // mode VT52
{
if (lec(1,0,ESC)) return;
if (les(1,0,CHR)) { tau( TY_CHR___( ), s[0], 0); reset(); return; }
if (lec(2,1,'Y')) return;
if (lec(3,1,'Y')) return;
if (p < 4) { tau( TY_VT52__(s[1] ), 0, 0); reset(); return; }
tau( TY_VT52__(s[1] ), s[2],s[3]); reset(); return;
}
}
void VT102Emulation::XtermHack()
{ int i,arg = 0;
for (i = 2; i < ppos && '0'<=pbuf[i] && pbuf[i]<'9' ; i++)
arg = 10*arg + (pbuf[i]-'0');
if (pbuf[i] != ';') { ReportErrorToken(); return; }
char str[ppos-i-1];
strncpy(str,(char*)pbuf+i+1,ppos-i-2);
str[ppos-i-2]='\0';
if (arg <= 2) emit changeTitle(arg,str);
}
/* ------------------------------------------------------------------------- */
/* */
/* Reporting */
/* */
/* ------------------------------------------------------------------------- */
/*! shows the contents of the scan buffer.
This functions is used for diagnostics. It is called by \e ReportErrorToken
to inform about strings that cannot be decoded or handled by the emulation.
\sa ReportErrorToken
*/
/*!
*/
static void hexdump(char* s, int len)
{ int i;
for (i = 0; i < len; i++)
{
if (s[i] == '\\')
printf("\\\\");
else
if ((s[i]&0xff) > 32)
printf("%c",s[i]);
else
printf("\\%02x",s[i]&0xff);
}
}
void VT102Emulation::scan_buffer_report()
{
if (ppos == 0 || ppos == 1 && (pbuf[0] & 0xff) >= 32) return;
printf("token: "); hexdump((char*)pbuf,ppos); printf("\n");
}
/*!
*/
void VT102Emulation::ReportErrorToken()
{
printf("undecodable "); scan_buffer_report();
}
void VT102Emulation::NotImplemented(char* text)
{
printf("not implemented: %s.",text); scan_buffer_report();
}
/*!
*/
void VT102Emulation::sendString(const char* s)
{
emit sndBlock(s,strlen(s));
}
/*!
*/
void VT102Emulation::reportTerminalType()
{
//FIXME: should change?
if (getMode(MODE_Ansi))
sendString("\033[?1;2c"); // I'm a VT100 with AP0
else
sendString("\033/Z"); // I'm a VT52
}
/*!
*/
void VT102Emulation::reportStatus()
{
sendString("\033[0n"); //VT100. Device status report. 0 = Ready.
}
/*!
*/
void VT102Emulation::reportAnswerBack()
{
sendString("konsole"); //FIXME? make configurable?
}
/*!
*/
void VT102Emulation::reportCursorPosition()
{ char tmp[20];
sprintf(tmp,"\033[%d;%dR",scr->getCursorY()+1,scr->getCursorX()+1);
sendString(tmp);
}
/*!
`x',`y' are 1-based.
`ev' (event) indicates the button pressed (0-2)
or a general mouse release (3).
*/
void VT102Emulation::reportMouseEvent(int ev, int x, int y)
{ char tmp[20];
sprintf(tmp,"\033[M%c%c%c",ev+040,x+040,y+040);
sendString(tmp);
}
void VT102Emulation::reportTerminalParms(int p)
// DECREPTPARM
{ char tmp[100];
sprintf(tmp,"\033[%d;1;1;112;112;1;0x",p); // not really true.
sendString(tmp);
}
/* ------------------------------------------------------------------------- */
/* */
/* Mode Operations */
/* */
/* ------------------------------------------------------------------------- */
// NOTE: experimental section.
// This is due to the fact that modes have to be handled both on
// emulation and screen level. Dought that we can clean this up.
void VT102Emulation::setMode(int m)
{
currParm.mode[m] = TRUE;
switch (m)
{
case MODE_Mouse1000 : gui->setMouseMarks(FALSE);
break;
case MODE_AppScreen : screen[1]->clearSelection();
screen[1]->clearEntireScreen();
setScreen(1);
break;
}
if (m < MODES_SCREEN || m == MODE_NewLine)
{
screen[0]->setMode(m);
screen[1]->setMode(m);
}
}
void VT102Emulation::resetMode(int m)
{
currParm.mode[m] = FALSE;
switch (m)
{
case MODE_Mouse1000 : gui->setMouseMarks(TRUE);
break;
case MODE_AppScreen : screen[0]->clearSelection();
setScreen(0);
break;
}
if (m < MODES_SCREEN || m == MODE_NewLine)
{
screen[0]->resetMode(m);
screen[1]->resetMode(m);
}
}
void VT102Emulation::saveMode(int m)
{
saveParm.mode[m] = currParm.mode[m];
}
void VT102Emulation::restoreMode(int m)
{
if(saveParm.mode[m]) setMode(m); else resetMode(m);
}
//NOTE: this is a helper function
BOOL VT102Emulation::getMode(int m)
{
return currParm.mode[m];
}
void VT102Emulation::setConnect(bool c)
{
Emulation::setConnect(c);
if (c)
{ // refresh mouse mode
if (getMode(MODE_Mouse1000))
setMode(MODE_Mouse1000);
else
resetMode(MODE_Mouse1000);
}
}
void VT102Emulation::setCharset(int n, int cs)
{
screen[0]->setCharset(n, cs);
screen[1]->setCharset(n, cs);
}
/* ------------------------------------------------------------------------- */
/* */
/* Miscelaneous */
/* */
/* ------------------------------------------------------------------------- */
/*! change between primary and alternate screen
*/
void VT102Emulation::setScreen(int n)
{
scr = screen[n&1];
}
/* ------------------------------------------------------------------------- */
/* */
/* Mouse Handling */
/* */
/* ------------------------------------------------------------------------- */
void VT102Emulation::onMouse( int cb, int cx, int cy )
{
if (!connected) return;
reportMouseEvent(cb,cx,cy);
}
/* ------------------------------------------------------------------------- */
/* */
/* Keyboard Handling */
/* */
/* ------------------------------------------------------------------------- */
#define KeyComb(B,K) ((ev->state() & (B)) == (B) && ev->key() == (K))
#define Xterm (!strcmp(emulation.data(),"xterm"))
/*!
*/
void VT102Emulation::onKeyPress( QKeyEvent* ev )
{ int key;
if (!connected) return; // someone else gets the keys
// revert to non-history when typing
if (scr->getHistCursor() != scr->getHistLines());
scr->setHistCursor(scr->getHistLines());
// Note: there 3 ways in rxvt to handle the Meta (Alt) key
// 1) ignore it
// 2) preceed the keycode by ESC (what we do here)
// 3) set the 8th bit of each char in string
// (which may fail for 8bit (european) characters.
if (ev->state() & AltButton) sendString("\033"); // ESC
//printf("State/Key: 0x%04x 0x%04x\n",ev->state(),ev->key());
key = ev->key();
switch (key)
{
case Key_Return : sendString(getMode(MODE_NewLine)?"\r\n" :"\r" ); return;
case Key_Backspace : sendString(getMode(MODE_BsHack )?"\x7f" :"\x08"); return;
case Key_Delete : sendString(getMode(MODE_BsHack )?"\033[3~":"\x7f"); return;
case Key_Up : sendString(!getMode(MODE_Ansi)?"\033A":getMode(MODE_AppCuKeys)?"\033OA":"\033[A"); return;
case Key_Down : sendString(!getMode(MODE_Ansi)?"\033B":getMode(MODE_AppCuKeys)?"\033OB":"\033[B"); return;
case Key_Right : sendString(!getMode(MODE_Ansi)?"\033C":getMode(MODE_AppCuKeys)?"\033OC":"\033[C"); return;
case Key_Left : sendString(!getMode(MODE_Ansi)?"\033D":getMode(MODE_AppCuKeys)?"\033OD":"\033[D"); return;
// XTERM LINUX
case Key_F1 : sendString(Xterm? "\033[11~": "\033[[A" ); return;
case Key_F2 : sendString(Xterm? "\033[12~": "\033[[B" ); return;
case Key_F3 : sendString(Xterm? "\033[13~": "\033[[C" ); return;
case Key_F4 : sendString(Xterm? "\033[14~": "\033[[D" ); return;
case Key_F5 : sendString(Xterm? "\033[15~": "\033[[E" ); return;
case Key_F6 : sendString("\033[17~" ); return;
case Key_F7 : sendString("\033[18~" ); return;
case Key_F8 : sendString("\033[19~" ); return;
case Key_F9 : sendString("\033[20~" ); return;
case Key_F10 : sendString("\033[21~" ); return;
case Key_F11 : sendString("\033[23~" ); return;
case Key_F12 : sendString("\033[24~" ); return;
case Key_Home : sendString("\033[H" ); return;
case Key_End : sendString("\033[F" ); return;
case Key_Prior : sendString("\033[5~" ); return;
case Key_Next : sendString("\033[6~" ); return;
case Key_Insert : sendString("\033[2~" ); return;
//FIXME: get keypad somehow
}
if (KeyComb(ControlButton,Key_Space)) // ctrl-Space == ctrl-@
{
sndBlock("\x00",1); return;
}
if (KeyComb(ControlButton,Key_Print)) // ctrl-print == sys-req
{
reportAnswerBack(); return;
}
if (ev->ascii()>0)
{ unsigned char c[1];
c[0] = ev->ascii();
//printf("ansi key: "); hexdump(c,1); printf("\n");
emit sndBlock((char*)c,1);
return;
}
}