📄 terminal.c
字号:
case 34: /* WYULCURM: Make cursor BIG */
compatibility2(OTHER, VT220);
term->big_cursor = !state;
}
}
/*
* Process an OSC sequence: set window title or icon name.
*/
static void do_osc(Terminal *term)
{
if (term->osc_w) {
while (term->osc_strlen--)
term->wordness[(unsigned char)
term->osc_string[term->osc_strlen]] = term->esc_args[0];
} else {
term->osc_string[term->osc_strlen] = '\0';
switch (term->esc_args[0]) {
case 0:
case 1:
if (!term->cfg.no_remote_wintitle)
set_icon(term->frontend, term->osc_string);
if (term->esc_args[0] == 1)
break;
/* fall through: parameter 0 means set both */
case 2:
case 21:
if (!term->cfg.no_remote_wintitle)
set_title(term->frontend, term->osc_string);
break;
}
}
}
/*
* ANSI printing routines.
*/
static void term_print_setup(Terminal *term)
{
bufchain_clear(&term->printer_buf);
term->print_job = printer_start_job(term->cfg.printer);
}
static void term_print_flush(Terminal *term)
{
void *data;
int len;
int size;
while ((size = bufchain_size(&term->printer_buf)) > 5) {
bufchain_prefix(&term->printer_buf, &data, &len);
if (len > size-5)
len = size-5;
printer_job_data(term->print_job, data, len);
bufchain_consume(&term->printer_buf, len);
}
}
static void term_print_finish(Terminal *term)
{
void *data;
int len, size;
char c;
if (!term->printing && !term->only_printing)
return; /* we need do nothing */
term_print_flush(term);
while ((size = bufchain_size(&term->printer_buf)) > 0) {
bufchain_prefix(&term->printer_buf, &data, &len);
c = *(char *)data;
if (c == '\033' || c == '\233') {
bufchain_consume(&term->printer_buf, size);
break;
} else {
printer_job_data(term->print_job, &c, 1);
bufchain_consume(&term->printer_buf, 1);
}
}
printer_finish_job(term->print_job);
term->print_job = NULL;
term->printing = term->only_printing = FALSE;
}
/*
* Remove everything currently in `inbuf' and stick it up on the
* in-memory display. There's a big state machine in here to
* process escape sequences...
*/
void term_out(Terminal *term)
{
int c, unget;
unsigned char localbuf[256], *chars;
int nchars = 0;
unget = -1;
chars = NULL; /* placate compiler warnings */
while (nchars > 0 || bufchain_size(&term->inbuf) > 0) {
if (unget == -1) {
if (nchars == 0) {
void *ret;
bufchain_prefix(&term->inbuf, &ret, &nchars);
if (nchars > sizeof(localbuf))
nchars = sizeof(localbuf);
memcpy(localbuf, ret, nchars);
bufchain_consume(&term->inbuf, nchars);
chars = localbuf;
assert(chars != NULL);
}
c = *chars++;
nchars--;
/*
* Optionally log the session traffic to a file. Useful for
* debugging and possibly also useful for actual logging.
*/
if (term->cfg.logtype == LGTYP_DEBUG && term->logctx)
logtraffic(term->logctx, (unsigned char) c, LGTYP_DEBUG);
} else {
c = unget;
unget = -1;
}
/* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even
* be able to display 8-bit characters, but I'll let that go 'cause
* of i18n.
*/
/*
* If we're printing, add the character to the printer
* buffer.
*/
if (term->printing) {
bufchain_add(&term->printer_buf, &c, 1);
/*
* If we're in print-only mode, we use a much simpler
* state machine designed only to recognise the ESC[4i
* termination sequence.
*/
if (term->only_printing) {
if (c == '\033')
term->print_state = 1;
else if (c == (unsigned char)'\233')
term->print_state = 2;
else if (c == '[' && term->print_state == 1)
term->print_state = 2;
else if (c == '4' && term->print_state == 2)
term->print_state = 3;
else if (c == 'i' && term->print_state == 3)
term->print_state = 4;
else
term->print_state = 0;
if (term->print_state == 4) {
term_print_finish(term);
}
continue;
}
}
/* First see about all those translations. */
if (term->termstate == TOPLEVEL) {
if (in_utf(term))
switch (term->utf_state) {
case 0:
if (c < 0x80) {
/* UTF-8 must be stateless so we ignore iso2022. */
if (term->ucsdata->unitab_ctrl[c] != 0xFF)
c = term->ucsdata->unitab_ctrl[c];
else c = ((unsigned char)c) | ATTR_ASCII;
break;
} else if ((c & 0xe0) == 0xc0) {
term->utf_size = term->utf_state = 1;
term->utf_char = (c & 0x1f);
} else if ((c & 0xf0) == 0xe0) {
term->utf_size = term->utf_state = 2;
term->utf_char = (c & 0x0f);
} else if ((c & 0xf8) == 0xf0) {
term->utf_size = term->utf_state = 3;
term->utf_char = (c & 0x07);
} else if ((c & 0xfc) == 0xf8) {
term->utf_size = term->utf_state = 4;
term->utf_char = (c & 0x03);
} else if ((c & 0xfe) == 0xfc) {
term->utf_size = term->utf_state = 5;
term->utf_char = (c & 0x01);
} else {
c = UCSERR;
break;
}
continue;
case 1:
case 2:
case 3:
case 4:
case 5:
if ((c & 0xC0) != 0x80) {
unget = c;
c = UCSERR;
term->utf_state = 0;
break;
}
term->utf_char = (term->utf_char << 6) | (c & 0x3f);
if (--term->utf_state)
continue;
c = term->utf_char;
/* Is somebody trying to be evil! */
if (c < 0x80 ||
(c < 0x800 && term->utf_size >= 2) ||
(c < 0x10000 && term->utf_size >= 3) ||
(c < 0x200000 && term->utf_size >= 4) ||
(c < 0x4000000 && term->utf_size >= 5))
c = UCSERR;
/* Unicode line separator and paragraph separator are CR-LF */
if (c == 0x2028 || c == 0x2029)
c = 0x85;
/* High controls are probably a Baaad idea too. */
if (c < 0xA0)
c = 0xFFFD;
/* The UTF-16 surrogates are not nice either. */
/* The standard give the option of decoding these:
* I don't want to! */
if (c >= 0xD800 && c < 0xE000)
c = UCSERR;
/* ISO 10646 characters now limited to UTF-16 range. */
if (c > 0x10FFFF)
c = UCSERR;
/* This is currently a TagPhobic application.. */
if (c >= 0xE0000 && c <= 0xE007F)
continue;
/* U+FEFF is best seen as a null. */
if (c == 0xFEFF)
continue;
/* But U+FFFE is an error. */
if (c == 0xFFFE || c == 0xFFFF)
c = UCSERR;
/* Oops this is a 16bit implementation */
if (c >= 0x10000)
c = 0xFFFD;
break;
}
/* Are we in the nasty ACS mode? Note: no sco in utf mode. */
else if(term->sco_acs &&
(c!='\033' && c!='\012' && c!='\015' && c!='\b'))
{
if (term->sco_acs == 2) c |= 0x80;
c |= ATTR_SCOACS;
} else {
switch (term->cset_attr[term->cset]) {
/*
* Linedraw characters are different from 'ESC ( B'
* only for a small range. For ones outside that
* range, make sure we use the same font as well as
* the same encoding.
*/
case ATTR_LINEDRW:
if (term->ucsdata->unitab_ctrl[c] != 0xFF)
c = term->ucsdata->unitab_ctrl[c];
else
c = ((unsigned char) c) | ATTR_LINEDRW;
break;
case ATTR_GBCHR:
/* If UK-ASCII, make the '#' a LineDraw Pound */
if (c == '#') {
c = '}' | ATTR_LINEDRW;
break;
}
/*FALLTHROUGH*/ case ATTR_ASCII:
if (term->ucsdata->unitab_ctrl[c] != 0xFF)
c = term->ucsdata->unitab_ctrl[c];
else
c = ((unsigned char) c) | ATTR_ASCII;
break;
case ATTR_SCOACS:
if (c>=' ') c = ((unsigned char)c) | ATTR_SCOACS;
break;
}
}
}
/* How about C1 controls ? */
if ((c & -32) == 0x80 && term->termstate < DO_CTRLS &&
!term->vt52_mode && has_compat(VT220)) {
term->termstate = SEEN_ESC;
term->esc_query = FALSE;
c = '@' + (c & 0x1F);
}
/* Or the GL control. */
if (c == '\177' && term->termstate < DO_CTRLS && has_compat(OTHER)) {
if (term->curs.x && !term->wrapnext)
term->curs.x--;
term->wrapnext = FALSE;
fix_cpos;
if (!term->cfg.no_dbackspace) /* destructive bksp might be disabled */
*term->cpos = (' ' | term->curr_attr | ATTR_ASCII);
} else
/* Or normal C0 controls. */
if ((c & -32) == 0 && term->termstate < DO_CTRLS) {
switch (c) {
case '\005': /* ENQ: terminal type query */
/* Strictly speaking this is VT100 but a VT100 defaults to
* no response. Other terminals respond at their option.
*
* Don't put a CR in the default string as this tends to
* upset some weird software.
*
* An xterm returns "xterm" (5 characters)
*/
compatibility(ANSIMIN);
if (term->ldisc) {
char abuf[256], *s, *d;
int state = 0;
for (s = term->cfg.answerback, d = abuf; *s; s++) {
if (state) {
if (*s >= 'a' && *s <= 'z')
*d++ = (*s - ('a' - 1));
else if ((*s >= '@' && *s <= '_') ||
*s == '?' || (*s & 0x80))
*d++ = ('@' ^ *s);
else if (*s == '~')
*d++ = '^';
state = 0;
} else if (*s == '^') {
state = 1;
} else
*d++ = *s;
}
lpage_send(term->ldisc, DEFAULT_CODEPAGE,
abuf, d - abuf, 0);
}
break;
case '\007': /* BEL: Bell */
{
struct beeptime *newbeep;
unsigned long ticks;
ticks = GETTICKCOUNT();
if (!term->beep_overloaded) {
newbeep = snew(struct beeptime);
newbeep->ticks = ticks;
newbeep->next = NULL;
if (!term->beephead)
term->beephead = newbeep;
else
term->beeptail->next = newbeep;
term->beeptail = newbeep;
term->nbeeps++;
}
/*
* Throw out any beeps that happened more than
* t seconds ago.
*/
while (term->beephead &&
term->beephead->ticks < ticks - term->cfg.bellovl_t) {
struct beeptime *tmp = term->beephead;
term->beephead = tmp->next;
sfree(tmp);
if (!term->beephead)
term->beeptail = NULL;
term->nbeeps--;
}
if (term->cfg.bellovl && term->beep_overloaded &&
ticks - term->lastbeep >= (unsigned)term->cfg.bellovl_s) {
/*
* If we're currently overloaded and the
* last beep was more than s seconds ago,
* leave overload mode.
*/
term->beep_overloaded = FALSE;
} else if (term->cfg.bellovl && !term->beep_overloaded &&
term->nbeeps >= term->cfg.bellovl_n) {
/*
* Now, if we have n or more beeps
* remaining in the queue, go into overload
* mode.
*/
term->beep_overloaded = TRUE;
}
term->lastbeep = ticks;
/*
* Perform an actual beep if we're not overloaded.
*/
if (!term->cfg.bellovl || !term->beep_overloaded) {
beep(term->frontend, term->cfg.beep);
if (term->cfg.beep == BELL_VISUAL) {
term->in_vbell = TRUE;
term->vbell_startpoint = ticks;
term_update(term);
}
}
term->seen_disp_event = TRUE;
}
break;
case '\b': /* BS: Back space */
if (term->curs.x == 0 &&
(term->curs.y == 0 || term->wrap == 0))
/* do nothing */ ;
else if (term->curs.x == 0 && term->curs.y > 0)
term->curs.x = term->cols - 1, term->curs.y--;
else if (term->wrapnext)
term->wrapnext = FALSE;
else
term->curs.x--;
fix_cpos;
term->seen_disp_event = TRUE;
break;
case '\016': /* LS1: Locking-shift one */
compatibility(VT100);
term->cset = 1;
break;
case '\017': /* LS0: Locking-shift zero */
compatibility(VT100);
term->cset = 0;
break;
case '\033': /* ESC: Escape */
if (term->vt52_mode)
term->termstate = VT52_ESC;
else {
compatibility(ANSIMIN);
term->termstate = SEEN_ESC;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -