[vte] parser: Parse subparameters in CSI sequences
- From: Christian Persch <chpe src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vte] parser: Parse subparameters in CSI sequences
- Date: Tue, 27 Mar 2018 17:41:47 +0000 (UTC)
commit db833edf98f881085b14ae5240ea65bcff383b91
Author: Christian Persch <chpe src gnome org>
Date: Tue Mar 27 19:40:12 2018 +0200
parser: Parse subparameters in CSI sequences
This is used in SGR.
src/parser-arg.hh | 112 ++++++++++++++++++++++++++++++++++++++++++++++-----
src/parser-test.cc | 107 ++++++++++++++++++++++++++++++++++++++------------
src/parser.cc | 42 +++++++++++--------
src/parser.hh | 1 +
4 files changed, 208 insertions(+), 54 deletions(-)
---
diff --git a/src/parser-arg.hh b/src/parser-arg.hh
index 75ab3d8..87d9343 100644
--- a/src/parser-arg.hh
+++ b/src/parser-arg.hh
@@ -20,14 +20,65 @@
#include <assert.h>
+/*
+ * vte_seq_arg_t:
+ *
+ * A type to hold a CSI, OSC or DCS parameter.
+ *
+ * Parameters can be final or nonfinal.
+ *
+ * Final parameters are those that occur at the end of the
+ * parameter list, or the end of a subparameter list.
+ *
+ * Nonfinal parameters are those that have subparameters
+ * after them.
+ *
+ * Parameters have default value or have a nondefault value.
+ */
typedef int vte_seq_arg_t;
+#define VTE_SEQ_ARG_FLAG_VALUE (1 << 16)
+#define VTE_SEQ_ARG_FLAG_NONFINAL (1 << 17)
+#define VTE_SEQ_ARG_VALUE_MASK (0xffff)
+
+/*
+ * VTE_SEQ_ARG_INIT_DEFAULT:
+ *
+ * Returns: a parameter with default value
+ */
#define VTE_SEQ_ARG_INIT_DEFAULT (0)
-#define VTE_SEQ_ARG_FLAG_VALUE (1 << 16)
-#define VTE_SEQ_ARG_VALUE_MASK (0xffff)
-#define VTE_SEQ_ARG_INIT(value) (value | VTE_SEQ_ARG_FLAG_VALUE)
+/*
+ * VTE_SEQ_ARG_INIT:
+ * @value:
+ *
+ * Returns: a parameter with value @value
+ */
+#define VTE_SEQ_ARG_INIT(value) ((value & VTE_SEQ_ARG_VALUE_MASK) | VTE_SEQ_ARG_FLAG_VALUE)
+
+/*
+ * vte_seq_arg_init:
+ * @value:
+ *
+ * Returns: a #vte_seq_arg_t for @value, or with default value if @value is -1
+ */
+static constexpr inline vte_seq_arg_t vte_seq_arg_init(int value)
+{
+ if (value == -1)
+ return VTE_SEQ_ARG_INIT_DEFAULT;
+ else
+ return VTE_SEQ_ARG_INIT(value);
+}
+/*
+ * vte_seq_arg_push:
+ * @arg:
+ * @c: a value between 3/0 and 3/9 ['0' .. '9']
+ *
+ * Multiplies @arg by 10 and adds the numeric value of @c.
+ *
+ * After this, @arg has a value.
+ */
static inline void vte_seq_arg_push(vte_seq_arg_t* arg,
uint32_t c)
{
@@ -46,26 +97,65 @@ static inline void vte_seq_arg_push(vte_seq_arg_t* arg,
*arg = value | VTE_SEQ_ARG_FLAG_VALUE;
}
-static inline void vte_seq_arg_finish(vte_seq_arg_t* arg)
+/*
+ * vte_seq_arg_finish:
+ * @arg:
+ * @finalise:
+ *
+ * Finished @arg; after this no more vte_seq_arg_push() calls
+ * are allowed.
+ *
+ * If @nonfinal is %true, marks @arg as a nonfinal parameter, is,
+ * there are more subparameters after it.
+ */
+static inline void vte_seq_arg_finish(vte_seq_arg_t* arg,
+ bool nonfinal = false)
{
+ if (nonfinal)
+ *arg |= VTE_SEQ_ARG_FLAG_NONFINAL;
}
-static inline bool vte_seq_arg_started(vte_seq_arg_t arg)
+/*
+ * vte_seq_arg_started:
+ * @arg:
+ *
+ * Returns: whether @arg has nondefault value
+ */
+static constexpr inline bool vte_seq_arg_started(vte_seq_arg_t arg)
{
return arg & VTE_SEQ_ARG_FLAG_VALUE;
}
-static inline bool vte_seq_arg_finished(vte_seq_arg_t arg)
+/*
+ * vte_seq_arg_default:
+ * @arg:
+ *
+ * Returns: whether @arg has default value
+ */
+static constexpr inline bool vte_seq_arg_default(vte_seq_arg_t arg)
{
- return true;
+ return !(arg & VTE_SEQ_ARG_FLAG_VALUE);
}
-static inline bool vte_seq_arg_default(vte_seq_arg_t arg)
+/*
+ * vte_seq_arg_nonfinal:
+ * @arg:
+ *
+ * Returns: whether @arg is a nonfinal parameter, i.e. there
+ * are more subparameters after it
+ */
+static constexpr inline int vte_seq_arg_nonfinal(vte_seq_arg_t arg)
{
- return !(arg & VTE_SEQ_ARG_FLAG_VALUE);
+ return (arg & VTE_SEQ_ARG_FLAG_NONFINAL);
}
-static inline int vte_seq_arg_value(vte_seq_arg_t arg)
+/*
+ * vte_seq_arg_value:
+ * @arg:
+ *
+ * Returns: the value of @arg, or -1 if @arg has default value
+ */
+static constexpr inline int vte_seq_arg_value(vte_seq_arg_t arg)
{
- return arg & VTE_SEQ_ARG_FLAG_VALUE ? arg & VTE_SEQ_ARG_VALUE_MASK : -1;
+ return (arg & VTE_SEQ_ARG_FLAG_VALUE) ? (arg & VTE_SEQ_ARG_VALUE_MASK) : -1;
}
diff --git a/src/parser-test.cc b/src/parser-test.cc
index 8f84804..eebfa42 100644
--- a/src/parser-test.cc
+++ b/src/parser-test.cc
@@ -23,6 +23,7 @@
#include <cstddef>
#include <cstdint>
#include <string>
+#include <vector>
#include <glib.h>
@@ -170,7 +171,8 @@ public:
void set_params(vte_seq_arg_t params[16])
{
- memcpy(&m_seq.args, params, 16*sizeof(params[0]));
+ for (unsigned int i = 0; i < 16; i++)
+ m_seq.args[i] = vte_seq_arg_init(params[i]);
}
void set_n_params(unsigned int n)
@@ -273,13 +275,9 @@ vte_seq_builder::assert_equal_full(struct vte_seq* seq)
}
static int
-feed_parser(vte_seq_builder& b,
- struct vte_seq** seq,
- bool c1 = false)
+feed_parser(std::u32string const& s,
+ struct vte_seq** seq)
{
- std::u32string s;
- b.to_string(s, c1);
-
int rv = VTE_SEQ_NONE;
for (auto it : s) {
rv = vte_parser_feed(parser, seq, (uint32_t)(char32_t)it);
@@ -289,6 +287,17 @@ feed_parser(vte_seq_builder& b,
return rv;
}
+static int
+feed_parser(vte_seq_builder& b,
+ struct vte_seq** seq,
+ bool c1 = false)
+{
+ std::u32string s;
+ b.to_string(s, c1);
+
+ return feed_parser(s, seq);
+}
+
static void
test_seq_arg(void)
{
@@ -302,7 +311,6 @@ test_seq_arg(void)
vte_seq_arg_push(&arg, '3');
vte_seq_arg_finish(&arg);
- g_assert_true(vte_seq_arg_finished(arg));
g_assert_cmpint(vte_seq_arg_value(arg), ==, 123);
g_assert_false(vte_seq_arg_default(arg));
@@ -315,7 +323,6 @@ test_seq_arg(void)
vte_seq_arg_push(&arg, '6');
vte_seq_arg_finish(&arg);
- g_assert_true(vte_seq_arg_finished(arg));
g_assert_cmpint(vte_seq_arg_value(arg), ==, 65535);
}
@@ -776,27 +783,76 @@ test_seq_csi(void)
* There could be any number of extra params bytes, but we only test up to 1.
* CSI can be either the C1 control itself, or ESC [
*/
- vte_seq_arg_t params1[16]{ VTE_SEQ_ARG_INIT(-1), VTE_SEQ_ARG_INIT(0),
- VTE_SEQ_ARG_INIT(1), VTE_SEQ_ARG_INIT(9),
- VTE_SEQ_ARG_INIT(10), VTE_SEQ_ARG_INIT(99),
- VTE_SEQ_ARG_INIT(100), VTE_SEQ_ARG_INIT(999),
- VTE_SEQ_ARG_INIT(1000), VTE_SEQ_ARG_INIT(9999),
- VTE_SEQ_ARG_INIT(10000), VTE_SEQ_ARG_INIT(65534),
- VTE_SEQ_ARG_INIT(65535), VTE_SEQ_ARG_INIT(65536),
- VTE_SEQ_ARG_INIT(-1), VTE_SEQ_ARG_INIT(-1) };
+ vte_seq_arg_t params1[16]{ -1, 0, 1, 9, 10, 99, 100, 999,
+ 1000, 9999, 10000, 65534, 65535, 65536, -1, -1 };
test_seq_csi(params1);
- vte_seq_arg_t params2[16]{ VTE_SEQ_ARG_INIT(1), VTE_SEQ_ARG_INIT(-1),
- VTE_SEQ_ARG_INIT(-1), VTE_SEQ_ARG_INIT(-1),
- VTE_SEQ_ARG_INIT(1), VTE_SEQ_ARG_INIT(-1),
- VTE_SEQ_ARG_INIT(1), VTE_SEQ_ARG_INIT(1),
- VTE_SEQ_ARG_INIT(1), VTE_SEQ_ARG_INIT(-1),
- VTE_SEQ_ARG_INIT(-1), VTE_SEQ_ARG_INIT(-1),
- VTE_SEQ_ARG_INIT(-1), VTE_SEQ_ARG_INIT(1),
- VTE_SEQ_ARG_INIT(1), VTE_SEQ_ARG_INIT(1) };
+ vte_seq_arg_t params2[16]{ 1, -1, -1, -1, 1, -1, 1, 1,
+ 1, -1, -1, -1, -1, 1, 1, 1 };
test_seq_csi(params2);
}
+static void
+test_seq_csi_param(char const* str,
+ std::vector<int> args,
+ std::vector<bool> args_nonfinal)
+{
+ g_assert_cmpuint(args.size(), ==, args_nonfinal.size());
+
+ std::u32string s;
+ s.push_back(0x9B); /* CSI */
+ for (unsigned int i = 0; str[i]; i++)
+ s.push_back(str[i]);
+ s.push_back(0x6d); /* m = SGR */
+
+ struct vte_seq* seq;
+ auto rv = feed_parser(s, &seq);
+ g_assert_cmpint(rv, ==, VTE_SEQ_CSI);
+
+ if (seq->n_args < VTE_PARSER_ARG_MAX)
+ g_assert_cmpuint(seq->n_args, ==, args.size());
+
+ unsigned int n_final_args = 0;
+ for (unsigned int i = 0; i < seq->n_args; i++) {
+ g_assert_cmpint(vte_seq_arg_value(seq->args[i]), ==, args[i]);
+
+ auto is_nonfinal = args_nonfinal[i];
+ if (!is_nonfinal)
+ n_final_args++;
+
+ g_assert_cmpint(!!vte_seq_arg_nonfinal(seq->args[i]), ==, is_nonfinal);
+ }
+
+ g_assert_cmpuint(seq->n_final_args, ==, n_final_args);
+}
+
+static void
+test_seq_csi_param(void)
+{
+ /* Tests that CSI parameters and subparameters are parsed correctly. */
+
+ test_seq_csi_param("", { }, { });
+ test_seq_csi_param(";", { -1, -1 }, { false, false });
+ test_seq_csi_param(":", { -1, -1 }, { true, false });
+ test_seq_csi_param(";:", { -1, -1, -1 }, { false, true, false });
+ test_seq_csi_param("::;;", { -1, -1, -1, -1, -1 }, { true, true, false, false, false });
+
+ test_seq_csi_param("1;2:3:4:5:6;7:8;9:0",
+ { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 },
+ { false, true, true, true, true, false, true, false, true, false });
+
+ test_seq_csi_param("1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1",
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false });
+
+ test_seq_csi_param("1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1",
+ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ { true, true, true, true, true, true, true, true,
+ true, true, true, true, true, true, true, false });
+
+}
+
int
main(int argc,
char* argv[])
@@ -818,6 +874,7 @@ main(int argc,
g_test_add_func("/vte/parser/sequences/escape/nF", test_seq_esc_nF);
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);
auto rv = g_test_run();
diff --git a/src/parser.cc b/src/parser.cc
index 5cf74fe..0b2715d 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -619,9 +619,10 @@ static unsigned int vte_parse_host_csi(const struct vte_seq *seq)
* Split both up and forward the call to the closer
* match.
*/
- if (seq->n_args <= 1) /* XTERM RPM */
+ // FIXMEchpe!
+ if (seq->n_final_args <= 1) /* XTERM RPM */
return VTE_CMD_XTERM_RPM;
- else if (seq->n_args >= 2) /* DECPCTERM */
+ else if (seq->n_final_args >= 2) /* DECPCTERM */
return VTE_CMD_DECPCTERM;
}
break;
@@ -659,10 +660,11 @@ static unsigned int vte_parse_host_csi(const struct vte_seq *seq)
* 1. We're conservative here and give both a wider
* range to allow unused arguments (compat...).
*/
- if (seq->n_args < 5) {
+ // FIXMEchpe!
+ if (seq->n_final_args < 5) {
/* SD */
return VTE_CMD_SD;
- } else if (seq->n_args >= 5) {
+ } else if (seq->n_final_args >= 5) {
/* XTERM IHMT */
return VTE_CMD_XTERM_IHMT;
}
@@ -931,6 +933,8 @@ static inline void parser_clear(struct vte_parser *parser)
parser->seq.intermediates = 0;
parser->seq.charset = VTE_CHARSET_NONE;
parser->seq.n_args = 0;
+ parser->seq.n_final_args = 0;
+ /* FIXME: we only really need to clear 0..n_args+1 since all others have not been touched */
for (i = 0; i < VTE_PARSER_ARG_MAX; ++i)
parser->seq.args[i] = VTE_SEQ_ARG_INIT_DEFAULT;
@@ -990,7 +994,16 @@ static void parser_param(struct vte_parser *parser, uint32_t raw)
{
if (raw == ';') {
if (parser->seq.n_args < VTE_PARSER_ARG_MAX) {
- vte_seq_arg_finish(&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;
+ }
+
+ return;
+ }
+ if (raw == ':') {
+ if (parser->seq.n_args < VTE_PARSER_ARG_MAX) {
+ vte_seq_arg_finish(&parser->seq.args[parser->seq.n_args], true);
++parser->seq.n_args;
}
@@ -1025,8 +1038,9 @@ static int parser_csi(struct vte_parser *parser, uint32_t raw)
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]);
+ vte_seq_arg_finish(&parser->seq.args[parser->seq.n_args], false);
++parser->seq.n_args;
+ ++parser->seq.n_final_args;
}
}
@@ -1190,11 +1204,8 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
case 0x20 ... 0x2f: /* [' ' - '\'] */
return parser_transition(parser, raw, STATE_CSI_INT,
ACTION_COLLECT);
- case 0x3a: /* ':' */
- return parser_transition(parser, raw, STATE_CSI_IGNORE,
- ACTION_NONE);
case 0x30 ... 0x39: /* ['0' - '9'] */
- case 0x3b: /* ';' */
+ case 0x3a ... 0x3b: /* [':' - ';'] */
return parser_transition(parser, raw, STATE_CSI_PARAM,
ACTION_PARAM);
case 0x3c ... 0x3f: /* ['<' - '?'] */
@@ -1222,10 +1233,9 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
return parser_transition(parser, raw, STATE_CSI_INT,
ACTION_COLLECT);
case 0x30 ... 0x39: /* ['0' - '9'] */
- case 0x3b: /* ';' */
+ case 0x3a ... 0x3b: /* [':' - ';'] */
return parser_transition(parser, raw, STATE_NONE,
ACTION_PARAM);
- case 0x3a: /* ':' */
case 0x3c ... 0x3f: /* ['<' - '?'] */
return parser_transition(parser, raw, STATE_CSI_IGNORE,
ACTION_NONE);
@@ -1295,11 +1305,8 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
case 0x20 ... 0x2f: /* [' ' - '\'] */
return parser_transition(parser, raw, STATE_DCS_INT,
ACTION_COLLECT);
- case 0x3a: /* ':' */
- return parser_transition(parser, raw, STATE_DCS_IGNORE,
- ACTION_NONE);
case 0x30 ... 0x39: /* ['0' - '9'] */
- case 0x3b: /* ';' */
+ case 0x3a ... 0x3b: /* [':' - ';'] */
return parser_transition(parser, raw, STATE_DCS_PARAM,
ACTION_PARAM);
case 0x3c ... 0x3f: /* ['<' - '?'] */
@@ -1327,10 +1334,9 @@ static int parser_feed_to_state(struct vte_parser *parser, uint32_t raw)
return parser_transition(parser, raw, STATE_DCS_INT,
ACTION_COLLECT);
case 0x30 ... 0x39: /* ['0' - '9'] */
- case 0x3b: /* ';' */
+ case 0x3a ... 0x3b: /* [':' - ';'] */
return parser_transition(parser, raw, STATE_NONE,
ACTION_PARAM);
- case 0x3a: /* ':' */
case 0x3c ... 0x3f: /* ['<' - '?'] */
return parser_transition(parser, raw, STATE_DCS_IGNORE,
ACTION_NONE);
diff --git a/src/parser.hh b/src/parser.hh
index 68b440e..1a723af 100644
--- a/src/parser.hh
+++ b/src/parser.hh
@@ -140,6 +140,7 @@ struct vte_seq {
unsigned int intermediates;
unsigned int charset;
unsigned int n_args;
+ unsigned int n_final_args;
vte_seq_arg_t args[VTE_PARSER_ARG_MAX];
unsigned int n_st;
char *st;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]