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
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
#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"
|
2019-06-17 19:33:10 +02:00
|
|
|
#include "grid.h"
|
2019-07-19 09:55:07 +02:00
|
|
|
#include "osc.h"
|
2019-06-15 22:22:44 +02:00
|
|
|
|
2019-11-30 00:32:34 +01:00
|
|
|
#define min(x, y) ((x) < (y) ? (x) : (y))
|
2019-08-30 22:08:37 +02:00
|
|
|
#define max(x, y) ((x) > (y) ? (x) : (y))
|
|
|
|
|
|
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,
|
|
|
|
|
|
2019-12-20 22:10:27 +01:00
|
|
|
STATE_UTF8_COLLECT_1,
|
|
|
|
|
STATE_UTF8_COLLECT_2,
|
|
|
|
|
STATE_UTF8_COLLECT_3,
|
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",
|
|
|
|
|
|
2019-12-20 22:10:27 +01:00
|
|
|
[STATE_UTF8_COLLECT_1] = "UTF8 collect (1 left)",
|
|
|
|
|
[STATE_UTF8_COLLECT_2] = "UTF8 collect (2 left)",
|
|
|
|
|
[STATE_UTF8_COLLECT_3] = "UTF8 collect (3 left)",
|
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
|
|
|
|
2019-07-19 09:56:59 +02:00
|
|
|
for (size_t i = 0; i < sizeof(term->vt.private) / sizeof(term->vt.private[0]); i++) {
|
|
|
|
|
if (term->vt.private[i] == 0)
|
|
|
|
|
break;
|
|
|
|
|
c += snprintf(&msg[c], sizeof(msg) - c, "%c", term->vt.private[i]);
|
|
|
|
|
}
|
2019-06-23 13:36:20 +02:00
|
|
|
|
2019-07-15 13:39:19 +02:00
|
|
|
assert(term->vt.params.idx == 0);
|
|
|
|
|
|
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-12-20 23:27:15 +01:00
|
|
|
static inline void
|
|
|
|
|
pre_print(struct terminal *term)
|
|
|
|
|
{
|
|
|
|
|
if (likely(!term->cursor.lcf))
|
|
|
|
|
return;
|
|
|
|
|
if (unlikely(!term->auto_margin))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (term->cursor.point.row == term->scroll_region.end - 1) {
|
|
|
|
|
term_scroll(term, 1);
|
|
|
|
|
term_cursor_to(term, term->cursor.point.row, 0);
|
|
|
|
|
} else
|
|
|
|
|
term_cursor_to(term, min(term->cursor.point.row + 1, term->rows - 1), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
post_print(struct terminal *term)
|
|
|
|
|
{
|
|
|
|
|
if (term->cursor.point.col < term->cols - 1)
|
|
|
|
|
term_cursor_right(term, 1);
|
|
|
|
|
else
|
|
|
|
|
term->cursor.lcf = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
print_insert(struct terminal *term, int width)
|
|
|
|
|
{
|
|
|
|
|
assert(width > 0);
|
|
|
|
|
if (unlikely(term->insert_mode)) {
|
|
|
|
|
struct row *row = term->grid->cur_row;
|
|
|
|
|
const size_t move_count = max(0, term->cols - term->cursor.point.col - width);
|
|
|
|
|
|
|
|
|
|
memmove(
|
|
|
|
|
&row->cells[term->cursor.point.col + width],
|
|
|
|
|
&row->cells[term->cursor.point.col],
|
|
|
|
|
move_count * sizeof(struct cell));
|
|
|
|
|
|
|
|
|
|
/* Mark moved cells as dirty */
|
|
|
|
|
for (size_t i = term->cursor.point.col + width; i < term->cols; i++)
|
|
|
|
|
row->cells[i].attrs.clean = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
term->vt.private[0] = 0;
|
|
|
|
|
term->vt.private[1] = 0;
|
|
|
|
|
term->vt.utf8.idx = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
case '\n':
|
|
|
|
|
/* LF - line feed */
|
|
|
|
|
term_linefeed(term);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '\r':
|
|
|
|
|
/* FF - form feed */
|
|
|
|
|
term_cursor_left(term, term->cursor.point.col);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '\b':
|
|
|
|
|
/* backspace */
|
|
|
|
|
term_cursor_left(term, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '\x07':
|
|
|
|
|
/* BEL */
|
|
|
|
|
// LOG_INFO("BELL");
|
|
|
|
|
// term_flash(term, 50);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '\x09': {
|
|
|
|
|
/* HT - horizontal tab */
|
|
|
|
|
int new_col = term->cols - 1;
|
|
|
|
|
tll_foreach(term->tab_stops, it) {
|
|
|
|
|
if (it->item > term->cursor.point.col) {
|
|
|
|
|
new_col = it->item;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
assert(new_col >= term->cursor.point.col);
|
|
|
|
|
term_cursor_right(term, new_col - term->cursor.point.col);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case '\x0b':
|
|
|
|
|
/* VT - vertical tab */
|
|
|
|
|
term_cursor_down(term, 1);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
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...
|
|
|
|
|
*/
|
|
|
|
|
#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)
|
|
|
|
|
{
|
|
|
|
|
pre_print(term);
|
|
|
|
|
|
|
|
|
|
struct row *row = term->grid->cur_row;
|
|
|
|
|
struct cell *cell = &row->cells[term->cursor.point.col];
|
|
|
|
|
|
|
|
|
|
row->dirty = true;
|
|
|
|
|
cell->attrs.clean = 0;
|
|
|
|
|
|
|
|
|
|
print_insert(term, 1);
|
|
|
|
|
|
|
|
|
|
/* 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 - ~ */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (unlikely(term->charsets.set[term->charsets.selected] == CHARSET_GRAPHIC) &&
|
|
|
|
|
c >= 0x60 && c <= 0x7e)
|
|
|
|
|
{
|
|
|
|
|
cell->wc = vt100_0[c - 0x60];
|
|
|
|
|
} else {
|
|
|
|
|
// LOG_DBG("print: ASCII: %c (0x%04x)", c, c);
|
|
|
|
|
cell->wc = c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cell->attrs = term->vt.attrs;
|
|
|
|
|
post_print(term);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c == ';') {
|
|
|
|
|
struct vt_param *param = &term->vt.params.v[term->vt.params.idx++];
|
|
|
|
|
param->value = 0;
|
|
|
|
|
param->sub.idx = 0;
|
|
|
|
|
} else if (c == ':') {
|
|
|
|
|
struct vt_param *param = &term->vt.params.v[term->vt.params.idx - 1];
|
|
|
|
|
param->sub.value[param->sub.idx++] = 0;
|
|
|
|
|
} else {
|
|
|
|
|
assert(term->vt.params.idx >= 0);
|
|
|
|
|
struct vt_param *param = &term->vt.params.v[term->vt.params.idx - 1];
|
|
|
|
|
|
|
|
|
|
unsigned *value = param->sub.idx > 0
|
|
|
|
|
? ¶m->sub.value[param->sub.idx - 1]
|
|
|
|
|
: ¶m->value;
|
|
|
|
|
|
|
|
|
|
*value *= 10;
|
|
|
|
|
*value += c - '0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
action_collect(struct terminal *term, uint8_t c)
|
|
|
|
|
{
|
|
|
|
|
LOG_DBG("collect");
|
|
|
|
|
if (term->vt.private[0] == 0)
|
|
|
|
|
term->vt.private[0] = c;
|
|
|
|
|
else if (term->vt.private[1] == 0)
|
|
|
|
|
term->vt.private[1] = c;
|
|
|
|
|
else
|
|
|
|
|
LOG_DBG("only two private/intermediate characters supported");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
2019-11-05 11:32:56 +01:00
|
|
|
switch (term->vt.private[0]) {
|
|
|
|
|
case 0:
|
|
|
|
|
switch (final) {
|
|
|
|
|
case '7':
|
|
|
|
|
term->saved_cursor = term->cursor;
|
|
|
|
|
term->vt.saved_attrs = term->vt.attrs;
|
2019-11-17 10:02:46 +01:00
|
|
|
term->saved_charsets = term->charsets;
|
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':
|
|
|
|
|
term_restore_cursor(term);
|
|
|
|
|
term->vt.attrs = term->vt.saved_attrs;
|
2019-11-17 10:02:46 +01:00
|
|
|
term->charsets = term->saved_charsets;
|
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':
|
|
|
|
|
term_linefeed(term);
|
2019-11-17 09:44:31 +01:00
|
|
|
term_cursor_left(term, term->cursor.point.col);
|
2019-11-05 11:32:56 +01:00
|
|
|
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) {
|
2019-11-17 09:44:31 +01:00
|
|
|
if (it->item >= term->cursor.point.col) {
|
|
|
|
|
tll_insert_before(term->tab_stops, it, term->cursor.point.col);
|
2019-11-16 10:57:11 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-17 09:44:31 +01:00
|
|
|
tll_push_back(term->tab_stops, term->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': {
|
|
|
|
|
char priv = term->vt.private[0];
|
|
|
|
|
ssize_t idx = priv ==
|
|
|
|
|
'(' ? 0 :
|
|
|
|
|
')' ? 1 :
|
|
|
|
|
'*' ? 2 :
|
|
|
|
|
'+' ? 3 : -1;
|
|
|
|
|
assert(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': {
|
|
|
|
|
char priv = term->vt.private[0];
|
|
|
|
|
ssize_t idx = priv ==
|
|
|
|
|
'(' ? 0 :
|
|
|
|
|
')' ? 1 :
|
|
|
|
|
'*' ? 2 :
|
|
|
|
|
'+' ? 3 : -1;
|
|
|
|
|
assert(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)
|
|
|
|
|
{
|
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
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
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
|
|
|
|
|
action_utf8_2_entry(struct terminal *term, uint8_t c)
|
|
|
|
|
{
|
|
|
|
|
term->vt.utf8.idx = 0;
|
|
|
|
|
term->vt.utf8.left = 2;
|
|
|
|
|
term->vt.utf8.data[term->vt.utf8.idx++] = c;
|
|
|
|
|
term->vt.utf8.left--;
|
|
|
|
|
}
|
2019-11-30 00:15:05 +01:00
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
static void
|
|
|
|
|
action_utf8_3_entry(struct terminal *term, uint8_t c)
|
|
|
|
|
{
|
|
|
|
|
term->vt.utf8.idx = 0;
|
|
|
|
|
term->vt.utf8.left = 3;
|
|
|
|
|
term->vt.utf8.data[term->vt.utf8.idx++] = c;
|
|
|
|
|
term->vt.utf8.left--;
|
2019-07-07 16:32:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2019-12-20 23:27:15 +01:00
|
|
|
action_utf8_4_entry(struct terminal *term, uint8_t c)
|
|
|
|
|
{
|
|
|
|
|
term->vt.utf8.idx = 0;
|
|
|
|
|
term->vt.utf8.left = 4;
|
|
|
|
|
term->vt.utf8.data[term->vt.utf8.idx++] = c;
|
|
|
|
|
term->vt.utf8.left--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
action_utf8_print(struct terminal *term, uint8_t c)
|
2019-07-07 16:32:18 +02:00
|
|
|
{
|
2019-11-17 17:22:16 +01:00
|
|
|
pre_print(term);
|
2019-07-07 16:32:18 +02:00
|
|
|
|
2019-07-08 13:57:31 +02:00
|
|
|
struct row *row = term->grid->cur_row;
|
2019-11-17 09:44:31 +01:00
|
|
|
struct cell *cell = &row->cells[term->cursor.point.col];
|
font: initial support for double-width *and* color emoji glyphs
Fonts are now loaded with FT_LOAD_COLOR and we recognize and support
the FT_PIXEL_MODE_BGRA pixel mode.
This is mapped to a CAIRO_FORMAT_ARGB32 surface, that is blitted
as-is (instead of used as a mask like we do for gray and mono glyphs).
Furthermore, since many emojis are double-width, we add initial
support for double-width glyphs.
These are assumed to always be utf8. When PRINT:ing an utf8 character,
we check its width, and add empty "spacer" cells after the cell with
the multi-column glyph.
When rendering, we render the columns in each row backwards. This
ensures the spacer cells get cleared *before* we render the glyph (so
that we don't end up erasing part of the glyph).
Finally, emoji fonts are usually bitmap fonts with *large*
glyphs. These aren't automatically scaled down. I.e. even if we
request a glyph of 13 pixels, we might end up getting a 100px glyph.
To handle this, fontconfig must be configured to scale bitmap
fonts. When it is, we can look at the 'scalable' and 'pixelsizefixup'
properties, and use these to scale the rendered glyph.
2019-07-31 18:03:35 +02:00
|
|
|
|
2019-08-30 22:08:37 +02:00
|
|
|
/* Convert to wchar */
|
|
|
|
|
mbstate_t ps = {0};
|
|
|
|
|
wchar_t wc;
|
|
|
|
|
if (mbrtowc(&wc, (const char *)term->vt.utf8.data, term->vt.utf8.idx, &ps) < 0)
|
|
|
|
|
wc = 0;
|
|
|
|
|
|
|
|
|
|
int width = wcwidth(wc);
|
2019-11-30 00:15:05 +01:00
|
|
|
if (width > 0)
|
|
|
|
|
print_insert(term, width);
|
2019-08-30 22:08:37 +02:00
|
|
|
|
2019-07-08 13:57:31 +02:00
|
|
|
row->dirty = true;
|
2019-08-30 22:08:37 +02:00
|
|
|
cell->wc = wc;
|
2019-07-30 18:03:03 +02:00
|
|
|
cell->attrs.clean = 0;
|
2019-08-30 22:08:37 +02:00
|
|
|
cell->attrs = term->vt.attrs;
|
2019-06-23 13:36:20 +02:00
|
|
|
|
2019-08-30 22:08:37 +02:00
|
|
|
/* Reset VT utf8 state */
|
2019-07-07 16:32:18 +02:00
|
|
|
term->vt.utf8.idx = 0;
|
|
|
|
|
|
2019-08-02 18:19:07 +02:00
|
|
|
if (width <= 0) {
|
|
|
|
|
/* Skip post_print() below - i.e. don't advance cursor */
|
|
|
|
|
return;
|
|
|
|
|
}
|
font: initial support for double-width *and* color emoji glyphs
Fonts are now loaded with FT_LOAD_COLOR and we recognize and support
the FT_PIXEL_MODE_BGRA pixel mode.
This is mapped to a CAIRO_FORMAT_ARGB32 surface, that is blitted
as-is (instead of used as a mask like we do for gray and mono glyphs).
Furthermore, since many emojis are double-width, we add initial
support for double-width glyphs.
These are assumed to always be utf8. When PRINT:ing an utf8 character,
we check its width, and add empty "spacer" cells after the cell with
the multi-column glyph.
When rendering, we render the columns in each row backwards. This
ensures the spacer cells get cleared *before* we render the glyph (so
that we don't end up erasing part of the glyph).
Finally, emoji fonts are usually bitmap fonts with *large*
glyphs. These aren't automatically scaled down. I.e. even if we
request a glyph of 13 pixels, we might end up getting a 100px glyph.
To handle this, fontconfig must be configured to scale bitmap
fonts. When it is, we can look at the 'scalable' and 'pixelsizefixup'
properties, and use these to scale the rendered glyph.
2019-07-31 18:03:35 +02:00
|
|
|
|
2019-08-02 18:19:07 +02:00
|
|
|
/* Advance cursor the 'additional' columns (last step is done
|
|
|
|
|
* by post_print()) */
|
2019-11-17 09:44:31 +01:00
|
|
|
for (int i = 1; i < width && term->cursor.point.col < term->cols - 1; i++) {
|
2019-08-02 18:19:07 +02:00
|
|
|
term_cursor_right(term, 1);
|
font: initial support for double-width *and* color emoji glyphs
Fonts are now loaded with FT_LOAD_COLOR and we recognize and support
the FT_PIXEL_MODE_BGRA pixel mode.
This is mapped to a CAIRO_FORMAT_ARGB32 surface, that is blitted
as-is (instead of used as a mask like we do for gray and mono glyphs).
Furthermore, since many emojis are double-width, we add initial
support for double-width glyphs.
These are assumed to always be utf8. When PRINT:ing an utf8 character,
we check its width, and add empty "spacer" cells after the cell with
the multi-column glyph.
When rendering, we render the columns in each row backwards. This
ensures the spacer cells get cleared *before* we render the glyph (so
that we don't end up erasing part of the glyph).
Finally, emoji fonts are usually bitmap fonts with *large*
glyphs. These aren't automatically scaled down. I.e. even if we
request a glyph of 13 pixels, we might end up getting a 100px glyph.
To handle this, fontconfig must be configured to scale bitmap
fonts. When it is, we can look at the 'scalable' and 'pixelsizefixup'
properties, and use these to scale the rendered glyph.
2019-07-31 18:03:35 +02:00
|
|
|
|
2019-11-17 09:44:31 +01:00
|
|
|
assert(term->cursor.point.col < term->cols);
|
|
|
|
|
struct cell *cell = &row->cells[term->cursor.point.col];
|
2019-08-02 18:19:07 +02:00
|
|
|
cell->wc = 0;
|
|
|
|
|
cell->attrs.clean = 0;
|
font: initial support for double-width *and* color emoji glyphs
Fonts are now loaded with FT_LOAD_COLOR and we recognize and support
the FT_PIXEL_MODE_BGRA pixel mode.
This is mapped to a CAIRO_FORMAT_ARGB32 surface, that is blitted
as-is (instead of used as a mask like we do for gray and mono glyphs).
Furthermore, since many emojis are double-width, we add initial
support for double-width glyphs.
These are assumed to always be utf8. When PRINT:ing an utf8 character,
we check its width, and add empty "spacer" cells after the cell with
the multi-column glyph.
When rendering, we render the columns in each row backwards. This
ensures the spacer cells get cleared *before* we render the glyph (so
that we don't end up erasing part of the glyph).
Finally, emoji fonts are usually bitmap fonts with *large*
glyphs. These aren't automatically scaled down. I.e. even if we
request a glyph of 13 pixels, we might end up getting a 100px glyph.
To handle this, fontconfig must be configured to scale bitmap
fonts. When it is, we can look at the 'scalable' and 'pixelsizefixup'
properties, and use these to scale the rendered glyph.
2019-07-31 18:03:35 +02:00
|
|
|
}
|
|
|
|
|
|
2019-07-07 16:32:18 +02:00
|
|
|
post_print(term);
|
2019-06-23 13:36:20 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-20 19:16:52 +01:00
|
|
|
static enum state
|
2019-12-20 23:45:21 +01:00
|
|
|
state_ground_switch(struct terminal *term, uint8_t c)
|
2019-12-20 19:16:52 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x1c ... 0x1f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x20 ... 0x7f: action_print(term, c); return STATE_GROUND;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0xc0 ... 0xdf: action_utf8_2_entry(term, c); return STATE_UTF8_COLLECT_1;
|
|
|
|
|
case 0xe0 ... 0xef: action_utf8_3_entry(term, c); return STATE_UTF8_COLLECT_2;
|
|
|
|
|
case 0xf0 ... 0xf7: action_utf8_4_entry(term, c); return STATE_UTF8_COLLECT_3;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
2019-12-20 23:27:15 +01:00
|
|
|
/* Anywhere */
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
state_escape_switch(struct terminal *term, uint8_t c)
|
2019-12-20 19:16:52 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x1c ... 0x1f: action_execute(term, c); return STATE_ESCAPE;
|
2019-12-20 23:38:16 +01:00
|
|
|
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x20 ... 0x2f: action_collect(term, c); return STATE_ESCAPE_INTERMEDIATE;
|
|
|
|
|
case 0x30 ... 0x4f: action_esc_dispatch(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x50: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x51 ... 0x57: action_esc_dispatch(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x58: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x59: action_esc_dispatch(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x5a: action_esc_dispatch(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x5b: action_clear(term); return STATE_CSI_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x5c: action_esc_dispatch(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x5d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
case 0x60 ... 0x7e: action_esc_dispatch(term, c); 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:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
state_escape_intermediate_switch(struct terminal *term, uint8_t c)
|
2019-12-20 19:16:52 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x1c ... 0x1f: action_execute(term, c); return STATE_ESCAPE_INTERMEDIATE;
|
2019-12-20 19:16:52 +01:00
|
|
|
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x20 ... 0x2f: action_collect(term, c); return STATE_ESCAPE_INTERMEDIATE;
|
|
|
|
|
case 0x30 ... 0x7e: action_esc_dispatch(term, c); 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:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
state_csi_entry_switch(struct terminal *term, uint8_t c)
|
2019-12-20 20:57:38 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x1c ... 0x1f: action_execute(term, c); return STATE_CSI_ENTRY;
|
2019-12-20 20:57:38 +01:00
|
|
|
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x20 ... 0x2f: action_collect(term, c); return STATE_CSI_INTERMEDIATE;
|
|
|
|
|
case 0x30 ... 0x39: action_param(term, c); return STATE_CSI_PARAM;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x3a ... 0x3b: return STATE_CSI_PARAM;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x3c ... 0x3f: action_collect(term, c); return STATE_CSI_PARAM;
|
|
|
|
|
case 0x40 ... 0x7e: action_csi_dispatch(term, c); 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:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
state_csi_param_switch(struct terminal *term, uint8_t c)
|
2019-12-20 21:04:47 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x1c ... 0x1f: action_execute(term, c); return STATE_CSI_PARAM;
|
2019-12-20 21:04:47 +01:00
|
|
|
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x20 ... 0x2f: action_collect(term, c); return STATE_CSI_INTERMEDIATE;
|
2019-12-20 21:04:47 +01:00
|
|
|
|
|
|
|
|
case 0x30 ... 0x39:
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x3a ... 0x3b: action_param(term, c); 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:45:21 +01:00
|
|
|
case 0x40 ... 0x7e: action_csi_dispatch(term, c); 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:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
state_csi_intermediate_switch(struct terminal *term, uint8_t c)
|
2019-12-20 21:09:00 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x1c ... 0x1f: action_execute(term, c); return STATE_CSI_INTERMEDIATE;
|
2019-12-20 21:09:00 +01:00
|
|
|
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x20 ... 0x2f: action_collect(term, c); return STATE_CSI_INTERMEDIATE;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x30 ... 0x3f: return STATE_CSI_IGNORE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x40 ... 0x7e: action_csi_dispatch(term, c); 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:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
state_csi_ignore_switch(struct terminal *term, uint8_t c)
|
2019-12-20 21:13:06 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x1c ... 0x1f: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
state_osc_string_switch(struct terminal *term, uint8_t c)
|
2019-12-20 21:48:04 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
default: action_osc_put(term, c); return STATE_OSC_STRING;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x07: action_osc_end(term, c); 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:45:21 +01:00
|
|
|
case 0x1a: action_osc_end(term, c); action_execute(term, c); return STATE_GROUND;
|
2019-12-20 21:48:04 +01:00
|
|
|
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x1b: action_osc_end(term, c); action_clear(term); return STATE_ESCAPE;
|
2019-12-20 21:48:04 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum state
|
2019-12-20 23:45:21 +01:00
|
|
|
state_dcs_entry_switch(struct terminal *term, uint8_t c)
|
2019-12-20 21:48:04 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x20 ... 0x2f: action_collect(term, c); return STATE_DCS_INTERMEDIATE;
|
|
|
|
|
case 0x30 ... 0x39: action_param(term, c); return STATE_DCS_PARAM;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x3a: return STATE_DCS_IGNORE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x3b: action_param(term, c); return STATE_DCS_PARAM;
|
|
|
|
|
case 0x3c ... 0x3f: action_collect(term, c); return STATE_DCS_PARAM;
|
|
|
|
|
case 0x40 ... 0x7e: action_hook(term, c); 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:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
state_dcs_param_switch(struct terminal *term, uint8_t c)
|
2019-12-20 21:48:04 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x20 ... 0x2f: action_collect(term, c); return STATE_DCS_INTERMEDIATE;
|
|
|
|
|
case 0x30 ... 0x39: action_param(term, c); return STATE_DCS_PARAM;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x3a: return STATE_DCS_IGNORE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x3b: action_param(term, c); return STATE_DCS_PARAM;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x3c ... 0x3f: return STATE_DCS_IGNORE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x40 ... 0x7e: action_hook(term, c); 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:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
state_dcs_intermediate_switch(struct terminal *term, uint8_t c)
|
2019-12-20 21:48:04 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x20 ... 0x2f: action_collect(term, c); return STATE_DCS_INTERMEDIATE;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x30 ... 0x3f: return STATE_DCS_IGNORE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x40 ... 0x7e: action_hook(term, c); 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:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
state_dcs_ignore_switch(struct terminal *term, uint8_t c)
|
2019-12-20 21:48:04 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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:45:21 +01:00
|
|
|
state_dcs_passthrough_switch(struct terminal *term, uint8_t c)
|
2019-12-20 21:48:04 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x1c ... 0x7e: action_put(term, c); 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:45:21 +01:00
|
|
|
case 0x18: action_unhook(term, c); action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_unhook(term, c); action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1b: action_unhook(term, c); action_clear(term); return STATE_ESCAPE;
|
|
|
|
|
case 0x80 ... 0x8f: action_unhook(term, c); action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x90: action_unhook(term, c); action_clear(term); return STATE_DCS_ENTRY;
|
|
|
|
|
case 0x91 ... 0x97: action_unhook(term, c); action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x98: action_unhook(term, c); return STATE_SOS_PM_APC_STRING;
|
|
|
|
|
case 0x99: action_unhook(term, c); action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_unhook(term, c); action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9b: action_unhook(term, c); action_clear(term); return STATE_CSI_ENTRY;
|
|
|
|
|
case 0x9c: action_unhook(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9d: action_unhook(term, c); action_osc_start(term, c); return STATE_OSC_STRING;
|
|
|
|
|
case 0x9e ... 0x9f: action_unhook(term, c); 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:45:21 +01:00
|
|
|
state_sos_pm_apc_string_switch(struct terminal *term, uint8_t c)
|
2019-12-20 21:50:54 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
switch (c) {
|
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:45:21 +01:00
|
|
|
case 0x18: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x1a: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x1b: action_clear(term); return STATE_ESCAPE;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x80 ... 0x8f: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x90: action_clear(term); return STATE_DCS_ENTRY;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x91 ... 0x97: action_execute(term, c); return STATE_GROUND;
|
2019-12-20 23:38:16 +01:00
|
|
|
case 0x98: return STATE_SOS_PM_APC_STRING;
|
2019-12-20 23:45:21 +01:00
|
|
|
case 0x99: action_execute(term, c); return STATE_GROUND;
|
|
|
|
|
case 0x9a: action_execute(term, c); 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:45:21 +01:00
|
|
|
case 0x9d: action_osc_start(term, c); 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
|
2019-12-20 23:45:21 +01:00
|
|
|
state_utf8_collect_1_switch(struct terminal *term, uint8_t c)
|
2019-12-20 22:10:27 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
term->vt.utf8.data[term->vt.utf8.idx++] = c;
|
2019-12-20 22:10:27 +01:00
|
|
|
term->vt.utf8.left--;
|
|
|
|
|
|
|
|
|
|
assert(term->vt.utf8.left == 0);
|
2019-12-20 23:45:21 +01:00
|
|
|
action_utf8_print(term, c);
|
2019-12-20 22:10:27 +01:00
|
|
|
return STATE_GROUND;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum state
|
2019-12-20 23:45:21 +01:00
|
|
|
state_utf8_collect_2_switch(struct terminal *term, uint8_t c)
|
2019-12-20 22:10:27 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
term->vt.utf8.data[term->vt.utf8.idx++] = c;
|
2019-12-20 22:10:27 +01:00
|
|
|
term->vt.utf8.left--;
|
|
|
|
|
|
|
|
|
|
assert(term->vt.utf8.left == 1);
|
|
|
|
|
return STATE_UTF8_COLLECT_1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static enum state
|
2019-12-20 23:45:21 +01:00
|
|
|
state_utf8_collect_3_switch(struct terminal *term, uint8_t c)
|
2019-12-20 22:10:27 +01:00
|
|
|
{
|
2019-12-20 23:45:21 +01:00
|
|
|
term->vt.utf8.data[term->vt.utf8.idx++] = c;
|
2019-12-20 22:10:27 +01:00
|
|
|
term->vt.utf8.left--;
|
|
|
|
|
|
|
|
|
|
assert(term->vt.utf8.left == 2);
|
|
|
|
|
return STATE_UTF8_COLLECT_2;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-20 23:45:21 +01:00
|
|
|
static inline enum state
|
|
|
|
|
vt_state_machine_progress(struct terminal *term, enum state current_state, uint8_t c)
|
|
|
|
|
{
|
|
|
|
|
switch (current_state) {
|
|
|
|
|
case STATE_GROUND: return state_ground_switch(term, c);
|
|
|
|
|
case STATE_ESCAPE: return state_escape_switch(term, c);
|
|
|
|
|
case STATE_ESCAPE_INTERMEDIATE: return state_escape_intermediate_switch(term, c);
|
|
|
|
|
case STATE_CSI_ENTRY: return state_csi_entry_switch(term, c);
|
|
|
|
|
case STATE_CSI_PARAM: return state_csi_param_switch(term, c);
|
|
|
|
|
case STATE_CSI_INTERMEDIATE: return state_csi_intermediate_switch(term, c);
|
|
|
|
|
case STATE_CSI_IGNORE: return state_csi_ignore_switch(term, c);
|
|
|
|
|
case STATE_OSC_STRING: return state_osc_string_switch(term, c);
|
|
|
|
|
case STATE_DCS_ENTRY: return state_dcs_entry_switch(term, c);
|
|
|
|
|
case STATE_DCS_PARAM: return state_dcs_param_switch(term, c);
|
|
|
|
|
case STATE_DCS_INTERMEDIATE: return state_dcs_intermediate_switch(term, c);
|
|
|
|
|
case STATE_DCS_IGNORE: return state_dcs_ignore_switch(term, c);
|
|
|
|
|
case STATE_DCS_PASSTHROUGH: return state_dcs_passthrough_switch(term, c);
|
|
|
|
|
case STATE_SOS_PM_APC_STRING: return state_sos_pm_apc_string_switch(term, c);
|
|
|
|
|
|
|
|
|
|
case STATE_UTF8_COLLECT_1: return state_utf8_collect_1_switch(term, c);
|
|
|
|
|
case STATE_UTF8_COLLECT_2: return state_utf8_collect_2_switch(term, c);
|
|
|
|
|
case STATE_UTF8_COLLECT_3: return state_utf8_collect_3_switch(term, c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(false);
|
|
|
|
|
return STATE_GROUND;
|
|
|
|
|
}
|
|
|
|
|
|
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:45:21 +01:00
|
|
|
for (size_t i = 0; i < len; i++, p++)
|
|
|
|
|
current_state = vt_state_machine_progress(term, current_state, *p);
|
2019-12-20 22:12:35 +01:00
|
|
|
|
|
|
|
|
term->vt.state = current_state;
|
2019-06-15 22:22:44 +02:00
|
|
|
}
|