2019-06-15 22:22:44 +02:00
|
|
|
|
#include "vt.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
#include <string.h>
|
2019-07-15 15:42:00 +02:00
|
|
|
|
#include <unistd.h>
|
2019-06-15 22:22:44 +02:00
|
|
|
|
|
|
|
|
|
|
#define LOG_MODULE "vt"
|
2019-07-03 20:21:03 +02:00
|
|
|
|
#define LOG_ENABLE_DBG 0
|
2019-06-15 22:22:44 +02:00
|
|
|
|
#include "log.h"
|
|
|
|
|
|
#include "csi.h"
|
2020-01-12 11:55:22 +01:00
|
|
|
|
#include "dcs.h"
|
2021-01-15 20:39:45 +00:00
|
|
|
|
#include "debug.h"
|
2019-06-17 19:33:10 +02:00
|
|
|
|
#include "grid.h"
|
2019-07-19 09:55:07 +02:00
|
|
|
|
#include "osc.h"
|
2020-05-01 11:46:24 +02:00
|
|
|
|
#include "util.h"
|
2020-08-08 20:34:30 +01:00
|
|
|
|
#include "xmalloc.h"
|
2019-08-30 22:08:37 +02:00
|
|
|
|
|
2019-11-29 23:59:24 +01:00
|
|
|
|
#define UNHANDLED() LOG_DBG("unhandled: %s", esc_as_string(term, final))
|
2019-07-30 21:42:46 +02:00
|
|
|
|
|
2019-06-15 22:22:44 +02:00
|
|
|
|
/* https://vt100.net/emu/dec_ansi_parser */
|
|
|
|
|
|
|
|
|
|
|
|
enum state {
|
|
|
|
|
|
STATE_GROUND,
|
2019-06-23 13:28:55 +02:00
|
|
|
|
STATE_ESCAPE,
|
|
|
|
|
|
STATE_ESCAPE_INTERMEDIATE,
|
|
|
|
|
|
|
|
|
|
|
|
STATE_CSI_ENTRY,
|
|
|
|
|
|
STATE_CSI_PARAM,
|
|
|
|
|
|
STATE_CSI_INTERMEDIATE,
|
|
|
|
|
|
STATE_CSI_IGNORE,
|
|
|
|
|
|
|
|
|
|
|
|
STATE_OSC_STRING,
|
|
|
|
|
|
|
|
|
|
|
|
STATE_DCS_ENTRY,
|
|
|
|
|
|
STATE_DCS_PARAM,
|
|
|
|
|
|
STATE_DCS_INTERMEDIATE,
|
|
|
|
|
|
STATE_DCS_IGNORE,
|
|
|
|
|
|
STATE_DCS_PASSTHROUGH,
|
2019-06-15 22:22:44 +02:00
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
|
STATE_SOS_PM_APC_STRING,
|
|
|
|
|
|
|
2020-06-07 16:16:50 +02:00
|
|
|
|
STATE_UTF8_21,
|
|
|
|
|
|
STATE_UTF8_31,
|
|
|
|
|
|
STATE_UTF8_32,
|
|
|
|
|
|
STATE_UTF8_41,
|
|
|
|
|
|
STATE_UTF8_42,
|
|
|
|
|
|
STATE_UTF8_43,
|
2019-06-15 22:22:44 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
2019-11-05 13:55:43 +01:00
|
|
|
|
#if defined(_DEBUG) && defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG && 0
|
2019-06-15 22:22:44 +02:00
|
|
|
|
static const char *const state_names[] = {
|
|
|
|
|
|
[STATE_GROUND] = "ground",
|
|
|
|
|
|
|
2019-06-23 13:28:55 +02:00
|
|
|
|
[STATE_ESCAPE] = "escape",
|
|
|
|
|
|
[STATE_ESCAPE_INTERMEDIATE] = "escape intermediate",
|
|
|
|
|
|
|
|
|
|
|
|
[STATE_CSI_ENTRY] = "CSI entry",
|
|
|
|
|
|
[STATE_CSI_PARAM] = "CSI param",
|
|
|
|
|
|
[STATE_CSI_INTERMEDIATE] = "CSI intermediate",
|
|
|
|
|
|
[STATE_CSI_IGNORE] = "CSI ignore",
|
|
|
|
|
|
|
|
|
|
|
|
[STATE_OSC_STRING] = "OSC string",
|
|
|
|
|
|
|
|
|
|
|
|
[STATE_DCS_ENTRY] = "DCS entry",
|
|
|
|
|
|
[STATE_DCS_PARAM] = "DCS param",
|
|
|
|
|
|
[STATE_DCS_INTERMEDIATE] = "DCS intermediate",
|
|
|
|
|
|
[STATE_DCS_IGNORE] = "DCS ignore",
|
|
|
|
|
|
[STATE_DCS_PASSTHROUGH] = "DCS passthrough",
|
|
|
|
|
|
|
|
|
|
|
|
[STATE_SOS_PM_APC_STRING] = "sos/pm/apc string",
|
|
|
|
|
|
|
2020-06-07 16:16:50 +02:00
|
|
|
|
[STATE_UTF8_21] = "UTF8 2-byte 1/2",
|
|
|
|
|
|
[STATE_UTF8_31] = "UTF8 3-byte 1/3",
|
|
|
|
|
|
[STATE_UTF8_32] = "UTF8 3-byte 2/3",
|
2019-06-15 22:22:44 +02:00
|
|
|
|
};
|
2019-12-20 22:10:27 +01:00
|
|
|
|
#endif
|
2019-06-15 22:22:44 +02:00
|
|
|
|
|
2019-11-30 00:02:19 +01:00
|
|
|
|
#if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
|
2019-07-04 19:35:01 +02:00
|
|
|
|
static const char *
|
|
|
|
|
|
esc_as_string(struct terminal *term, uint8_t final)
|
2019-06-23 13:36:20 +02:00
|
|
|
|
{
|
2019-07-04 19:35:01 +02:00
|
|
|
|
static char msg[1024];
|
2019-07-10 16:04:25 +02:00
|
|
|
|
int c = snprintf(msg, sizeof(msg), "\\E");
|
2019-06-23 13:36:20 +02:00
|
|
|
|
|
vt: don’t ignore extra private/intermediate characters
Take ‘\E(#0’ for example - this is *not* the same as ‘\E(0’.
Up until now, foot has however treated them as the same escape,
because the handler for ‘\E(0’ didn’t verify there weren’t any _other_
private characters present.
Fix this by turning the ‘private’ array into a single 4-byte
integer. This allows us to match *all* privates with a single
comparison.
Private characters are added to the LSB first, and MSB last. This
means we can check for single privates in pretty much the same way as
before:
switch (term->vt.private) {
case ‘?’:
...
break;
}
Checking for two (or more) is much uglier, but foot only supports
a *single* escape with two privates, and no escapes with three or
more:
switch (term->vt.private) {
case 0x243f: /* ‘?$’ */
...
break;
}
The ‘clear’ action remains simple (and fast), with a single write
operation.
Collecting privates is potentially _slightly_ more complex than
before; we now need mask and compare, instead of simply comparing,
when checking how many privates we already have.
We _could_ add a counter, which would make collecting privates easier,
but this would add an additional write to the ‘clean’ action which is
really bad since it’s in the hot path.
2020-12-16 14:30:49 +01:00
|
|
|
|
for (size_t i = 0; i < sizeof(term->vt.private); i++) {
|
|
|
|
|
|
char value = (term->vt.private >> (i * 8)) & 0xff;
|
|
|
|
|
|
if (value == 0)
|
2019-07-19 09:56:59 +02:00
|
|
|
|
break;
|
vt: don’t ignore extra private/intermediate characters
Take ‘\E(#0’ for example - this is *not* the same as ‘\E(0’.
Up until now, foot has however treated them as the same escape,
because the handler for ‘\E(0’ didn’t verify there weren’t any _other_
private characters present.
Fix this by turning the ‘private’ array into a single 4-byte
integer. This allows us to match *all* privates with a single
comparison.
Private characters are added to the LSB first, and MSB last. This
means we can check for single privates in pretty much the same way as
before:
switch (term->vt.private) {
case ‘?’:
...
break;
}
Checking for two (or more) is much uglier, but foot only supports
a *single* escape with two privates, and no escapes with three or
more:
switch (term->vt.private) {
case 0x243f: /* ‘?$’ */
...
break;
}
The ‘clear’ action remains simple (and fast), with a single write
operation.
Collecting privates is potentially _slightly_ more complex than
before; we now need mask and compare, instead of simply comparing,
when checking how many privates we already have.
We _could_ add a counter, which would make collecting privates easier,
but this would add an additional write to the ‘clean’ action which is
really bad since it’s in the hot path.
2020-12-16 14:30:49 +01:00
|
|
|
|
c += snprintf(&msg[c], sizeof(msg) - c, "%c", value);
|
2019-07-19 09:56:59 +02:00
|
|
|
|
}
|
2019-06-23 13:36:20 +02:00
|
|
|
|
|
2021-01-16 20:16:00 +00:00
|
|
|
|
xassert(term->vt.params.idx == 0);
|
2019-07-15 13:39:19 +02:00
|
|
|
|
|
2019-11-05 10:39:36 +01:00
|
|
|
|
snprintf(&msg[c], sizeof(msg) - c, "%c", final);
|
2019-07-04 19:35:01 +02:00
|
|
|
|
return msg;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2019-11-30 00:02:19 +01:00
|
|
|
|
#endif
|
2019-07-04 19:35:01 +02:00
|
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
|
static void
|
2019-12-20 23:27:15 +01:00
|
|
|
|
action_ignore(struct terminal *term)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_clear(struct terminal *term)
|
|
|
|
|
|
{
|
|
|
|
|
|
term->vt.params.idx = 0;
|
vt: don’t ignore extra private/intermediate characters
Take ‘\E(#0’ for example - this is *not* the same as ‘\E(0’.
Up until now, foot has however treated them as the same escape,
because the handler for ‘\E(0’ didn’t verify there weren’t any _other_
private characters present.
Fix this by turning the ‘private’ array into a single 4-byte
integer. This allows us to match *all* privates with a single
comparison.
Private characters are added to the LSB first, and MSB last. This
means we can check for single privates in pretty much the same way as
before:
switch (term->vt.private) {
case ‘?’:
...
break;
}
Checking for two (or more) is much uglier, but foot only supports
a *single* escape with two privates, and no escapes with three or
more:
switch (term->vt.private) {
case 0x243f: /* ‘?$’ */
...
break;
}
The ‘clear’ action remains simple (and fast), with a single write
operation.
Collecting privates is potentially _slightly_ more complex than
before; we now need mask and compare, instead of simply comparing,
when checking how many privates we already have.
We _could_ add a counter, which would make collecting privates easier,
but this would add an additional write to the ‘clean’ action which is
really bad since it’s in the hot path.
2020-12-16 14:30:49 +01:00
|
|
|
|
term->vt.private = 0;
|
2019-12-20 23:27:15 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_execute(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_DBG("execute: 0x%02x", c);
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* 7-bit C0 control characters
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
case '\0':
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2020-07-14 09:11:17 +02:00
|
|
|
|
case '\a':
|
|
|
|
|
|
/* BEL - bell */
|
2020-10-08 19:55:32 +02:00
|
|
|
|
term_bell(term);
|
2019-12-20 23:27:15 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case '\b':
|
|
|
|
|
|
/* backspace */
|
2021-01-15 18:40:07 +01:00
|
|
|
|
#if 0
|
|
|
|
|
|
/*
|
|
|
|
|
|
* This is the “correct” BS behavior. However, it doesn’t play
|
|
|
|
|
|
* nicely with bw/auto_left_margin, hence the alternative
|
|
|
|
|
|
* implementation below.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Note that it breaks vttest “1. Test of cursor movements ->
|
|
|
|
|
|
* Test of autowrap”
|
|
|
|
|
|
*/
|
|
|
|
|
|
term_cursor_left(term, 1);
|
|
|
|
|
|
#else
|
2020-10-02 21:40:30 +02:00
|
|
|
|
if (term->grid->cursor.lcf)
|
|
|
|
|
|
term->grid->cursor.lcf = false;
|
|
|
|
|
|
else
|
|
|
|
|
|
term_cursor_left(term, 1);
|
2021-01-15 18:40:07 +01:00
|
|
|
|
#endif
|
2019-12-20 23:27:15 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
2020-07-14 09:11:17 +02:00
|
|
|
|
case '\t': {
|
2019-12-20 23:27:15 +01:00
|
|
|
|
/* HT - horizontal tab */
|
|
|
|
|
|
int new_col = term->cols - 1;
|
|
|
|
|
|
tll_foreach(term->tab_stops, it) {
|
2020-04-16 18:51:14 +02:00
|
|
|
|
if (it->item > term->grid->cursor.point.col) {
|
2019-12-20 23:27:15 +01:00
|
|
|
|
new_col = it->item;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-01-16 20:16:00 +00:00
|
|
|
|
xassert(new_col >= term->grid->cursor.point.col);
|
2020-07-14 10:47:17 +02:00
|
|
|
|
|
|
|
|
|
|
/* According to the specification, HT _should_ cancel LCF. But
|
|
|
|
|
|
* XTerm, and nearly all other emulators, don't. So we follow
|
2020-08-16 14:37:27 +01:00
|
|
|
|
* suit */
|
2020-07-14 10:47:17 +02:00
|
|
|
|
bool lcf = term->grid->cursor.lcf;
|
2020-04-16 18:51:14 +02:00
|
|
|
|
term_cursor_right(term, new_col - term->grid->cursor.point.col);
|
2020-07-14 10:47:17 +02:00
|
|
|
|
term->grid->cursor.lcf = lcf;
|
2019-12-20 23:27:15 +01:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-14 09:11:17 +02:00
|
|
|
|
case '\n':
|
|
|
|
|
|
case '\v':
|
2020-07-14 09:18:52 +02:00
|
|
|
|
case '\f':
|
2020-07-14 09:15:15 +02:00
|
|
|
|
/* LF - \n - line feed */
|
|
|
|
|
|
/* VT - \v - vertical tab */
|
2020-07-14 09:18:52 +02:00
|
|
|
|
/* FF - \f - form feed */
|
2020-07-14 09:15:15 +02:00
|
|
|
|
term_linefeed(term);
|
2019-12-20 23:27:15 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
2020-07-14 09:11:17 +02:00
|
|
|
|
case '\r':
|
|
|
|
|
|
/* CR - carriage ret */
|
2020-07-14 09:29:10 +02:00
|
|
|
|
term_carriage_return(term);
|
2020-07-14 09:11:17 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
case '\x0e':
|
|
|
|
|
|
/* SO - shift out */
|
|
|
|
|
|
term->charsets.selected = 1; /* G1 */
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case '\x0f':
|
|
|
|
|
|
/* SI - shift in */
|
|
|
|
|
|
term->charsets.selected = 0; /* G0 */
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* 8-bit C1 control characters
|
|
|
|
|
|
*
|
|
|
|
|
|
* We ignore these, but keep them here for reference, along
|
|
|
|
|
|
* with their corresponding 7-bit variants.
|
|
|
|
|
|
*
|
|
|
|
|
|
* As far as I can tell, XTerm also ignores these _when in
|
|
|
|
|
|
* UTF-8 mode_. Which would be the normal mode of operation
|
|
|
|
|
|
* these days. And since we _only_ support UTF-8...
|
|
|
|
|
|
*/
|
2020-07-14 09:29:10 +02:00
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
#if 0
|
|
|
|
|
|
case '\x84': /* IND -> ESC D */
|
|
|
|
|
|
case '\x85': /* NEL -> ESC E */
|
|
|
|
|
|
case '\x88': /* Tab Set -> ESC H */
|
|
|
|
|
|
case '\x8d': /* RI -> ESC M */
|
|
|
|
|
|
case '\x8e': /* SS2 -> ESC N */
|
|
|
|
|
|
case '\x8f': /* SS3 -> ESC O */
|
|
|
|
|
|
case '\x90': /* DCS -> ESC P */
|
|
|
|
|
|
case '\x96': /* SPA -> ESC V */
|
|
|
|
|
|
case '\x97': /* EPA -> ESC W */
|
|
|
|
|
|
case '\x98': /* SOS -> ESC X */
|
|
|
|
|
|
case '\x9a': /* DECID -> ESC Z (obsolete form of CSI c) */
|
|
|
|
|
|
case '\x9b': /* CSI -> ESC [ */
|
|
|
|
|
|
case '\x9c': /* ST -> ESC \ */
|
|
|
|
|
|
case '\x9d': /* OSC -> ESC ] */
|
|
|
|
|
|
case '\x9e': /* PM -> ESC ^ */
|
|
|
|
|
|
case '\x9f': /* APC -> ESC _ */
|
|
|
|
|
|
break;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_print(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
/* 0x60 - 0x7e */
|
|
|
|
|
|
static const wchar_t vt100_0[] = {
|
|
|
|
|
|
L'◆', L'▒', L'␉', L'␌', L'␍', L'␊', L'°', L'±', /* ` - g */
|
|
|
|
|
|
L'', L'␋', L'┘', L'┐', L'┌', L'└', L'┼', L'⎺', /* h - o */
|
|
|
|
|
|
L'⎻', L'─', L'⎼', L'⎽', L'├', L'┤', L'┴', L'┬', /* p - w */
|
|
|
|
|
|
L'│', L'≤', L'≥', L'π', L'≠', L'£', L'·', /* x - ~ */
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2021-01-16 20:16:00 +00:00
|
|
|
|
xassert(wcwidth(c) == 1);
|
2020-07-16 08:01:37 +02:00
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
if (unlikely(term->charsets.set[term->charsets.selected] == CHARSET_GRAPHIC) &&
|
|
|
|
|
|
c >= 0x60 && c <= 0x7e)
|
|
|
|
|
|
{
|
2020-01-20 18:34:32 +01:00
|
|
|
|
term_print(term, vt100_0[c - 0x60], 1);
|
2019-12-20 23:27:15 +01:00
|
|
|
|
} else {
|
2020-01-20 18:34:32 +01:00
|
|
|
|
term_print(term, c, 1);
|
2019-12-20 23:27:15 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_param(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (term->vt.params.idx == 0) {
|
|
|
|
|
|
struct vt_param *param = &term->vt.params.v[0];
|
|
|
|
|
|
param->value = 0;
|
|
|
|
|
|
param->sub.idx = 0;
|
|
|
|
|
|
term->vt.params.idx = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-16 20:16:00 +00:00
|
|
|
|
xassert(term->vt.params.idx > 0);
|
2020-02-01 19:44:56 +01:00
|
|
|
|
|
|
|
|
|
|
const size_t max_params
|
|
|
|
|
|
= sizeof(term->vt.params.v) / sizeof(term->vt.params.v[0]);
|
|
|
|
|
|
const size_t max_sub_params
|
|
|
|
|
|
= sizeof(term->vt.params.v[0].sub.value) / sizeof(term->vt.params.v[0].sub.value[0]);
|
|
|
|
|
|
|
|
|
|
|
|
/* New parameter */
|
2019-12-20 23:27:15 +01:00
|
|
|
|
if (c == ';') {
|
2020-02-01 19:44:56 +01:00
|
|
|
|
if (unlikely(term->vt.params.idx >= max_params))
|
|
|
|
|
|
goto excess_params;
|
|
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
struct vt_param *param = &term->vt.params.v[term->vt.params.idx++];
|
|
|
|
|
|
param->value = 0;
|
|
|
|
|
|
param->sub.idx = 0;
|
2020-02-01 19:44:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* New sub-parameter */
|
|
|
|
|
|
else if (c == ':') {
|
|
|
|
|
|
if (unlikely(term->vt.params.idx - 1 >= max_params))
|
|
|
|
|
|
goto excess_params;
|
|
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
struct vt_param *param = &term->vt.params.v[term->vt.params.idx - 1];
|
2020-02-01 19:44:56 +01:00
|
|
|
|
if (unlikely(param->sub.idx >= max_sub_params))
|
|
|
|
|
|
goto excess_sub_params;
|
|
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
param->sub.value[param->sub.idx++] = 0;
|
2020-02-01 19:44:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* New digit for current parameter/sub-parameter */
|
|
|
|
|
|
else {
|
|
|
|
|
|
if (unlikely(term->vt.params.idx - 1 >= max_params))
|
|
|
|
|
|
goto excess_params;
|
|
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
struct vt_param *param = &term->vt.params.v[term->vt.params.idx - 1];
|
2020-02-01 19:44:56 +01:00
|
|
|
|
unsigned *value;
|
2019-12-20 23:27:15 +01:00
|
|
|
|
|
2020-02-01 19:44:56 +01:00
|
|
|
|
if (param->sub.idx > 0) {
|
|
|
|
|
|
if (unlikely(param->sub.idx - 1 >= max_sub_params))
|
|
|
|
|
|
goto excess_sub_params;
|
|
|
|
|
|
value = ¶m->sub.value[param->sub.idx - 1];
|
|
|
|
|
|
} else
|
|
|
|
|
|
value = ¶m->value;
|
2019-12-20 23:27:15 +01:00
|
|
|
|
|
|
|
|
|
|
*value *= 10;
|
|
|
|
|
|
*value += c - '0';
|
|
|
|
|
|
}
|
2020-02-01 19:44:56 +01:00
|
|
|
|
|
|
|
|
|
|
#if defined(_DEBUG)
|
|
|
|
|
|
/* The rest of the code assumes 'idx' *never* points outside the array */
|
2021-01-16 20:16:00 +00:00
|
|
|
|
xassert(term->vt.params.idx <= max_params);
|
2020-02-01 19:44:56 +01:00
|
|
|
|
for (size_t i = 0; i < term->vt.params.idx; i++)
|
2021-01-16 20:16:00 +00:00
|
|
|
|
xassert(term->vt.params.v[i].sub.idx <= max_sub_params);
|
2020-02-01 19:44:56 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
excess_params:
|
|
|
|
|
|
{
|
|
|
|
|
|
static bool have_warned = false;
|
|
|
|
|
|
if (!have_warned) {
|
|
|
|
|
|
have_warned = true;
|
|
|
|
|
|
LOG_WARN(
|
|
|
|
|
|
"unsupported: escape with more than %zu parameters "
|
|
|
|
|
|
"(will not warn again)",
|
|
|
|
|
|
sizeof(term->vt.params.v) / sizeof(term->vt.params.v[0]));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
excess_sub_params:
|
|
|
|
|
|
{
|
|
|
|
|
|
static bool have_warned = false;
|
|
|
|
|
|
if (!have_warned) {
|
|
|
|
|
|
have_warned = true;
|
|
|
|
|
|
LOG_WARN(
|
|
|
|
|
|
"unsupported: escape with more than %zu sub-parameters "
|
|
|
|
|
|
"(will not warn again)",
|
|
|
|
|
|
sizeof(term->vt.params.v[0].sub.value) / sizeof(term->vt.params.v[0].sub.value[0]));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
2019-12-20 23:27:15 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_collect(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
2020-02-01 19:29:14 +01:00
|
|
|
|
LOG_DBG("collect: %c", c);
|
vt: don’t ignore extra private/intermediate characters
Take ‘\E(#0’ for example - this is *not* the same as ‘\E(0’.
Up until now, foot has however treated them as the same escape,
because the handler for ‘\E(0’ didn’t verify there weren’t any _other_
private characters present.
Fix this by turning the ‘private’ array into a single 4-byte
integer. This allows us to match *all* privates with a single
comparison.
Private characters are added to the LSB first, and MSB last. This
means we can check for single privates in pretty much the same way as
before:
switch (term->vt.private) {
case ‘?’:
...
break;
}
Checking for two (or more) is much uglier, but foot only supports
a *single* escape with two privates, and no escapes with three or
more:
switch (term->vt.private) {
case 0x243f: /* ‘?$’ */
...
break;
}
The ‘clear’ action remains simple (and fast), with a single write
operation.
Collecting privates is potentially _slightly_ more complex than
before; we now need mask and compare, instead of simply comparing,
when checking how many privates we already have.
We _could_ add a counter, which would make collecting privates easier,
but this would add an additional write to the ‘clean’ action which is
really bad since it’s in the hot path.
2020-12-16 14:30:49 +01:00
|
|
|
|
|
|
|
|
|
|
/*
|
2020-12-16 15:06:34 +01:00
|
|
|
|
* Having more than one private is *very* rare. Foot only supports
|
vt: don’t ignore extra private/intermediate characters
Take ‘\E(#0’ for example - this is *not* the same as ‘\E(0’.
Up until now, foot has however treated them as the same escape,
because the handler for ‘\E(0’ didn’t verify there weren’t any _other_
private characters present.
Fix this by turning the ‘private’ array into a single 4-byte
integer. This allows us to match *all* privates with a single
comparison.
Private characters are added to the LSB first, and MSB last. This
means we can check for single privates in pretty much the same way as
before:
switch (term->vt.private) {
case ‘?’:
...
break;
}
Checking for two (or more) is much uglier, but foot only supports
a *single* escape with two privates, and no escapes with three or
more:
switch (term->vt.private) {
case 0x243f: /* ‘?$’ */
...
break;
}
The ‘clear’ action remains simple (and fast), with a single write
operation.
Collecting privates is potentially _slightly_ more complex than
before; we now need mask and compare, instead of simply comparing,
when checking how many privates we already have.
We _could_ add a counter, which would make collecting privates easier,
but this would add an additional write to the ‘clean’ action which is
really bad since it’s in the hot path.
2020-12-16 14:30:49 +01:00
|
|
|
|
* a *single* escape with two privates, and none with three or
|
|
|
|
|
|
* more.
|
|
|
|
|
|
*
|
|
|
|
|
|
* As such, we optimize *reading* the private(s), and *resetting*
|
|
|
|
|
|
* them (in action_clear()). Writing is ok if it’s a bit slow.
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
if ((term->vt.private & 0xff) == 0)
|
|
|
|
|
|
term->vt.private = c;
|
|
|
|
|
|
else if (((term->vt.private >> 8) & 0xff) == 0)
|
|
|
|
|
|
term->vt.private |= c << 8;
|
|
|
|
|
|
else if (((term->vt.private >> 16) & 0xff) == 0)
|
|
|
|
|
|
term->vt.private |= c << 16;
|
|
|
|
|
|
else if (((term->vt.private >> 24) & 0xff) == 0)
|
|
|
|
|
|
term->vt.private |= c << 24;
|
2019-12-20 23:27:15 +01:00
|
|
|
|
else
|
vt: don’t ignore extra private/intermediate characters
Take ‘\E(#0’ for example - this is *not* the same as ‘\E(0’.
Up until now, foot has however treated them as the same escape,
because the handler for ‘\E(0’ didn’t verify there weren’t any _other_
private characters present.
Fix this by turning the ‘private’ array into a single 4-byte
integer. This allows us to match *all* privates with a single
comparison.
Private characters are added to the LSB first, and MSB last. This
means we can check for single privates in pretty much the same way as
before:
switch (term->vt.private) {
case ‘?’:
...
break;
}
Checking for two (or more) is much uglier, but foot only supports
a *single* escape with two privates, and no escapes with three or
more:
switch (term->vt.private) {
case 0x243f: /* ‘?$’ */
...
break;
}
The ‘clear’ action remains simple (and fast), with a single write
operation.
Collecting privates is potentially _slightly_ more complex than
before; we now need mask and compare, instead of simply comparing,
when checking how many privates we already have.
We _could_ add a counter, which would make collecting privates easier,
but this would add an additional write to the ‘clean’ action which is
really bad since it’s in the hot path.
2020-12-16 14:30:49 +01:00
|
|
|
|
LOG_WARN("only four private/intermediate characters supported");
|
2019-12-20 23:27:15 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_esc_dispatch(struct terminal *term, uint8_t final)
|
2019-07-04 19:35:01 +02:00
|
|
|
|
{
|
|
|
|
|
|
LOG_DBG("ESC: %s", esc_as_string(term, final));
|
2019-06-23 13:36:20 +02:00
|
|
|
|
|
vt: don’t ignore extra private/intermediate characters
Take ‘\E(#0’ for example - this is *not* the same as ‘\E(0’.
Up until now, foot has however treated them as the same escape,
because the handler for ‘\E(0’ didn’t verify there weren’t any _other_
private characters present.
Fix this by turning the ‘private’ array into a single 4-byte
integer. This allows us to match *all* privates with a single
comparison.
Private characters are added to the LSB first, and MSB last. This
means we can check for single privates in pretty much the same way as
before:
switch (term->vt.private) {
case ‘?’:
...
break;
}
Checking for two (or more) is much uglier, but foot only supports
a *single* escape with two privates, and no escapes with three or
more:
switch (term->vt.private) {
case 0x243f: /* ‘?$’ */
...
break;
}
The ‘clear’ action remains simple (and fast), with a single write
operation.
Collecting privates is potentially _slightly_ more complex than
before; we now need mask and compare, instead of simply comparing,
when checking how many privates we already have.
We _could_ add a counter, which would make collecting privates easier,
but this would add an additional write to the ‘clean’ action which is
really bad since it’s in the hot path.
2020-12-16 14:30:49 +01:00
|
|
|
|
switch (term->vt.private) {
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case 0:
|
|
|
|
|
|
switch (final) {
|
|
|
|
|
|
case '7':
|
2021-01-15 17:08:30 +01:00
|
|
|
|
term_save_cursor(term);
|
2019-11-05 11:32:56 +01:00
|
|
|
|
break;
|
2019-07-17 10:39:38 +02:00
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case '8':
|
2020-04-16 18:51:14 +02:00
|
|
|
|
term_restore_cursor(term, &term->grid->saved_cursor);
|
2019-11-05 11:32:56 +01:00
|
|
|
|
break;
|
2019-06-29 20:49:00 +02:00
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case 'c':
|
|
|
|
|
|
term_reset(term, true);
|
|
|
|
|
|
break;
|
2019-06-29 20:49:00 +02:00
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case 'D':
|
|
|
|
|
|
term_linefeed(term);
|
|
|
|
|
|
break;
|
2019-07-10 16:05:19 +02:00
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case 'E':
|
2020-07-14 09:29:10 +02:00
|
|
|
|
term_carriage_return(term);
|
2019-11-05 11:32:56 +01:00
|
|
|
|
term_linefeed(term);
|
|
|
|
|
|
break;
|
2019-07-18 19:25:53 +02:00
|
|
|
|
|
2019-11-16 10:57:11 +01:00
|
|
|
|
case 'H':
|
|
|
|
|
|
tll_foreach(term->tab_stops, it) {
|
2020-04-16 18:51:14 +02:00
|
|
|
|
if (it->item >= term->grid->cursor.point.col) {
|
|
|
|
|
|
tll_insert_before(term->tab_stops, it, term->grid->cursor.point.col);
|
2019-11-16 10:57:11 +01:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-04-16 18:51:14 +02:00
|
|
|
|
tll_push_back(term->tab_stops, term->grid->cursor.point.col);
|
2019-11-16 10:57:11 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case 'M':
|
|
|
|
|
|
term_reverse_index(term);
|
|
|
|
|
|
break;
|
2019-07-10 16:05:01 +02:00
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case 'N':
|
|
|
|
|
|
/* SS2 - Single Shift 2 */
|
2019-11-17 09:59:12 +01:00
|
|
|
|
term->charsets.selected = 2; /* G2 */
|
2019-11-05 11:32:56 +01:00
|
|
|
|
break;
|
2019-07-18 19:25:53 +02:00
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case 'O':
|
|
|
|
|
|
/* SS3 - Single Shift 3 */
|
2019-11-17 09:59:12 +01:00
|
|
|
|
term->charsets.selected = 3; /* G3 */
|
2019-11-05 11:32:56 +01:00
|
|
|
|
break;
|
2019-07-18 19:25:53 +02:00
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case '\\':
|
|
|
|
|
|
/* ST - String Terminator */
|
|
|
|
|
|
break;
|
2019-07-10 16:05:19 +02:00
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case '=':
|
|
|
|
|
|
term->keypad_keys_mode = KEYPAD_APPLICATION;
|
|
|
|
|
|
break;
|
2019-07-03 16:21:26 +02:00
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case '>':
|
|
|
|
|
|
term->keypad_keys_mode = KEYPAD_NUMERICAL;
|
|
|
|
|
|
break;
|
2019-07-03 16:21:26 +02:00
|
|
|
|
|
|
|
|
|
|
default:
|
2019-07-30 21:42:46 +02:00
|
|
|
|
UNHANDLED();
|
2019-07-07 16:32:18 +02:00
|
|
|
|
break;
|
2019-07-03 16:21:26 +02:00
|
|
|
|
}
|
2019-11-05 11:32:56 +01:00
|
|
|
|
break; /* private[0] == 0 */
|
|
|
|
|
|
|
|
|
|
|
|
case '(':
|
|
|
|
|
|
case ')':
|
|
|
|
|
|
case '*':
|
|
|
|
|
|
case '+':
|
|
|
|
|
|
switch (final) {
|
|
|
|
|
|
case '0': {
|
vt: don’t ignore extra private/intermediate characters
Take ‘\E(#0’ for example - this is *not* the same as ‘\E(0’.
Up until now, foot has however treated them as the same escape,
because the handler for ‘\E(0’ didn’t verify there weren’t any _other_
private characters present.
Fix this by turning the ‘private’ array into a single 4-byte
integer. This allows us to match *all* privates with a single
comparison.
Private characters are added to the LSB first, and MSB last. This
means we can check for single privates in pretty much the same way as
before:
switch (term->vt.private) {
case ‘?’:
...
break;
}
Checking for two (or more) is much uglier, but foot only supports
a *single* escape with two privates, and no escapes with three or
more:
switch (term->vt.private) {
case 0x243f: /* ‘?$’ */
...
break;
}
The ‘clear’ action remains simple (and fast), with a single write
operation.
Collecting privates is potentially _slightly_ more complex than
before; we now need mask and compare, instead of simply comparing,
when checking how many privates we already have.
We _could_ add a counter, which would make collecting privates easier,
but this would add an additional write to the ‘clean’ action which is
really bad since it’s in the hot path.
2020-12-16 14:30:49 +01:00
|
|
|
|
char priv = term->vt.private;
|
2019-11-05 11:32:56 +01:00
|
|
|
|
ssize_t idx = priv ==
|
|
|
|
|
|
'(' ? 0 :
|
|
|
|
|
|
')' ? 1 :
|
|
|
|
|
|
'*' ? 2 :
|
|
|
|
|
|
'+' ? 3 : -1;
|
2021-01-16 20:16:00 +00:00
|
|
|
|
xassert(idx != -1);
|
2019-11-17 09:59:12 +01:00
|
|
|
|
term->charsets.set[idx] = CHARSET_GRAPHIC;
|
2019-11-05 11:32:56 +01:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
2019-06-29 20:49:00 +02:00
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case 'B': {
|
vt: don’t ignore extra private/intermediate characters
Take ‘\E(#0’ for example - this is *not* the same as ‘\E(0’.
Up until now, foot has however treated them as the same escape,
because the handler for ‘\E(0’ didn’t verify there weren’t any _other_
private characters present.
Fix this by turning the ‘private’ array into a single 4-byte
integer. This allows us to match *all* privates with a single
comparison.
Private characters are added to the LSB first, and MSB last. This
means we can check for single privates in pretty much the same way as
before:
switch (term->vt.private) {
case ‘?’:
...
break;
}
Checking for two (or more) is much uglier, but foot only supports
a *single* escape with two privates, and no escapes with three or
more:
switch (term->vt.private) {
case 0x243f: /* ‘?$’ */
...
break;
}
The ‘clear’ action remains simple (and fast), with a single write
operation.
Collecting privates is potentially _slightly_ more complex than
before; we now need mask and compare, instead of simply comparing,
when checking how many privates we already have.
We _could_ add a counter, which would make collecting privates easier,
but this would add an additional write to the ‘clean’ action which is
really bad since it’s in the hot path.
2020-12-16 14:30:49 +01:00
|
|
|
|
char priv = term->vt.private;
|
2019-11-05 11:32:56 +01:00
|
|
|
|
ssize_t idx = priv ==
|
|
|
|
|
|
'(' ? 0 :
|
|
|
|
|
|
')' ? 1 :
|
|
|
|
|
|
'*' ? 2 :
|
|
|
|
|
|
'+' ? 3 : -1;
|
2021-01-16 20:16:00 +00:00
|
|
|
|
xassert(idx != -1);
|
2019-11-17 09:59:12 +01:00
|
|
|
|
term->charsets.set[idx] = CHARSET_ASCII;
|
2019-06-23 13:36:20 +02:00
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-06-23 13:36:20 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
|
case '#':
|
|
|
|
|
|
switch (final) {
|
|
|
|
|
|
case '8':
|
|
|
|
|
|
for (int r = 0; r < term->rows; r++) {
|
2019-11-14 11:08:49 +01:00
|
|
|
|
struct row *row = grid_row(term->grid, r);
|
2019-11-05 11:32:56 +01:00
|
|
|
|
for (int c = 0; c < term->cols; c++) {
|
|
|
|
|
|
row->cells[c].wc = L'E';
|
|
|
|
|
|
row->cells[c].attrs.clean = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
row->dirty = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
break; /* private[0] == '#' */
|
|
|
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
static void
|
|
|
|
|
|
action_csi_dispatch(struct terminal *term, uint8_t c)
|
2019-11-17 17:22:16 +01:00
|
|
|
|
{
|
2019-12-20 23:27:15 +01:00
|
|
|
|
csi_dispatch(term, c);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_osc_start(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
term->vt.osc.idx = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_osc_end(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!osc_ensure_size(term, term->vt.osc.idx + 1))
|
2019-11-30 00:32:34 +01:00
|
|
|
|
return;
|
2019-12-20 23:27:15 +01:00
|
|
|
|
term->vt.osc.data[term->vt.osc.idx] = '\0';
|
|
|
|
|
|
osc_dispatch(term);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_osc_put(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!osc_ensure_size(term, term->vt.osc.idx + 1))
|
2019-11-30 00:32:34 +01:00
|
|
|
|
return;
|
2019-12-20 23:27:15 +01:00
|
|
|
|
term->vt.osc.data[term->vt.osc.idx++] = c;
|
|
|
|
|
|
}
|
2019-11-30 00:32:34 +01:00
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
static void
|
|
|
|
|
|
action_hook(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
2020-01-12 11:55:22 +01:00
|
|
|
|
dcs_hook(term, c);
|
2019-11-17 17:22:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
static void
|
|
|
|
|
|
action_unhook(struct terminal *term, uint8_t c)
|
2019-07-07 16:32:18 +02:00
|
|
|
|
{
|
2020-01-12 11:55:22 +01:00
|
|
|
|
dcs_unhook(term);
|
2019-07-07 16:32:18 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
static void
|
|
|
|
|
|
action_put(struct terminal *term, uint8_t c)
|
2019-07-07 16:32:18 +02:00
|
|
|
|
{
|
2020-01-12 11:55:22 +01:00
|
|
|
|
dcs_put(term, c);
|
2019-12-20 23:27:15 +01:00
|
|
|
|
}
|
2019-11-30 00:15:05 +01:00
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
static void
|
2020-06-07 16:16:50 +02:00
|
|
|
|
action_utf8_print(struct terminal *term, wchar_t wc)
|
2019-12-20 23:27:15 +01:00
|
|
|
|
{
|
2020-05-02 16:11:51 +02:00
|
|
|
|
int width = wcwidth(wc);
|
|
|
|
|
|
|
utf8: add support for unicode combining characters
This feature lets foot combine e.g. "a\u0301" to "á".
We first check if the current character (that we're about to print) is
a combining character, by checking if it's in one of the following
ranges:
* Combining Diacritical Marks (0300–036F), since version 1.0, with
modifications in subsequent versions down to 4.1
* Combining Diacritical Marks Extended (1AB0–1AFF), version 7.0
* Combining Diacritical Marks Supplement (1DC0–1DFF), versions 4.1 to 5.2
* Combining Diacritical Marks for Symbols (20D0–20FF), since version
1.0, with modifications in subsequent versions down to 5.1
* Combining Half Marks (FE20–FE2F), versions 1.0, with modifications
in subsequent versions down to 8.0
If it is, we check if the last cell appears to contain a valid symbol,
and if so, we attempt to compose (combine) the last cell with the
current character, using utf8proc.
If the result is a combined character, we replace the content in the
previous cell with the new, combined character.
Thus, if you select and copy the printed character, you would get
e.g. "\u00e1" instead of "a\u0301".
This feature can be disabled. By default, it is enabled if the
utf8proc library is found, but can be explicitly disabled, or enabled,
with 'meson -Dunicode-combining=disabled|enabled'.
2020-04-27 12:13:30 +02:00
|
|
|
|
/*
|
2020-05-02 16:11:51 +02:00
|
|
|
|
* Is this is combining character? The basic assumption is that if
|
|
|
|
|
|
* wcwdith() returns 0, then it *is* a combining character.
|
|
|
|
|
|
*
|
|
|
|
|
|
* We hen optimize this by ignoring all characters before 0x0300,
|
|
|
|
|
|
* since there aren't any zero-width characters there. This means
|
|
|
|
|
|
* all "normal" western characters will quickly be categorized as
|
|
|
|
|
|
* *not* being combining characters.
|
utf8: add support for unicode combining characters
This feature lets foot combine e.g. "a\u0301" to "á".
We first check if the current character (that we're about to print) is
a combining character, by checking if it's in one of the following
ranges:
* Combining Diacritical Marks (0300–036F), since version 1.0, with
modifications in subsequent versions down to 4.1
* Combining Diacritical Marks Extended (1AB0–1AFF), version 7.0
* Combining Diacritical Marks Supplement (1DC0–1DFF), versions 4.1 to 5.2
* Combining Diacritical Marks for Symbols (20D0–20FF), since version
1.0, with modifications in subsequent versions down to 5.1
* Combining Half Marks (FE20–FE2F), versions 1.0, with modifications
in subsequent versions down to 8.0
If it is, we check if the last cell appears to contain a valid symbol,
and if so, we attempt to compose (combine) the last cell with the
current character, using utf8proc.
If the result is a combined character, we replace the content in the
previous cell with the new, combined character.
Thus, if you select and copy the printed character, you would get
e.g. "\u00e1" instead of "a\u0301".
This feature can be disabled. By default, it is enabled if the
utf8proc library is found, but can be explicitly disabled, or enabled,
with 'meson -Dunicode-combining=disabled|enabled'.
2020-04-27 12:13:30 +02:00
|
|
|
|
*
|
2020-05-02 16:11:51 +02:00
|
|
|
|
* TODO: xterm does more or less the same, but also filters a
|
|
|
|
|
|
* small subset of BIDI control characters. Should we too? I think
|
|
|
|
|
|
* what we have here is good enough - a control character
|
|
|
|
|
|
* shouldn't have a glyph associated with it, so rendering
|
|
|
|
|
|
* shouldn't be affected.
|
|
|
|
|
|
*
|
|
|
|
|
|
* TODO: handle line-wrap when locating the base character.
|
utf8: add support for unicode combining characters
This feature lets foot combine e.g. "a\u0301" to "á".
We first check if the current character (that we're about to print) is
a combining character, by checking if it's in one of the following
ranges:
* Combining Diacritical Marks (0300–036F), since version 1.0, with
modifications in subsequent versions down to 4.1
* Combining Diacritical Marks Extended (1AB0–1AFF), version 7.0
* Combining Diacritical Marks Supplement (1DC0–1DFF), versions 4.1 to 5.2
* Combining Diacritical Marks for Symbols (20D0–20FF), since version
1.0, with modifications in subsequent versions down to 5.1
* Combining Half Marks (FE20–FE2F), versions 1.0, with modifications
in subsequent versions down to 8.0
If it is, we check if the last cell appears to contain a valid symbol,
and if so, we attempt to compose (combine) the last cell with the
current character, using utf8proc.
If the result is a combined character, we replace the content in the
previous cell with the new, combined character.
Thus, if you select and copy the printed character, you would get
e.g. "\u00e1" instead of "a\u0301".
This feature can be disabled. By default, it is enabled if the
utf8proc library is found, but can be explicitly disabled, or enabled,
with 'meson -Dunicode-combining=disabled|enabled'.
2020-04-27 12:13:30 +02:00
|
|
|
|
*/
|
2020-06-09 17:30:49 +02:00
|
|
|
|
if (width == 0 && wc >= 0x0300 && term->grid->cursor.point.col > 0) {
|
2020-05-01 11:52:40 +02:00
|
|
|
|
const struct row *row = term->grid->cur_row;
|
|
|
|
|
|
|
utf8: add support for unicode combining characters
This feature lets foot combine e.g. "a\u0301" to "á".
We first check if the current character (that we're about to print) is
a combining character, by checking if it's in one of the following
ranges:
* Combining Diacritical Marks (0300–036F), since version 1.0, with
modifications in subsequent versions down to 4.1
* Combining Diacritical Marks Extended (1AB0–1AFF), version 7.0
* Combining Diacritical Marks Supplement (1DC0–1DFF), versions 4.1 to 5.2
* Combining Diacritical Marks for Symbols (20D0–20FF), since version
1.0, with modifications in subsequent versions down to 5.1
* Combining Half Marks (FE20–FE2F), versions 1.0, with modifications
in subsequent versions down to 8.0
If it is, we check if the last cell appears to contain a valid symbol,
and if so, we attempt to compose (combine) the last cell with the
current character, using utf8proc.
If the result is a combined character, we replace the content in the
previous cell with the new, combined character.
Thus, if you select and copy the printed character, you would get
e.g. "\u00e1" instead of "a\u0301".
This feature can be disabled. By default, it is enabled if the
utf8proc library is found, but can be explicitly disabled, or enabled,
with 'meson -Dunicode-combining=disabled|enabled'.
2020-04-27 12:13:30 +02:00
|
|
|
|
int base_col = term->grid->cursor.point.col;
|
|
|
|
|
|
if (!term->grid->cursor.lcf)
|
|
|
|
|
|
base_col--;
|
|
|
|
|
|
|
2020-07-16 07:41:51 +02:00
|
|
|
|
while (row->cells[base_col].wc == CELL_MULT_COL_SPACER && base_col > 0)
|
|
|
|
|
|
base_col--;
|
|
|
|
|
|
|
2021-01-16 20:16:00 +00:00
|
|
|
|
xassert(base_col >= 0 && base_col < term->cols);
|
2020-05-01 11:52:40 +02:00
|
|
|
|
wchar_t base = row->cells[base_col].wc;
|
|
|
|
|
|
|
unicode-combining: store seen combining chains "globally" in the term struct
Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.
When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.
When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).
Then we render the grapheme pretty much like before.
2020-05-03 11:03:22 +02:00
|
|
|
|
const struct composed *composed =
|
2020-07-14 16:41:57 +02:00
|
|
|
|
(base >= CELL_COMB_CHARS_LO &&
|
|
|
|
|
|
base < (CELL_COMB_CHARS_LO + term->composed_count))
|
|
|
|
|
|
? &term->composed[base - CELL_COMB_CHARS_LO]
|
unicode-combining: store seen combining chains "globally" in the term struct
Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.
When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.
When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).
Then we render the grapheme pretty much like before.
2020-05-03 11:03:22 +02:00
|
|
|
|
: NULL;
|
|
|
|
|
|
|
|
|
|
|
|
if (composed != NULL)
|
|
|
|
|
|
base = composed->base;
|
|
|
|
|
|
|
utf8: add support for unicode combining characters
This feature lets foot combine e.g. "a\u0301" to "á".
We first check if the current character (that we're about to print) is
a combining character, by checking if it's in one of the following
ranges:
* Combining Diacritical Marks (0300–036F), since version 1.0, with
modifications in subsequent versions down to 4.1
* Combining Diacritical Marks Extended (1AB0–1AFF), version 7.0
* Combining Diacritical Marks Supplement (1DC0–1DFF), versions 4.1 to 5.2
* Combining Diacritical Marks for Symbols (20D0–20FF), since version
1.0, with modifications in subsequent versions down to 5.1
* Combining Half Marks (FE20–FE2F), versions 1.0, with modifications
in subsequent versions down to 8.0
If it is, we check if the last cell appears to contain a valid symbol,
and if so, we attempt to compose (combine) the last cell with the
current character, using utf8proc.
If the result is a combined character, we replace the content in the
previous cell with the new, combined character.
Thus, if you select and copy the printed character, you would get
e.g. "\u00e1" instead of "a\u0301".
This feature can be disabled. By default, it is enabled if the
utf8proc library is found, but can be explicitly disabled, or enabled,
with 'meson -Dunicode-combining=disabled|enabled'.
2020-04-27 12:13:30 +02:00
|
|
|
|
int base_width = wcwidth(base);
|
|
|
|
|
|
|
2020-05-01 11:52:40 +02:00
|
|
|
|
if (base != 0 && base_width > 0) {
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2020-05-01 20:17:37 +02:00
|
|
|
|
* If this is the *first* combining characger, see if
|
|
|
|
|
|
* there's a pre-composed character of this combo, with
|
|
|
|
|
|
* the same column width as the base character.
|
|
|
|
|
|
*
|
|
|
|
|
|
* If there is, replace the base character with the
|
|
|
|
|
|
* pre-composed character, as that is likely to produce a
|
|
|
|
|
|
* better looking result.
|
2020-05-01 11:52:40 +02:00
|
|
|
|
*/
|
unicode-combining: store seen combining chains "globally" in the term struct
Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.
When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.
When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).
Then we render the grapheme pretty much like before.
2020-05-03 11:03:22 +02:00
|
|
|
|
term->grid->cursor.point.col = base_col;
|
|
|
|
|
|
term->grid->cursor.lcf = false;
|
utf8: add support for unicode combining characters
This feature lets foot combine e.g. "a\u0301" to "á".
We first check if the current character (that we're about to print) is
a combining character, by checking if it's in one of the following
ranges:
* Combining Diacritical Marks (0300–036F), since version 1.0, with
modifications in subsequent versions down to 4.1
* Combining Diacritical Marks Extended (1AB0–1AFF), version 7.0
* Combining Diacritical Marks Supplement (1DC0–1DFF), versions 4.1 to 5.2
* Combining Diacritical Marks for Symbols (20D0–20FF), since version
1.0, with modifications in subsequent versions down to 5.1
* Combining Half Marks (FE20–FE2F), versions 1.0, with modifications
in subsequent versions down to 8.0
If it is, we check if the last cell appears to contain a valid symbol,
and if so, we attempt to compose (combine) the last cell with the
current character, using utf8proc.
If the result is a combined character, we replace the content in the
previous cell with the new, combined character.
Thus, if you select and copy the printed character, you would get
e.g. "\u00e1" instead of "a\u0301".
This feature can be disabled. By default, it is enabled if the
utf8proc library is found, but can be explicitly disabled, or enabled,
with 'meson -Dunicode-combining=disabled|enabled'.
2020-04-27 12:13:30 +02:00
|
|
|
|
|
unicode-combining: store seen combining chains "globally" in the term struct
Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.
When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.
When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).
Then we render the grapheme pretty much like before.
2020-05-03 11:03:22 +02:00
|
|
|
|
if (composed == NULL) {
|
2020-05-08 23:36:33 +02:00
|
|
|
|
bool base_from_primary;
|
|
|
|
|
|
bool comb_from_primary;
|
|
|
|
|
|
bool pre_from_primary;
|
|
|
|
|
|
|
|
|
|
|
|
wchar_t precomposed = fcft_precompose(
|
|
|
|
|
|
term->fonts[0], base, wc, &base_from_primary,
|
|
|
|
|
|
&comb_from_primary, &pre_from_primary);
|
|
|
|
|
|
|
2020-05-02 17:29:00 +02:00
|
|
|
|
int precomposed_width = wcwidth(precomposed);
|
2020-05-08 23:36:33 +02:00
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
* Only use the pre-composed character if:
|
|
|
|
|
|
*
|
|
|
|
|
|
* 1. we *have* a pre-composed character
|
|
|
|
|
|
* 2. the width matches the base characters width
|
|
|
|
|
|
* 3. it's in the primary font, OR one of the base or
|
|
|
|
|
|
* combining characters are *not* from the primary
|
|
|
|
|
|
* font
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
if (precomposed != (wchar_t)-1 &&
|
|
|
|
|
|
precomposed_width == base_width &&
|
|
|
|
|
|
(pre_from_primary ||
|
|
|
|
|
|
!base_from_primary ||
|
|
|
|
|
|
!comb_from_primary))
|
|
|
|
|
|
{
|
2020-05-02 17:29:00 +02:00
|
|
|
|
term_print(term, precomposed, precomposed_width);
|
2020-05-01 20:17:37 +02:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
utf8: add support for unicode combining characters
This feature lets foot combine e.g. "a\u0301" to "á".
We first check if the current character (that we're about to print) is
a combining character, by checking if it's in one of the following
ranges:
* Combining Diacritical Marks (0300–036F), since version 1.0, with
modifications in subsequent versions down to 4.1
* Combining Diacritical Marks Extended (1AB0–1AFF), version 7.0
* Combining Diacritical Marks Supplement (1DC0–1DFF), versions 4.1 to 5.2
* Combining Diacritical Marks for Symbols (20D0–20FF), since version
1.0, with modifications in subsequent versions down to 5.1
* Combining Half Marks (FE20–FE2F), versions 1.0, with modifications
in subsequent versions down to 8.0
If it is, we check if the last cell appears to contain a valid symbol,
and if so, we attempt to compose (combine) the last cell with the
current character, using utf8proc.
If the result is a combined character, we replace the content in the
previous cell with the new, combined character.
Thus, if you select and copy the printed character, you would get
e.g. "\u00e1" instead of "a\u0301".
This feature can be disabled. By default, it is enabled if the
utf8proc library is found, but can be explicitly disabled, or enabled,
with 'meson -Dunicode-combining=disabled|enabled'.
2020-04-27 12:13:30 +02:00
|
|
|
|
}
|
2020-05-01 11:52:40 +02:00
|
|
|
|
|
unicode-combining: store seen combining chains "globally" in the term struct
Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.
When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.
When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).
Then we render the grapheme pretty much like before.
2020-05-03 11:03:22 +02:00
|
|
|
|
size_t wanted_count = composed != NULL ? composed->count + 1 : 1;
|
2020-05-03 11:27:06 +02:00
|
|
|
|
if (wanted_count > ALEN(composed->combining)) {
|
2021-01-16 20:16:00 +00:00
|
|
|
|
xassert(composed != NULL);
|
2020-05-03 11:27:06 +02:00
|
|
|
|
|
2020-06-09 17:31:58 +02:00
|
|
|
|
#if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
|
2020-05-03 11:27:06 +02:00
|
|
|
|
LOG_WARN("combining character overflow:");
|
|
|
|
|
|
LOG_WARN(" base: 0x%04x", composed->base);
|
|
|
|
|
|
for (size_t i = 0; i < composed->count; i++)
|
|
|
|
|
|
LOG_WARN(" cc: 0x%04x", composed->combining[i]);
|
|
|
|
|
|
LOG_ERR(" new: 0x%04x", wc);
|
2020-06-09 17:31:58 +02:00
|
|
|
|
#endif
|
2020-05-03 11:27:06 +02:00
|
|
|
|
/* This are going to break anyway... */
|
|
|
|
|
|
wanted_count--;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-16 20:16:00 +00:00
|
|
|
|
xassert(wanted_count <= ALEN(composed->combining));
|
unicode-combining: store seen combining chains "globally" in the term struct
Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.
When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.
When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).
Then we render the grapheme pretty much like before.
2020-05-03 11:03:22 +02:00
|
|
|
|
|
|
|
|
|
|
/* Look for existing combining chain */
|
|
|
|
|
|
for (size_t i = 0; i < term->composed_count; i++) {
|
|
|
|
|
|
const struct composed *cc = &term->composed[i];
|
|
|
|
|
|
if (cc->base != base)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (cc->count != wanted_count)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if (cc->combining[wanted_count - 1] != wc)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
2020-07-14 16:41:57 +02:00
|
|
|
|
term_print(term, CELL_COMB_CHARS_LO + i, base_width);
|
unicode-combining: store seen combining chains "globally" in the term struct
Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.
When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.
When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).
Then we render the grapheme pretty much like before.
2020-05-03 11:03:22 +02:00
|
|
|
|
return;
|
2020-05-01 11:52:40 +02:00
|
|
|
|
}
|
unicode-combining: store seen combining chains "globally" in the term struct
Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.
When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.
When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).
Then we render the grapheme pretty much like before.
2020-05-03 11:03:22 +02:00
|
|
|
|
|
|
|
|
|
|
/* Allocate new chain */
|
|
|
|
|
|
|
|
|
|
|
|
struct composed new_cc;
|
|
|
|
|
|
new_cc.base = base;
|
|
|
|
|
|
new_cc.count = wanted_count;
|
|
|
|
|
|
for (size_t i = 0; i < wanted_count - 1; i++)
|
|
|
|
|
|
new_cc.combining[i] = composed->combining[i];
|
|
|
|
|
|
new_cc.combining[wanted_count - 1] = wc;
|
|
|
|
|
|
|
2020-07-14 16:41:57 +02:00
|
|
|
|
if (term->composed_count < CELL_COMB_CHARS_HI) {
|
2020-05-03 11:31:59 +02:00
|
|
|
|
term->composed_count++;
|
2020-08-08 20:34:30 +01:00
|
|
|
|
term->composed = xrealloc(term->composed, term->composed_count * sizeof(term->composed[0]));
|
2020-05-03 11:31:59 +02:00
|
|
|
|
term->composed[term->composed_count - 1] = new_cc;
|
unicode-combining: store seen combining chains "globally" in the term struct
Instead of storing combining data per cell, realize that most
combinations are re-occurring and that there's lots of available space
left in the unicode range, and store seen base+combining combinations
chains in a per-terminal array.
When we encounter a combining character, we first try to pre-compose,
like before. If that fails, we then search for the current
base+combining combo in the list of previously seen combinations. If
not found there either, we allocate a new combo and add it to the
list. Regardless, the result is an index into this array. We store
this index, offsetted by COMB_CHARS_LO=0x40000000ul in the cell.
When rendering, we need to check if the cell character is a plain
character, or if it's a composed character (identified by checking if
the cell character is >= COMB_CHARS_LO).
Then we render the grapheme pretty much like before.
2020-05-03 11:03:22 +02:00
|
|
|
|
|
2020-07-14 16:41:57 +02:00
|
|
|
|
term_print(term, CELL_COMB_CHARS_LO + term->composed_count - 1, base_width);
|
2020-05-03 11:31:59 +02:00
|
|
|
|
return;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
/* We reached our maximum number of allowed composed
|
|
|
|
|
|
* character chains. Fall through here and print the
|
|
|
|
|
|
* current zero-width character to the current cell */
|
|
|
|
|
|
LOG_WARN("maximum number of composed characters reached");
|
|
|
|
|
|
}
|
utf8: add support for unicode combining characters
This feature lets foot combine e.g. "a\u0301" to "á".
We first check if the current character (that we're about to print) is
a combining character, by checking if it's in one of the following
ranges:
* Combining Diacritical Marks (0300–036F), since version 1.0, with
modifications in subsequent versions down to 4.1
* Combining Diacritical Marks Extended (1AB0–1AFF), version 7.0
* Combining Diacritical Marks Supplement (1DC0–1DFF), versions 4.1 to 5.2
* Combining Diacritical Marks for Symbols (20D0–20FF), since version
1.0, with modifications in subsequent versions down to 5.1
* Combining Half Marks (FE20–FE2F), versions 1.0, with modifications
in subsequent versions down to 8.0
If it is, we check if the last cell appears to contain a valid symbol,
and if so, we attempt to compose (combine) the last cell with the
current character, using utf8proc.
If the result is a combined character, we replace the content in the
previous cell with the new, combined character.
Thus, if you select and copy the printed character, you would get
e.g. "\u00e1" instead of "a\u0301".
This feature can be disabled. By default, it is enabled if the
utf8proc library is found, but can be explicitly disabled, or enabled,
with 'meson -Dunicode-combining=disabled|enabled'.
2020-04-27 12:13:30 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-16 08:04:12 +02:00
|
|
|
|
if (width > 0)
|
|
|
|
|
|
term_print(term, wc, width);
|
2019-06-23 13:36:20 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-07 16:16:50 +02:00
|
|
|
|
static void
|
|
|
|
|
|
action_utf8_21(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
// wc = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)
|
|
|
|
|
|
term->vt.utf8 = (c & 0x1f) << 6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_utf8_22(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
// wc = ((utf8[0] & 0x1f) << 6) | (utf8[1] & 0x3f)
|
|
|
|
|
|
term->vt.utf8 |= c & 0x3f;
|
|
|
|
|
|
action_utf8_print(term, term->vt.utf8);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_utf8_31(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
// wc = ((utf8[0] & 0xf) << 12) | ((utf8[1] & 0x3f) << 6) | (utf8[2] & 0x3f)
|
|
|
|
|
|
term->vt.utf8 = (c & 0x0f) << 12;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_utf8_32(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
// wc = ((utf8[0] & 0xf) << 12) | ((utf8[1] & 0x3f) << 6) | (utf8[2] & 0x3f)
|
|
|
|
|
|
term->vt.utf8 |= (c & 0x3f) << 6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_utf8_33(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
// wc = ((utf8[0] & 0xf) << 12) | ((utf8[1] & 0x3f) << 6) | (utf8[2] & 0x3f)
|
|
|
|
|
|
term->vt.utf8 |= c & 0x3f;
|
|
|
|
|
|
action_utf8_print(term, term->vt.utf8);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_utf8_41(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
// wc = ((utf8[0] & 7) << 18) | ((utf8[1] & 0x3f) << 12) | ((utf8[2] & 0x3f) << 6) | (utf8[3] & 0x3f);
|
|
|
|
|
|
term->vt.utf8 = (c & 0x07) << 18;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_utf8_42(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
// wc = ((utf8[0] & 7) << 18) | ((utf8[1] & 0x3f) << 12) | ((utf8[2] & 0x3f) << 6) | (utf8[3] & 0x3f);
|
|
|
|
|
|
term->vt.utf8 |= (c & 0x3f) << 12;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_utf8_43(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
// wc = ((utf8[0] & 7) << 18) | ((utf8[1] & 0x3f) << 12) | ((utf8[2] & 0x3f) << 6) | (utf8[3] & 0x3f);
|
|
|
|
|
|
term->vt.utf8 |= (c & 0x3f) << 6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
|
action_utf8_44(struct terminal *term, uint8_t c)
|
|
|
|
|
|
{
|
|
|
|
|
|
// wc = ((utf8[0] & 7) << 18) | ((utf8[1] & 0x3f) << 12) | ((utf8[2] & 0x3f) << 6) | (utf8[3] & 0x3f);
|
|
|
|
|
|
term->vt.utf8 |= c & 0x3f;
|
|
|
|
|
|
action_utf8_print(term, term->vt.utf8);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-03 08:56:47 +00:00
|
|
|
|
IGNORE_WARNING("-Wpedantic")
|
2020-08-23 09:38:37 +02:00
|
|
|
|
|
2019-12-20 19:16:52 +01:00
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_ground_switch(struct terminal *term, uint8_t data)
|
2019-12-20 19:16:52 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 19:16:52 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x1c ... 0x1f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
|
2020-07-16 08:01:37 +02:00
|
|
|
|
/* modified from 0x20..0x7f to 0x20..0x7e, since 0x7f is DEL, which is a zero-width character */
|
|
|
|
|
|
case 0x20 ... 0x7e: action_print(term, data); return STATE_GROUND;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
|
2020-06-07 16:16:50 +02:00
|
|
|
|
case 0xc2 ... 0xdf: action_utf8_21(term, data); return STATE_UTF8_21;
|
|
|
|
|
|
case 0xe0 ... 0xef: action_utf8_31(term, data); return STATE_UTF8_31;
|
|
|
|
|
|
case 0xf0 ... 0xf4: action_utf8_41(term, data); return STATE_UTF8_41;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_GROUND;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_escape_switch(struct terminal *term, uint8_t data)
|
2019-12-20 19:16:52 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 19:16:52 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x1c ... 0x1f: action_execute(term, data); return STATE_ESCAPE;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x20 ... 0x2f: action_collect(term, data); return STATE_ESCAPE_INTERMEDIATE;
|
|
|
|
|
|
case 0x30 ... 0x4f: action_esc_dispatch(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x50: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x51 ... 0x57: action_esc_dispatch(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x58: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x59: action_esc_dispatch(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x5a: action_esc_dispatch(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x5b: action_clear(term); return STATE_CSI_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x5c: action_esc_dispatch(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x5d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x5e ... 0x5f: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x60 ... 0x7e: action_esc_dispatch(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x7f: action_ignore(term); return STATE_ESCAPE;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_ESCAPE;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_escape_intermediate_switch(struct terminal *term, uint8_t data)
|
2019-12-20 19:16:52 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 19:16:52 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x1c ... 0x1f: action_execute(term, data); return STATE_ESCAPE_INTERMEDIATE;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x20 ... 0x2f: action_collect(term, data); return STATE_ESCAPE_INTERMEDIATE;
|
|
|
|
|
|
case 0x30 ... 0x7e: action_esc_dispatch(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x7f: action_ignore(term); return STATE_ESCAPE_INTERMEDIATE;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_ESCAPE_INTERMEDIATE;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-20 20:57:38 +01:00
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_csi_entry_switch(struct terminal *term, uint8_t data)
|
2019-12-20 20:57:38 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 20:57:38 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x1c ... 0x1f: action_execute(term, data); return STATE_CSI_ENTRY;
|
2019-12-20 20:57:38 +01:00
|
|
|
|
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x20 ... 0x2f: action_collect(term, data); return STATE_CSI_INTERMEDIATE;
|
|
|
|
|
|
case 0x30 ... 0x39: action_param(term, data); return STATE_CSI_PARAM;
|
2020-01-26 00:44:53 +01:00
|
|
|
|
case 0x3a ... 0x3b: action_param(term, data); return STATE_CSI_PARAM;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x3c ... 0x3f: action_collect(term, data); return STATE_CSI_PARAM;
|
|
|
|
|
|
case 0x40 ... 0x7e: action_csi_dispatch(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x7f: action_ignore(term); return STATE_CSI_ENTRY;
|
2019-12-20 20:57:38 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_CSI_ENTRY;
|
2019-12-20 20:57:38 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-20 21:04:47 +01:00
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_csi_param_switch(struct terminal *term, uint8_t data)
|
2019-12-20 21:04:47 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 21:04:47 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x1c ... 0x1f: action_execute(term, data); return STATE_CSI_PARAM;
|
2019-12-20 21:04:47 +01:00
|
|
|
|
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x20 ... 0x2f: action_collect(term, data); return STATE_CSI_INTERMEDIATE;
|
2019-12-20 21:04:47 +01:00
|
|
|
|
|
|
|
|
|
|
case 0x30 ... 0x39:
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x3a ... 0x3b: action_param(term, data); return STATE_CSI_PARAM;
|
2019-12-20 21:04:47 +01:00
|
|
|
|
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x3c ... 0x3f: return STATE_CSI_IGNORE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x40 ... 0x7e: action_csi_dispatch(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x7f: action_ignore(term); return STATE_CSI_PARAM;
|
2019-12-20 21:04:47 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_CSI_PARAM;
|
2019-12-20 21:04:47 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-20 21:09:00 +01:00
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_csi_intermediate_switch(struct terminal *term, uint8_t data)
|
2019-12-20 21:09:00 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 21:09:00 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x1c ... 0x1f: action_execute(term, data); return STATE_CSI_INTERMEDIATE;
|
2019-12-20 21:09:00 +01:00
|
|
|
|
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x20 ... 0x2f: action_collect(term, data); return STATE_CSI_INTERMEDIATE;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x30 ... 0x3f: return STATE_CSI_IGNORE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x40 ... 0x7e: action_csi_dispatch(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x7f: action_ignore(term); return STATE_CSI_INTERMEDIATE;
|
2019-12-20 21:09:00 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_CSI_INTERMEDIATE;
|
2019-12-20 21:09:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-20 21:13:06 +01:00
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_csi_ignore_switch(struct terminal *term, uint8_t data)
|
2019-12-20 21:13:06 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 21:13:06 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x1c ... 0x1f: action_execute(term, data); return STATE_CSI_IGNORE;
|
2019-12-20 21:13:06 +01:00
|
|
|
|
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x20 ... 0x3f: action_ignore(term); return STATE_CSI_IGNORE;
|
|
|
|
|
|
case 0x40 ... 0x7e: return STATE_GROUND;
|
|
|
|
|
|
case 0x7f: action_ignore(term); return STATE_CSI_IGNORE;
|
2019-12-20 21:13:06 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_CSI_IGNORE;
|
2019-12-20 21:13:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-20 21:48:04 +01:00
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_osc_string_switch(struct terminal *term, uint8_t data)
|
2019-12-20 21:48:04 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
|
|
|
|
|
/* Note: original was 20-7f, but I changed to 20-ff to include utf-8. Don't forget to add EXECUTE to 8-bit C1 if we implement that. */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
default: action_osc_put(term, data); return STATE_OSC_STRING;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x07: action_osc_end(term, data); return STATE_GROUND;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
|
|
|
|
|
case 0x00 ... 0x06:
|
|
|
|
|
|
case 0x08 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1c ... 0x1f: action_ignore(term); return STATE_OSC_STRING;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case 0x18:
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x1a: action_osc_end(term, data); action_execute(term, data); return STATE_GROUND;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x1b: action_osc_end(term, data); action_clear(term); return STATE_ESCAPE;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_dcs_entry_switch(struct terminal *term, uint8_t data)
|
2019-12-20 21:48:04 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 21:48:04 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1c ... 0x1f: action_ignore(term); return STATE_DCS_ENTRY;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x20 ... 0x2f: action_collect(term, data); return STATE_DCS_INTERMEDIATE;
|
|
|
|
|
|
case 0x30 ... 0x39: action_param(term, data); return STATE_DCS_PARAM;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x3a: return STATE_DCS_IGNORE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x3b: action_param(term, data); return STATE_DCS_PARAM;
|
|
|
|
|
|
case 0x3c ... 0x3f: action_collect(term, data); return STATE_DCS_PARAM;
|
|
|
|
|
|
case 0x40 ... 0x7e: action_hook(term, data); return STATE_DCS_PASSTHROUGH;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x7f: action_ignore(term); return STATE_DCS_ENTRY;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_DCS_ENTRY;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_dcs_param_switch(struct terminal *term, uint8_t data)
|
2019-12-20 21:48:04 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 21:48:04 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1c ... 0x1f: action_ignore(term); return STATE_DCS_PARAM;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x20 ... 0x2f: action_collect(term, data); return STATE_DCS_INTERMEDIATE;
|
|
|
|
|
|
case 0x30 ... 0x39: action_param(term, data); return STATE_DCS_PARAM;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x3a: return STATE_DCS_IGNORE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x3b: action_param(term, data); return STATE_DCS_PARAM;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x3c ... 0x3f: return STATE_DCS_IGNORE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x40 ... 0x7e: action_hook(term, data); return STATE_DCS_PASSTHROUGH;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x7f: action_ignore(term); return STATE_DCS_PARAM;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_DCS_PARAM;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_dcs_intermediate_switch(struct terminal *term, uint8_t data)
|
2019-12-20 21:48:04 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 21:48:04 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1c ... 0x1f: action_ignore(term); return STATE_DCS_INTERMEDIATE;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x20 ... 0x2f: action_collect(term, data); return STATE_DCS_INTERMEDIATE;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x30 ... 0x3f: return STATE_DCS_IGNORE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x40 ... 0x7e: action_hook(term, data); return STATE_DCS_PASSTHROUGH;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x7f: action_ignore(term); return STATE_DCS_INTERMEDIATE;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_DCS_INTERMEDIATE;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_dcs_ignore_switch(struct terminal *term, uint8_t data)
|
2019-12-20 21:48:04 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 21:48:04 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
|
|
|
|
|
case 0x1c ... 0x1f:
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x20 ... 0x7f: action_ignore(term); return STATE_DCS_IGNORE;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_DCS_IGNORE;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_dcs_passthrough_switch(struct terminal *term, uint8_t data)
|
2019-12-20 21:48:04 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 21:48:04 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x1c ... 0x7e: action_put(term, data); return STATE_DCS_PASSTHROUGH;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x7f: action_ignore(term); return STATE_DCS_PASSTHROUGH;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1b: action_unhook(term, data); action_clear(term); return STATE_ESCAPE;
|
|
|
|
|
|
case 0x80 ... 0x8f: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x90: action_unhook(term, data); action_clear(term); return STATE_DCS_ENTRY;
|
|
|
|
|
|
case 0x91 ... 0x97: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x98: action_unhook(term, data); return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
case 0x99: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_unhook(term, data); action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9b: action_unhook(term, data); action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: action_unhook(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9d: action_unhook(term, data); action_osc_start(term, data); return STATE_OSC_STRING;
|
|
|
|
|
|
case 0x9e ... 0x9f: action_unhook(term, data); return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
|
|
|
|
|
|
default: return STATE_DCS_PASSTHROUGH;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-20 21:50:54 +01:00
|
|
|
|
static enum state
|
2019-12-20 23:59:23 +01:00
|
|
|
|
state_sos_pm_apc_string_switch(struct terminal *term, uint8_t data)
|
2019-12-20 21:50:54 +01:00
|
|
|
|
{
|
2019-12-20 23:59:23 +01:00
|
|
|
|
switch (data) {
|
2019-12-20 23:38:16 +01:00
|
|
|
|
/* exit current enter new state */
|
2019-12-20 21:50:54 +01:00
|
|
|
|
case 0x00 ... 0x17:
|
|
|
|
|
|
case 0x19:
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1c ... 0x7f: action_ignore(term); return STATE_SOS_PM_APC_STRING;
|
2019-12-20 21:50:54 +01:00
|
|
|
|
|
|
|
|
|
|
/* Anywhere */
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x18: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x1a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x80 ... 0x8f: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x91 ... 0x97: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x99: action_execute(term, data); return STATE_GROUND;
|
|
|
|
|
|
case 0x9a: action_execute(term, data); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9b: action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
|
case 0x9c: return STATE_GROUND;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
case 0x9d: action_osc_start(term, data); return STATE_OSC_STRING;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
case 0x9e ... 0x9f: return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
|
|
|
|
|
|
|
default: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 21:50:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-20 22:10:27 +01:00
|
|
|
|
static enum state
|
2020-06-07 16:16:50 +02:00
|
|
|
|
state_utf8_21_switch(struct terminal *term, uint8_t data)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (data) {
|
|
|
|
|
|
/* exit current enter new state */
|
|
|
|
|
|
case 0x80 ... 0xbf: action_utf8_22(term, data); return STATE_GROUND;
|
|
|
|
|
|
default: action_utf8_print(term, 0); return STATE_GROUND;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
|
|
|
|
|
state_utf8_31_switch(struct terminal *term, uint8_t data)
|
2019-12-20 22:10:27 +01:00
|
|
|
|
{
|
2020-06-07 16:16:50 +02:00
|
|
|
|
switch (data) {
|
|
|
|
|
|
/* exit current enter new state */
|
|
|
|
|
|
case 0x80 ... 0xbf: action_utf8_32(term, data); return STATE_UTF8_32;
|
|
|
|
|
|
default: action_utf8_print(term, 0); return STATE_GROUND;
|
|
|
|
|
|
}
|
2019-12-20 22:10:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
2020-06-07 16:16:50 +02:00
|
|
|
|
state_utf8_32_switch(struct terminal *term, uint8_t data)
|
2019-12-20 22:10:27 +01:00
|
|
|
|
{
|
2020-06-07 16:16:50 +02:00
|
|
|
|
switch (data) {
|
|
|
|
|
|
/* exit current enter new state */
|
|
|
|
|
|
case 0x80 ... 0xbf: action_utf8_33(term, data); return STATE_GROUND;
|
|
|
|
|
|
default: action_utf8_print(term, 0); return STATE_GROUND;
|
|
|
|
|
|
}
|
2019-12-20 22:10:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
2020-06-07 16:16:50 +02:00
|
|
|
|
state_utf8_41_switch(struct terminal *term, uint8_t data)
|
2019-12-20 22:10:27 +01:00
|
|
|
|
{
|
2020-06-07 16:16:50 +02:00
|
|
|
|
switch (data) {
|
|
|
|
|
|
/* exit current enter new state */
|
|
|
|
|
|
case 0x80 ... 0xbf: action_utf8_42(term, data); return STATE_UTF8_42;
|
|
|
|
|
|
default: action_utf8_print(term, 0); return STATE_GROUND;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
|
|
|
|
|
state_utf8_42_switch(struct terminal *term, uint8_t data)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (data) {
|
|
|
|
|
|
/* exit current enter new state */
|
|
|
|
|
|
case 0x80 ... 0xbf: action_utf8_43(term, data); return STATE_UTF8_43;
|
|
|
|
|
|
default: action_utf8_print(term, 0); return STATE_GROUND;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static enum state
|
|
|
|
|
|
state_utf8_43_switch(struct terminal *term, uint8_t data)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (data) {
|
|
|
|
|
|
/* exit current enter new state */
|
|
|
|
|
|
case 0x80 ... 0xbf: action_utf8_44(term, data); return STATE_GROUND;
|
|
|
|
|
|
default: action_utf8_print(term, 0); return STATE_GROUND;
|
|
|
|
|
|
}
|
2019-12-20 22:10:27 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-03 08:56:47 +00:00
|
|
|
|
UNIGNORE_WARNINGS
|
2020-08-23 09:38:37 +02:00
|
|
|
|
|
2019-06-15 22:22:44 +02:00
|
|
|
|
void
|
|
|
|
|
|
vt_from_slave(struct terminal *term, const uint8_t *data, size_t len)
|
|
|
|
|
|
{
|
2019-12-20 23:00:07 +01:00
|
|
|
|
enum state current_state = term->vt.state;
|
|
|
|
|
|
|
|
|
|
|
|
const uint8_t *p = data;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
for (size_t i = 0; i < len; i++, p++) {
|
|
|
|
|
|
switch (current_state) {
|
|
|
|
|
|
case STATE_GROUND: current_state = state_ground_switch(term, *p); break;
|
|
|
|
|
|
case STATE_ESCAPE: current_state = state_escape_switch(term, *p); break;
|
|
|
|
|
|
case STATE_ESCAPE_INTERMEDIATE: current_state = state_escape_intermediate_switch(term, *p); break;
|
|
|
|
|
|
case STATE_CSI_ENTRY: current_state = state_csi_entry_switch(term, *p); break;
|
|
|
|
|
|
case STATE_CSI_PARAM: current_state = state_csi_param_switch(term, *p); break;
|
|
|
|
|
|
case STATE_CSI_INTERMEDIATE: current_state = state_csi_intermediate_switch(term, *p); break;
|
|
|
|
|
|
case STATE_CSI_IGNORE: current_state = state_csi_ignore_switch(term, *p); break;
|
|
|
|
|
|
case STATE_OSC_STRING: current_state = state_osc_string_switch(term, *p); break;
|
|
|
|
|
|
case STATE_DCS_ENTRY: current_state = state_dcs_entry_switch(term, *p); break;
|
|
|
|
|
|
case STATE_DCS_PARAM: current_state = state_dcs_param_switch(term, *p); break;
|
|
|
|
|
|
case STATE_DCS_INTERMEDIATE: current_state = state_dcs_intermediate_switch(term, *p); break;
|
|
|
|
|
|
case STATE_DCS_IGNORE: current_state = state_dcs_ignore_switch(term, *p); break;
|
|
|
|
|
|
case STATE_DCS_PASSTHROUGH: current_state = state_dcs_passthrough_switch(term, *p); break;
|
|
|
|
|
|
case STATE_SOS_PM_APC_STRING: current_state = state_sos_pm_apc_string_switch(term, *p); break;
|
|
|
|
|
|
|
2020-06-07 16:16:50 +02:00
|
|
|
|
case STATE_UTF8_21: current_state = state_utf8_21_switch(term, *p); break;
|
|
|
|
|
|
case STATE_UTF8_31: current_state = state_utf8_31_switch(term, *p); break;
|
|
|
|
|
|
case STATE_UTF8_32: current_state = state_utf8_32_switch(term, *p); break;
|
|
|
|
|
|
case STATE_UTF8_41: current_state = state_utf8_41_switch(term, *p); break;
|
|
|
|
|
|
case STATE_UTF8_42: current_state = state_utf8_42_switch(term, *p); break;
|
|
|
|
|
|
case STATE_UTF8_43: current_state = state_utf8_43_switch(term, *p); break;
|
2019-12-20 23:59:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-12-20 22:12:35 +01:00
|
|
|
|
|
|
|
|
|
|
term->vt.state = current_state;
|
2019-06-15 22:22:44 +02:00
|
|
|
|
}
|