📄 emul.c
字号:
/* emul.c
* Copyright (c) 1997 David Cole
*
* Terminal emulation
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "utils.h"
#include "term.h"
#include "termwin.h"
#include "lines.h"
#include "emul.h"
#include "connect.h"
#include "dtelnet.h"
#include "raw.h"
#include "socket.h"
#include "log.h"
#include "status.h"
#include "printing.h"
#include "editor.h"
#include "dtchars.h"
#define DEBUG(str)
static unsigned char usCharSet[256] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 15, 26, 27, 28, 29, 30, 31,
' ', '!', '"', '#', '$', '%', '&', '\'',
'(', ')', '*', '+', ',', '-', '.', '/',
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', ';', '<', '=', '>', '?',
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', '{', '|', '}', '~', 127,
128, 129, 130, 131, 132, 133, 134, 135,
136, 137, 138, 139, 140, 141, 142, 143,
144, 145, 146, 147, 148, 149, 150, 151,
152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 163, 164, 165, 166, 167,
168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183,
184, 185, 186, 187, 188, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199,
200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215,
216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231,
232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247,
248, 249, 250, 251, 252, 253, 254, 255
};
static unsigned char graphicsCharSet[256] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 15, 26, 27, 28, 29, 30, 31,
' ', '!', '"', '#', '$', '%', '&', '\'',
'(', ')', '*', '+', ',', '-', '.', '/',
219, '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', ';', '<', '=', '>', '?',
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', '[', '\\', ']', '^', ' ',
'`', 177, 254, 254, 254, 254, 248, 241,
176, 254, 217, 191, 218, 192, 197, 254,
254, 196, 254, '_', 195, 180, 193, 194,
179, 243, 242, 227, 254, 156, 250, 127,
128, 129, 130, 131, 132, 133, 134, 135,
136, 137, 138, 139, 140, 141, 142, 143,
144, 145, 146, 147, 148, 149, 150, 151,
152, 153, 154, 155, 156, 157, 158, 159,
160, 161, 162, 163, 164, 165, 166, 167,
168, 169, 170, 171, 172, 173, 174, 175,
176, 177, 178, 179, 180, 181, 182, 183,
184, 185, 186, 187, 188, 189, 190, 191,
192, 193, 194, 195, 196, 197, 198, 199,
200, 201, 202, 203, 204, 205, 206, 207,
208, 209, 210, 211, 212, 213, 214, 215,
216, 217, 218, 219, 220, 221, 222, 223,
224, 225, 226, 227, 228, 229, 230, 231,
232, 233, 234, 235, 236, 237, 238, 239,
240, 241, 242, 243, 244, 245, 246, 247,
248, 249, 250, 251, 252, 253, 254, 255
};
static unsigned char* ukCharSet = usCharSet;
static unsigned char* altCharSet = usCharSet;
static unsigned char* altGraphicsCharSet = graphicsCharSet;
/* map graphic characters from vt100 code to OEM charset
* warning: some codes are below 0x20 (eg 0x11 as LARROW)
*/
static unsigned char graphToOEM [] = {
'l', 0xda, 'm', 0xc0, 'k', 0xbf, 'j', 0xd9, 't', 0xc3, 'u', 0xb4,
'v', 0xc1, 'w', 0xc2, 'q', 0xc4, 'x', 0xb3, 'n', 0xc5, 'o', 0x7e,
's', 0x5f, '`', 0x04, 'a', 0xb1, 'f', 0xf8, 'g', 0xf1, '~', 0xfe,
',', 0x11, '+', 0x10, '.', 0x19, '-', 0x18, 'h', 0xb0, 'i', 0xce,
'0', 0xdb, 'p', 0xc4, 'r', 0xc4, 'y', 0xf3, 'z', 0xf2, '{', 0xe3,
'|', 0xd8, '}', 0x7d, 0
};
/*
* terminating zero does not count into length
*/
#define NgraphToOEM ((sizeof (graphToOEM) -1)/2)
static char title[sizeof(term.title)];
static int titleLen;
static Emul currEmul = { "" /* empty terminal name */ };
static void emulCharSet(int charSet);
static void emulCharDeleteCore (int numChars, BOOL bKeyboard);
/* Return pointer to the description of the terminal currently being
* emulated.
*/
Emul* emulGetTerm()
{
return &currEmul;
}
/* Set the terminal type to emulate by name
*
* Args:
* name - the name of the terminal type to emulate
*/
void emulSetTerm(const char* name)
{
telnetGetTermProfile(&currEmul, name);
}
/* Set the from/to server charsets specified by name */
void emulSetCharset(const char *name)
{
dtcEC_Load (name, currEmul.ctServerToOem, currEmul.ctOemToServer,
currEmul.ctAnsiToServer, currEmul.ctServerToAnsi);
currEmul.fAnsi = strcmp (name, "OEM")!=0;
}
/**************************
* ATTRIBUTE MANIPULATION *
**************************/
/* Set the foreground attribute for new characters
*
* Args:
* color - ANSI color number 0 .. 7
*/
static void setForeground(int color)
{
term.currAttr &= ~FG_MASK;
term.currAttr |= (unsigned char)FG(color);
}
/* Set the background attribute for new characters
*
* Args:
* color - ANSI color number 0 .. 7
*/
static void setBackground(int color)
{
term.currAttr &= ~BG_MASK;
term.currAttr |= (unsigned char)BG(color);
}
/* Make the current foreground attribute bold
*/
static void setBold(void)
{
term.currAttr |= BOLD;
}
/* Set or clear the inverse attribute
*
* Args:
* inverse - when TRUE, foreground and background are transposed.
*/
static void setInverse(BOOL inverse)
{
term.inverseVideo = inverse;
}
/* Restore the default color attributes
*/
static void clearAttribs(void)
{
term.currAttr = term.blankAttr;
term.inverseVideo = FALSE;
}
/* Return current character attributes
*/
unsigned char getCurrAttr()
{
if (!term.inverseVideo)
return term.currAttr;
return (unsigned char)REVERSE(term.currAttr);
}
/**********************
* TERMINAL EMULATION *
**********************/
/* Clear parameters used for various terminal commands
*/
static void emulParamInit(void)
{
titleLen = 0;
term.numParams = 0;
term.numSParam = 0; /* no byte collected yet */
term.stateSParam = 0; /* waiting for simple bytes */
memset(term.params, 0, sizeof(term.params));
term.seenQuestion = FALSE;
}
/* Start building the next command parameter
*/
static void emulParamNext(void)
{
if (term.numParams < sizeof(term.params) / sizeof(term.params[0]))
term.numParams++;
}
/* Accumulate a digit in the current command parameter
*
* Args:
* num - a decimal digit 0 .. 9
*/
static void emulParamAdd(int num)
{
if (term.numParams == 0)
term.numParams++;
term.params[term.numParams - 1]
= term.params[term.numParams - 1] * 10 + num;
}
static void emulSParamAdd (char byte)
{
int val;
if (term.numSParam >= MAXSPARAM) return; /* ignore */
else if (term.stateSParam == 0) {
term.sparam [term.numSParam++] = byte;
} else {
val = fromhex (byte);
if (term.stateSParam == 1) {
term.sparam [term.numSParam] = (char)(val<<4);
term.stateSParam = 2;
} else {
term.sparam [term.numSParam] += (char)val;
++term.numSParam;
term.stateSParam = 1;
}
}
}
/* Capture new window title from the terminal input
*/
static void emulAddTitle(char c)
{
if (titleLen < sizeof(title) - 1) {
title[titleLen++] = c;
title[titleLen] = '\0';
}
}
/* Set the window title from the captured text
*/
static void emulSetTitle(void)
{
if (term.numParams == 0)
term.params[term.numParams++] = 0;
switch (term.params[0]) {
case 0:
case 2:
termSetTitle(title);
break;
}
titleLen = 0;
}
/* Check to see if the cursor has been moved off the terminal. If it
* has, scroll the terminal to bring the cursor back.
*/
static void emulCursorCheck(void)
{
if (term.haveRegion) {
/* Scrolling a region has different semantics - we do not
* update the history if we have a region set.
*/
if (term.cursor.y == term.scrollBottom) {
/* We have moved the cursor off the bottom of the region -
* scroll the region.
*/
term.cursor.y--;
if (term.topVisibleLine + term.scrollBottom > winTerminalTopLine())
winScrollRegion(1);
linesDelete(term.scrollTop, term.scrollBottom, 1);
} else if (term.cursor.y == term.scrollTop - 1) {
term.cursor.y++;
if (term.topVisibleLine + term.scrollBottom > winTerminalTopLine())
winScrollRegion(-1);
linesInsert(term.scrollTop, term.scrollBottom, 1);
}
} else {
if (term.cursor.y == term.winSize.cy) {
/* We have moved the cursor off the bottom of the terminal -
* scroll the window if we have not scrolled back in the
* history buffer.
*/
term.cursor.y--;
if (term.topVisibleLine == winTerminalTopLine()) {
winScrollRegion(1);
term.topVisibleLine++;
}
linesNewLine();
} else if (term.cursor.y == -1) {
term.cursor.y++;
if (term.topVisibleLine + term.winSize.cy > winTerminalTopLine())
winScrollRegion(-1);
linesInsert(0, term.winSize.cy, 1);
}
}
/* Make sure we create lines to the cursor position.
*/
linesCreateTo(term.cursor.y);
}
/* If a character added to the end of the current line will cause a
* line wrap, perform necessary actions.
*/
static void emulCheckWrap(void)
{
if (term.cursor.x == term.winSize.cx) {
if (term.lineWrap) {
/* Wrap to start of next line
*/
int lineIdx = linesTerminalToLine(term.cursor.y);
Line* line;
linesCreateTo(lineIdx);
line = linesGetLine(lineIdx);
/* Remember that we wrapped this line. This allows us to
* copy/paste lines that wrap without getting spurious end
* of line sequences.
*/
if (line != NULL)
term.lineList[lineIdx]->wrapped = 1;
term.cursor.x = 0;
term.cursor.y++;
} else
/* Overwrite the character at the end of the line
*/
term.cursor.x--;
}
/* Line wrap might cause the terminal to scroll
*/
emulCursorCheck();
}
/* Carriage Return moves cursor to the beginning of the current line
*/
static void emulCarriageReturn(void)
{
term.cursor.x = 0;
emulCursorCheck();
}
/* Line Feed moves cursor down one line.
*/
static void emulLineFeed(void)
{
if (rawInBinaryMode())
emulCarriageReturn();
term.cursor.y++;
emulCursorCheck();
}
/* Move cursor to the next tab stop. The cursor always stays on the
* current line.
*/
static void emulTab(void)
{
if (printingIsActive()){
printingAddChar('\t');
return;
}
/* Move the cursor */
do
term.cursor.x++;
while (term.cursor.x < MaxLineLen
&& !term.tabStops[term.cursor.x]);
/* Make sure that we do not move the cursor off the end of the
* visible line.
*/
if (term.cursor.x > term.winSize.cx)
term.cursor.x = term.winSize.cx;
}
/* Move cursor to the previous tab stop.
*/
static void emulBacktab(void)
{
do
term.cursor.x--;
while (term.cursor.x > 0 && !term.tabStops[term.cursor.x]);
if (term.cursor.x < 0)
term.cursor.x = 0;
}
/* Tab forward <param-0> tab stops.
*/
static void emulTabForward(void)
{
if (term.numParams != 1)
return;
while (term.params[0]-- > 0)
emulTab();
}
/* Tab backwards <param-0> tab stops.
*/
static void emulTabBackward(void)
{
if (term.numParams != 1)
return;
while (term.params[0]-- > 0)
emulBacktab();
}
/* Set a tab stop at the current cursor column.
*/
static void emulTabSet(void)
{
if (term.cursor.x < MaxLineLen)
term.tabStops[term.cursor.x] = 1;
}
/* Clear tab stops depending on <param-0>;
* if 0, clear tab stop at current cursor column
* if 3, clear all tab stops
*/
static void emulTabClear(void)
{
if (term.numParams != 1)
return;
switch (term.params[0]) {
case 0:
/* Clear tab stop at current cursor column
*/
if (term.cursor.x >= 0 && term.cursor.x < MaxLineLen)
term.tabStops[term.cursor.x] = 0;
break;
case 3:
/* Clear all tab stops
*/
memset(term.tabStops, 0, sizeof(term.tabStops));
break;
}
}
/* Reset all tab stops to 8 character interval
*/
static void emulTabReset(void)
{
int x;
for (x = 0; x < sizeof(term.tabStops); x++)
term.tabStops[x] = (char)(x > 0 && (x % 8) == 0);
}
/* Backspace the cursor
*/
static void emulBackspace(BOOL bKeyboard)
{
int lineIdx;
Line *line;
if (term.cursor.x > 0) {
term.cursor.x--;
if (bKeyboard)
emulCharDeleteCore (1, bKeyboard);
} else {
lineIdx = linesTerminalToLine(term.cursor.y);
if (lineIdx==0) return;
--lineIdx;
linesCreateTo(lineIdx);
line = linesGetLine(lineIdx);
if (! line->wrapped) return;
/* term.cursor.x = term.winSize.cx - 1; */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -