Commit b3d8fe0e authored by Christian Persch's avatar Christian Persch

parser: Implement DCS parsing

parent 1e29c00a
/*
* Copyright © 2015 David Herrmann <dh.herrmann@gmail.com>
* Copyright © 2018 Christian Persch
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -41,12 +42,16 @@ _VTE_CMD(DC3) /* device-control-3 or XOFF */
_VTE_CMD(DCH) /* delete-character */
_VTE_CMD(DECALN) /* screen-alignment-pattern */
_VTE_CMD(DECANM) /* ansi-mode */
_VTE_CMD(DECAUPSS) /* assign-user-preferred-supplemental-sets */
_VTE_CMD(DECBI) /* back-index */
_VTE_CMD(DECCARA) /* change-attributes-in-rectangular-area */
_VTE_CMD(DECCKD) /* copy-key-default */
_VTE_CMD(DECCRA) /* copy-rectangular-area */
_VTE_CMD(DECDC) /* delete-column */
_VTE_CMD(DECDHL_BH) /* double-width-double-height-line: bottom half */
_VTE_CMD(DECDHL_TH) /* double-width-double-height-line: top half */
_VTE_CMD(DECDLD) /* dynamically-redefinable-character-sets-extension */
_VTE_CMD(DECDMAC) /* define-macro */
_VTE_CMD(DECDWL) /* double-width-single-height-line */
_VTE_CMD(DECEFR) /* enable-filter-rectangle */
_VTE_CMD(DECELF) /* enable-local-functions */
......@@ -60,14 +65,20 @@ _VTE_CMD(DECINVM) /* invoke-macro */
_VTE_CMD(DECKBD) /* keyboard-language-selection */
_VTE_CMD(DECKPAM) /* keypad-application-mode */
_VTE_CMD(DECKPNM) /* keypad-numeric-mode */
_VTE_CMD(DECLANS) /* load-answerback-message */
_VTE_CMD(DECLBAN) /* load-banner-message */
_VTE_CMD(DECLBD) /* locator-button-define */
_VTE_CMD(DECLFKC) /* local-function-key-control */
_VTE_CMD(DECLL) /* load-leds */
_VTE_CMD(DECLTOD) /* load-time-of-day */
_VTE_CMD(DECPCTERM) /* pcterm-mode */
_VTE_CMD(DECPAK) /* program-alphanumeric-key */
_VTE_CMD(DECPFK) /* program-function-key */
_VTE_CMD(DECPKA) /* program-key-action */
_VTE_CMD(DECPKFMR) /* program-key-free-memory-report */
_VTE_CMD(DECRARA) /* reverse-attributes-in-rectangular-area */
_VTE_CMD(DECRC) /* restore-cursor */
_VTE_CMD(DECREGIS) /* ReGIS-graphics */
_VTE_CMD(DECREQTPARM) /* request-terminal-parameters */
_VTE_CMD(DECRPKT) /* report-key-type */
_VTE_CMD(DECRQCRA) /* request-checksum-of-rectangular-area */
......@@ -78,8 +89,11 @@ _VTE_CMD(DECRQM_ANSI) /* request-mode-ansi */
_VTE_CMD(DECRQM_DEC) /* request-mode-dec */
_VTE_CMD(DECRQPKFM) /* request-program-key-free-memory */
_VTE_CMD(DECRQPSR) /* request-presentation-state-report */
_VTE_CMD(DECRQSS) /* request-selection-or-setting */
_VTE_CMD(DECRQTSR) /* request-terminal-state-report */
_VTE_CMD(DECRQUPSS) /* request-user-preferred-supplemental-set */
_VTE_CMD(DECRSPS) /* restore-presentation-state */
_VTE_CMD(DECRSTS) /* restore-terminal-state */
_VTE_CMD(DECSACE) /* select-attribute-change-extent */
_VTE_CMD(DECSASD) /* select-active-status-display */
_VTE_CMD(DECSC) /* save-cursor */
......@@ -95,6 +109,7 @@ _VTE_CMD(DECSED) /* selective-erase-in-display */
_VTE_CMD(DECSEL) /* selective-erase-in-line */
_VTE_CMD(DECSERA) /* selective-erase-rectangular-area */
_VTE_CMD(DECSFC) /* select-flow-control */
_VTE_CMD(DECSIXEL) /* SIXEL-graphics */
_VTE_CMD(DECSKCV) /* set-key-click-volume */
_VTE_CMD(DECSLCK) /* set-lock-key-style */
_VTE_CMD(DECSLE) /* select-locator-events */
......@@ -113,6 +128,7 @@ _VTE_CMD(DECSSDT) /* select-status-display-line-type */
_VTE_CMD(DECSSL) /* select-setup-language */
_VTE_CMD(DECST8C) /* set-tab-at-every-8-columns */
_VTE_CMD(DECSTBM) /* set-top-and-bottom-margins */
_VTE_CMD(DECSTUI) /* set-terminal-unit-id */
_VTE_CMD(DECSTR) /* soft-terminal-reset */
_VTE_CMD(DECSTRL) /* set-transmit-rate-limit */
_VTE_CMD(DECSWBV) /* set-warning-bell-volume */
......@@ -120,6 +136,7 @@ _VTE_CMD(DECSWL) /* single-width-single-height-line */
_VTE_CMD(DECTID) /* select-terminal-id */
_VTE_CMD(DECTME) /* terminal-mode-emulation */
_VTE_CMD(DECTST) /* invoke-confidence-test */
_VTE_CMD(DECUDK) /* user-defined-keys */
_VTE_CMD(DL) /* delete-line */
_VTE_CMD(DOCS) /* designate-other-coding-system */
_VTE_CMD(DSR_DEC) /* device-status-report-dec */
......
......@@ -915,6 +915,95 @@ test_seq_csi(void)
test_seq_csi(params2);
}
static void
test_seq_dcs(uint32_t f,
uint32_t p,
vte_seq_arg_t params[16],
uint32_t i[4],
unsigned int ni,
std::u32string const& str)
{
vte_seq_builder b{VTE_SEQ_DCS, f};
b.set_intermediates(i, ni);
b.set_param_byte(p);
b.set_params(params);
b.set_string(str);
int expected_rv = (f & 0xF0) == 0x30 ? VTE_SEQ_NONE : VTE_SEQ_DCS;
for (unsigned int n = 0; n <= 16; n++) {
b.set_n_params(n);
vte_parser_reset(parser);
struct vte_seq* seq;
#if 0
/* First with C0 DCS */
auto rv = feed_parser(b, &seq, false);
g_assert_cmpint(rv, ==, expected_rv);
if (rv != VTE_SEQ_NONE)
b.assert_equal_full(seq);
#endif
/* Now with C1 DCS */
auto rv = feed_parser(b, &seq, true);
g_assert_cmpint(rv, ==, expected_rv);
if (rv != VTE_SEQ_NONE)
b.assert_equal_full(seq);
}
}
static void
test_seq_dcs(uint32_t p,
vte_seq_arg_t params[16],
std::u32string const& str)
{
uint32_t i[4];
for (uint32_t f = 0x30; f < 0x7f; f++) {
for (i[0] = 0x20; i[0] < 0x30; i[0]++) {
test_seq_dcs(f, p, params, i, 1, str);
for (i[1] = 0x20; i[1] < 0x30; i[1]++) {
test_seq_dcs(f, p, params, i, 2, str);
}
}
}
}
static void
test_seq_dcs(vte_seq_arg_t params[16],
std::u32string const& str)
{
test_seq_dcs(0, params, str);
for (uint32_t p = 0x3c; p <= 0x3f; p++)
test_seq_dcs(p, params, str);
}
static void
test_seq_dcs(std::u32string const& str)
{
/* Tests DCS sequences, that is sequences of the form
* DCS P...P I...I F D...D ST
* with parameter bytes P from 3/0..3/15, intermediate bytes I from 2/0..2/15 and
* final byte F from 4/0..7/14.
* There could be any number of intermediate bytes, but we only test up to 2.
* There could be any number of extra params bytes, but we only test up to 1.
* DCS can be either the C1 control itself, or ESC [; ST can be either the C1
* control itself, or ESC \\
*/
vte_seq_arg_t params1[16]{ -1, 0, 1, 9, 10, 99, 100, 999,
1000, 9999, 10000, 65534, 65535, 65536, -1, -1 };
test_seq_dcs(params1, str);
vte_seq_arg_t params2[16]{ 1, -1, -1, -1, 1, -1, 1, 1,
1, -1, -1, -1, -1, 1, 1, 1 };
test_seq_dcs(params2, str);
}
static void
test_seq_dcs(void)
{
test_seq_dcs(U""s);
test_seq_dcs(U"123;TESTING"s);
}
static void
test_seq_parse(char const* str,
struct vte_seq** seq)
......@@ -1197,7 +1286,7 @@ test_seq_osc(void)
/* String of any supported length */
for (unsigned int len = 0; len < VTE_SEQ_STRING_MAX_CAPACITY; ++len)
test_seq_osc(std::u32string(len, 0x100000), seq);
test_seq_osc(std::u32string(len, 0x10000+len), seq);
/* Length exceeded */
// test_seq_osc(std::u32string(VTE_SEQ_STRING_MAX_CAPACITY + 1, 0x100000), seq, VTE_SEQ_NONE);
......@@ -1359,6 +1448,7 @@ main(int argc,
g_test_add_func("/vte/parser/sequences/escape/F[pes]", test_seq_esc_Fpes);
g_test_add_func("/vte/parser/sequences/csi", test_seq_csi);
g_test_add_func("/vte/parser/sequences/csi/parameters", test_seq_csi_param);
g_test_add_func("/vte/parser/sequences/dcs", test_seq_dcs);
g_test_add_func("/vte/parser/sequences/osc", test_seq_osc);
auto rv = g_test_run();
......
......@@ -830,6 +830,78 @@ static unsigned int vte_parse_host_csi(const struct vte_seq *seq)
return VTE_CMD_NONE;
}
static unsigned int vte_parse_host_dcs(const struct vte_seq *seq)
{
unsigned int const flags = seq->intermediates;
switch (seq->terminator) {
case 'p':
if (flags == 0) /* DECREGIS */
return VTE_CMD_DECREGIS;
else if (flags == VTE_SEQ_FLAG_CASH) /* DECRSTS */
return VTE_CMD_DECRSTS;
break;
case 'q':
if (flags == 0) /* DECSIXEL */
return VTE_CMD_DECSIXEL;
else if (flags == VTE_SEQ_FLAG_CASH) /* DECRQSS */
return VTE_CMD_DECRQSS;
break;
case 'r':
if (flags == 0) /* DECLBAN */
return VTE_CMD_DECLBAN;
else if (flags == VTE_SEQ_FLAG_CASH) /* DECRQSS */
return VTE_CMD_DECRQSS; // FIXMEchpe really??
break;
case 's':
if (flags == VTE_SEQ_FLAG_CASH) /* DECRQTSR */
return VTE_CMD_DECRQTSR;
break;
case 't':
if (flags == VTE_SEQ_FLAG_CASH) /* DECRSPS */
return VTE_CMD_DECRSPS;
break;
case 'u':
if (flags == VTE_SEQ_FLAG_BANG) /* DECAUPSS */
return VTE_CMD_DECAUPSS;
break;
case 'v':
if (flags == 0) /* DECLANS */
return VTE_CMD_DECLANS;
break;
case 'w':
if (flags == 0) /* DECLBD */
return VTE_CMD_DECLBD;
break;
case 'x':
if (flags == VTE_SEQ_FLAG_DQUOTE) /* DECPFK */
return VTE_CMD_DECPFK;
break;
case 'y':
if (flags == VTE_SEQ_FLAG_DQUOTE) /* DECPAK */
return VTE_CMD_DECPAK;
break;
case 'z':
if (flags == VTE_SEQ_FLAG_BANG) /* DECDMAC */
return VTE_CMD_DECDMAC;
else if (flags == VTE_SEQ_FLAG_DQUOTE) /* DECCKD */
return VTE_CMD_DECCKD;
break;
case '{':
if (flags == 0) /* DECDLD */
return VTE_CMD_DECDLD;
else if (flags == VTE_SEQ_FLAG_BANG) /* DECSTUI */
return VTE_CMD_DECSTUI;
break;
case '|':
if (flags == 0) /* DECUDK */
return VTE_CMD_DECUDK;
break;
}
return VTE_CMD_NONE;
}
/*
* State Machine
* This parser controls the parser-state and returns any detected sequence to
......@@ -870,12 +942,11 @@ enum parser_action {
ACTION_ESC_DISPATCH, /* dispatch escape sequence */
ACTION_CSI_DISPATCH, /* dispatch CSI sequence */
ACTION_DCS_START, /* start of DCS data */
ACTION_DCS_COLLECT, /* collect DCS data */
ACTION_DCS_CONSUME, /* consume DCS terminator */
ACTION_DCS_COLLECT, /* collect DCS data */
ACTION_DCS_DISPATCH, /* dispatch DCS sequence */
ACTION_OSC_START, /* clear and clear string data */
ACTION_OSC_START, /* clear and clear string data */
ACTION_OSC_COLLECT, /* collect OSC data */
ACTION_OSC_CONSUME, /* consume OSC terminator */
ACTION_OSC_DISPATCH, /* dispatch OSC sequence */
ACTION_N,
};
......@@ -930,9 +1001,6 @@ static inline void parser_clear(struct vte_parser *parser)
// FIXMEchpe: now that DEFAULT is all-zero, use memset here
for (i = 0; i < VTE_PARSER_ARG_MAX; ++i)
parser->seq.args[i] = VTE_SEQ_ARG_INIT_DEFAULT;
// FIXMEchpe not really needed here, just in parser_st_start
vte_seq_string_reset(&parser->seq.arg_str);
}
static int parser_ignore(struct vte_parser *parser, uint32_t raw)
......@@ -1014,18 +1082,52 @@ static void parser_param(struct vte_parser *parser, uint32_t raw)
static inline void parser_osc_start(struct vte_parser *parser)
{
parser_clear(parser);
vte_seq_string_reset(&parser->seq.arg_str);
}
static void parser_collect_string(struct vte_parser *parser, uint32_t raw)
static void parser_osc_collect(struct vte_parser *parser, uint32_t raw)
{
/*
* Only characters from 0x20..0x7e and 0xa0..0x10ffff are allowed here.
* Only characters from 0x20..0x7e and >= 0xa0 are allowed here.
* Our state-machine already verifies those restrictions.
*/
vte_seq_string_push(&parser->seq.arg_str, raw);
}
static inline void parser_dcs_start(struct vte_parser *parser)
{
parser_clear(parser);
vte_seq_string_reset(&parser->seq.arg_str);
}
static void parser_dcs_consume(struct vte_parser *parser, uint32_t raw)
{
/* parser->seq is cleared during DCS-START state, thus there's no need
* to clear invalid fields here. */
if (parser->seq.n_args < VTE_PARSER_ARG_MAX) {
if (parser->seq.n_args > 0 ||
vte_seq_arg_started(parser->seq.args[parser->seq.n_args])) {
vte_seq_arg_finish(&parser->seq.args[parser->seq.n_args], false);
++parser->seq.n_args;
++parser->seq.n_final_args;
}
}
parser->seq.type = VTE_SEQ_DCS;
parser->seq.terminator = raw;
parser->seq.charset = VTE_CHARSET_NONE;
parser->seq.command = vte_parse_host_dcs(&parser->seq);
}
static void parser_dcs_collect(struct vte_parser *parser, uint32_t raw)
{
vte_seq_string_push(&parser->seq.arg_str, raw);
}
static int parser_esc(struct vte_parser *parser, uint32_t raw)
{
parser->seq.type = VTE_SEQ_ESCAPE;
......@@ -1076,6 +1178,13 @@ static int parser_osc(struct vte_parser *parser, uint32_t raw)
return parser->seq.type;
}
static int parser_dcs(struct vte_parser *parser, uint32_t raw)
{
/* parser->seq was already filled in parser_dcs_consume() */
return parser->seq.type;
}
/* perform state transition and dispatch related actions */
static int parser_transition(struct vte_parser *parser,
uint32_t raw,
......@@ -1108,25 +1217,21 @@ static int parser_transition(struct vte_parser *parser,
case ACTION_CSI_DISPATCH:
return parser_csi(parser, raw);
case ACTION_DCS_START:
/* not implemented */
return VTE_SEQ_NONE;
case ACTION_DCS_COLLECT:
/* not implemented */
parser_dcs_start(parser);
return VTE_SEQ_NONE;
case ACTION_DCS_CONSUME:
/* not implemented */
parser_dcs_consume(parser, raw);
return VTE_SEQ_NONE;
case ACTION_DCS_DISPATCH:
/* not implemented */
case ACTION_DCS_COLLECT:
parser_dcs_collect(parser, raw);
return VTE_SEQ_NONE;
case ACTION_DCS_DISPATCH:
return parser_dcs(parser, raw);
case ACTION_OSC_START:
parser_osc_start(parser);
return VTE_SEQ_NONE;
case ACTION_OSC_COLLECT:
parser_collect_string(parser, raw);
return VTE_SEQ_NONE;
case ACTION_OSC_CONSUME:
/* not implemented */
parser_osc_collect(parser, raw);
return VTE_SEQ_NONE;
case ACTION_OSC_DISPATCH:
return parser_osc(parser, raw);
......@@ -1175,13 +1280,13 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
ACTION_ESC_DISPATCH);
case 0x50: /* 'P' */
return parser_transition(parser, raw, STATE_DCS_ENTRY,
ACTION_CLEAR);
ACTION_DCS_START);
case 0x5b: /* '[' */
return parser_transition(parser, raw, STATE_CSI_ENTRY,
ACTION_CLEAR);
case 0x5d: /* ']' */
return parser_transition(parser, raw, STATE_OSC_STRING,
ACTION_CLEAR);
ACTION_OSC_START);
case 0x58: /* 'X' */
case 0x5e: /* '^' */
case 0x5f: /* '_' */
......@@ -1503,7 +1608,7 @@ int vte_parser_feed(struct vte_parser *parser,
break;
case 0x90: /* DCS */
ret = parser_transition(parser, raw,
STATE_DCS_ENTRY, ACTION_CLEAR);
STATE_DCS_ENTRY, ACTION_DCS_START);
break;
case 0x9d: /* OSC */
ret = parser_transition(parser, raw,
......
......@@ -2337,6 +2337,16 @@ VteTerminalPrivate::DECANM(vte::parser::Sequence const& seq)
*/
}
void
VteTerminalPrivate::DECAUPSS(vte::parser::Sequence const& seq)
{
/*
* DECAUPSS - assign user preferred supplemental sets
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECBI(vte::parser::Sequence const& seq)
{
......@@ -2364,6 +2374,16 @@ VteTerminalPrivate::DECCARA(vte::parser::Sequence const& seq)
*/
}
void
VteTerminalPrivate::DECCKD(vte::parser::Sequence const& seq)
{
/*
* DECCKD - copy key default
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECCRA(vte::parser::Sequence const& seq)
{
......@@ -2404,6 +2424,26 @@ VteTerminalPrivate::DECDHL_TH(vte::parser::Sequence const& seq)
*/
}
void
VteTerminalPrivate::DECDLD(vte::parser::Sequence const& seq)
{
/*
* DECDLD - dynamically redefinable character sets extension
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECDMAC(vte::parser::Sequence const& seq)
{
/*
* DECDMAC - define-macro
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECDWL(vte::parser::Sequence const& seq)
{
......@@ -2572,6 +2612,38 @@ VteTerminalPrivate::DECKPNM(vte::parser::Sequence const& seq)
set_mode_private(vte::terminal::modes::Private::eDEC_APPLICATION_KEYPAD, false);
}
void
VteTerminalPrivate::DECLANS(vte::parser::Sequence const& seq)
{
/*
* DECLANS - load answerback message
*
* Will not implement this because of security policy.
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECLBAN(vte::parser::Sequence const& seq)
{
/*
* DECLBAN - load banner message
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECLBD(vte::parser::Sequence const& seq)
{
/*
* DECLBD - locator button define
*
* References: VT330
*/
}
void
VteTerminalPrivate::DECLFKC(vte::parser::Sequence const& seq)
{
......@@ -2602,6 +2674,16 @@ VteTerminalPrivate::DECLTOD(vte::parser::Sequence const& seq)
*/
}
void
VteTerminalPrivate::DECPAK(vte::parser::Sequence const& seq)
{
/*
* DECPAK - program alphanumeric key
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECPCTERM(vte::parser::Sequence const& seq)
{
......@@ -2614,6 +2696,16 @@ VteTerminalPrivate::DECPCTERM(vte::parser::Sequence const& seq)
*/
}
void
VteTerminalPrivate::DECPFK(vte::parser::Sequence const& seq)
{
/*
* DECPFK - program function key
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECPKA(vte::parser::Sequence const& seq)
{
......@@ -2667,6 +2759,16 @@ VteTerminalPrivate::DECRC(vte::parser::Sequence const& seq)
restore_cursor();
}
void
VteTerminalPrivate::DECREGIS(vte::parser::Sequence const& seq)
{
/*
* DECREGIS - ReGIS graphics
*
* References: VT330
*/
}
void
VteTerminalPrivate::DECREQTPARM(vte::parser::Sequence const& seq)
{
......@@ -2822,6 +2924,16 @@ VteTerminalPrivate::DECRQPSR(vte::parser::Sequence const& seq)
*/
}
void
VteTerminalPrivate::DECRQSS(vte::parser::Sequence const& seq)
{
/*
* DECRQSS - request selection or setting
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECRQTSR(vte::parser::Sequence const& seq)
{
......@@ -2842,6 +2954,26 @@ VteTerminalPrivate::DECRQUPSS(vte::parser::Sequence const& seq)
*/
}
void
VteTerminalPrivate::DECRSPS(vte::parser::Sequence const& seq)
{
/*
* DECRSPS - restore presentation state
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECRSTS(vte::parser::Sequence const& seq)
{
/*
* DECRSTS - restore terminal state
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECSACE(vte::parser::Sequence const& seq)
{
......@@ -3125,6 +3257,17 @@ VteTerminalPrivate::DECSFC(vte::parser::Sequence const& seq)
*/
}
void
VteTerminalPrivate::DECSIXEL(vte::parser::Sequence const& seq)
{
/*
* DECSIXEL - SIXEL graphics
*
* References: VT330
*/
}
void
VteTerminalPrivate::DECSKCV(vte::parser::Sequence const& seq)
{
......@@ -3425,6 +3568,16 @@ VteTerminalPrivate::DECSTRL(vte::parser::Sequence const& seq)
*/
}
void
VteTerminalPrivate::DECSTUI(vte::parser::Sequence const& seq)
{
/*
* DECSTUI - set terminal unit ID
*
* References: VT525
*/
}
void
VteTerminalPrivate::DECSWBV(vte::parser::Sequence const& seq)
{
......@@ -3475,6 +3628,16 @@ VteTerminalPrivate::DECTST(vte::parser::Sequence const& seq)
*/
}
void
VteTerminalPrivate::DECUDK(vte::parser::Sequence const& seq)
{
/*
* DECUDK - user define keys
*
* References: VT525
*/
}
void
VteTerminalPrivate::DL(vte::parser::Sequence const& seq)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment