From 545ac922d278f3864d2ad09bd54cf46ea29f710d Mon Sep 17 00:00:00 2001 From: Dimitris Panokostas Date: Tue, 21 Jul 2026 21:47:35 +0300 Subject: [PATCH 1/4] fix(host-shell): filter unsupported OSC output Modern Linux login shells emit terminal metadata such as systemd OSC 3008 markers. Track escape state across reads and remove OSC sequences before writing output to the Amiga console. --- Makefile | 7 +- src/host-shell.c | 43 ++++------ src/host_terminal_filter.h | 122 +++++++++++++++++++++++++++ tests/test_host_terminal_filter.c | 132 ++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+), 30 deletions(-) create mode 100644 src/host_terminal_filter.h create mode 100644 tests/test_host_terminal_filter.c diff --git a/Makefile b/Makefile index d5ecfbc..1d18035 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later TOOLS = host-run host-multiview host-shell host-path host-reveal host-notify host-edit host-clip host-info host-download host-env -TEST_BINS = tests/test_host_common.out tests/test_host_command_builders.out tests/test_host_edit_command.out tests/test_host_download_command.out +TEST_BINS = tests/test_host_common.out tests/test_host_command_builders.out tests/test_host_edit_command.out tests/test_host_download_command.out tests/test_host_terminal_filter.out TEST_SCRIPTS = tests/test_package_layout.sh tests/test_ahi_driver_source.sh TESTS = $(TEST_BINS) $(TEST_SCRIPTS) COMMON_HEADERS = src/host_common.h src/host_path.h src/host_capture.h src/host_base64.h src/host_clip_command.h src/host_download_command.h src/host_edit_command.h src/host_env_command.h src/host_info_command.h src/host_notify_command.h src/host_powershell.h src/host_reveal_command.h src/host_shell_command.h src/uae_pragmas.h @@ -74,7 +74,7 @@ host-run: src/host-run.c $(COMMON_HEADERS) host-multiview: src/host-multiview.c $(COMMON_HEADERS) $(CC) $(CFLAGS) $(VERFLAGS) $(INCLUDES) src/host-multiview.c -o $@ -host-shell: src/host-shell.c $(COMMON_HEADERS) +host-shell: src/host-shell.c $(COMMON_HEADERS) src/host_terminal_filter.h $(CC) $(CFLAGS) $(VERFLAGS) $(INCLUDES) src/host-shell.c -o $@ host-path: src/host-path.c $(COMMON_HEADERS) @@ -113,6 +113,9 @@ tests/test_host_edit_command.out: tests/test_host_edit_command.c src/host_edit_c tests/test_host_download_command.out: tests/test_host_download_command.c src/host_download_command.h src/host_base64.h src/host_common.h $(HOST_CC) $(HOST_NATIVE_FLAGS) $(HOST_CFLAGS) tests/test_host_download_command.c -o $@ +tests/test_host_terminal_filter.out: tests/test_host_terminal_filter.c src/host_terminal_filter.h + $(HOST_CC) $(HOST_NATIVE_FLAGS) $(HOST_CFLAGS) tests/test_host_terminal_filter.c -o $@ + debug: CFLAGS += -DDEBUG -g debug: clean all diff --git a/src/host-shell.c b/src/host-shell.c index 9044962..95ebcea 100644 --- a/src/host-shell.c +++ b/src/host-shell.c @@ -12,6 +12,7 @@ #include "host_capture.h" #include "host_common.h" #include "host_shell_command.h" +#include "host_terminal_filter.h" #define OUTBUFSIZE 4095 @@ -128,8 +129,8 @@ int main(int argc, char *argv[]) BPTR in = 0; BPTR out = 0; long handle = 0; - BOOL esc_pending = FALSE; BOOL raw_mode = FALSE; + struct host_terminal_filter terminal_filter = { HOST_TERMINAL_TEXT }; long actual; ULONG status; int status_supported = 0; @@ -222,30 +223,13 @@ int main(int argc, char *argv[]) actual = HostShell_Read(handle, (UBYTE *)buffer, sizeof(buffer) - 2); if (actual > 0) { - int outptr = 0; - for (int i = 0; i < actual; i++) { - unsigned char c = (unsigned char)buffer[i]; - if (esc_pending) { - if (c == 0x5B) { // '[' - outbuf[outptr++] = 0x9B; // CSI - } else { - outbuf[outptr++] = 0x1B; // Original ESC - outbuf[outptr++] = c; - } - esc_pending = FALSE; - } else { - if (c == 0x1B) { - esc_pending = TRUE; - } else { - outbuf[outptr++] = c; - } - } - - // Safety check for outbuf overflow (should rarely happen given the math) - if (outptr >= OUTBUFSIZE) { - Write(out, outbuf, outptr); - outptr = 0; - } + int outptr = host_terminal_filter_process(&terminal_filter, + (const unsigned char *)buffer, actual, + (unsigned char *)outbuf, sizeof(outbuf)); + if (outptr < 0) { + printf("Failed to translate host terminal output.\n"); + return_code = HOST_RETURN_ERROR; + goto cleanup; } if (outptr > 0) { Write(out, outbuf, outptr); @@ -318,9 +302,12 @@ int main(int argc, char *argv[]) } cleanup: - if (esc_pending && out != 0) { - outbuf[0] = 0x1B; - Write(out, outbuf, 1); + if (out != 0) { + int outptr = host_terminal_filter_finish(&terminal_filter, + (unsigned char *)outbuf, sizeof(outbuf)); + if (outptr > 0) { + Write(out, outbuf, outptr); + } } if (handle != 0) { HostShell_Close(handle); diff --git a/src/host_terminal_filter.h b/src/host_terminal_filter.h new file mode 100644 index 0000000..2900874 --- /dev/null +++ b/src/host_terminal_filter.h @@ -0,0 +1,122 @@ +/* + * SPDX-FileCopyrightText: 2020-2026 Dimitris Panokostas + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef HOST_TERMINAL_FILTER_H +#define HOST_TERMINAL_FILTER_H + +#define HOST_TERMINAL_TEXT 0 +#define HOST_TERMINAL_ESCAPE 1 +#define HOST_TERMINAL_OSC 2 +#define HOST_TERMINAL_OSC_ESCAPE 3 + +struct host_terminal_filter +{ + int state; +}; + +static inline int host_terminal_filter_put(unsigned char *output, int output_size, + int *output_len, unsigned char value) +{ + if (*output_len >= output_size) { + return 0; + } + + output[(*output_len)++] = value; + return 1; +} + +/* + * Convert host ANSI CSI sequences to the Amiga console's single-byte CSI and + * discard OSC sequences, which the Amiga console does not support. The state + * is retained so escape sequences may span HostShell_Read() calls. + * + * The output can be at most input_len + 1 bytes when a pending ESC from the + * previous call turns out to be literal. + */ +static inline int host_terminal_filter_process(struct host_terminal_filter *filter, + const unsigned char *input, int input_len, + unsigned char *output, int output_size) +{ + int output_len = 0; + + if (filter == NULL || input == NULL || input_len < 0 || + output == NULL || output_size < 0) { + return -1; + } + + for (int i = 0; i < input_len; i++) { + unsigned char c = input[i]; + + switch (filter->state) { + case HOST_TERMINAL_TEXT: + if (c == 0x1B) { + filter->state = HOST_TERMINAL_ESCAPE; + } else if (c == 0x9D) { + filter->state = HOST_TERMINAL_OSC; + } else if (!host_terminal_filter_put(output, output_size, &output_len, c)) { + return -1; + } + break; + + case HOST_TERMINAL_ESCAPE: + if (c == '[') { + if (!host_terminal_filter_put(output, output_size, &output_len, 0x9B)) { + return -1; + } + filter->state = HOST_TERMINAL_TEXT; + } else if (c == ']') { + filter->state = HOST_TERMINAL_OSC; + } else { + if (!host_terminal_filter_put(output, output_size, &output_len, 0x1B) || + !host_terminal_filter_put(output, output_size, &output_len, c)) { + return -1; + } + filter->state = HOST_TERMINAL_TEXT; + } + break; + + case HOST_TERMINAL_OSC: + if (c == 0x07 || c == 0x9C) { + filter->state = HOST_TERMINAL_TEXT; + } else if (c == 0x1B) { + filter->state = HOST_TERMINAL_OSC_ESCAPE; + } + break; + + case HOST_TERMINAL_OSC_ESCAPE: + if (c == '\\' || c == 0x07 || c == 0x9C) { + filter->state = HOST_TERMINAL_TEXT; + } else if (c != 0x1B) { + filter->state = HOST_TERMINAL_OSC; + } + break; + + default: + return -1; + } + } + + return output_len; +} + +static inline int host_terminal_filter_finish(struct host_terminal_filter *filter, + unsigned char *output, int output_size) +{ + int output_len = 0; + + if (filter == NULL || output == NULL || output_size < 0) { + return -1; + } + + if (filter->state == HOST_TERMINAL_ESCAPE && + !host_terminal_filter_put(output, output_size, &output_len, 0x1B)) { + return -1; + } + + filter->state = HOST_TERMINAL_TEXT; + return output_len; +} + +#endif diff --git a/tests/test_host_terminal_filter.c b/tests/test_host_terminal_filter.c new file mode 100644 index 0000000..e5c2576 --- /dev/null +++ b/tests/test_host_terminal_filter.c @@ -0,0 +1,132 @@ +/* + * SPDX-FileCopyrightText: 2020-2026 Dimitris Panokostas + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include +#include +#include + +#include "host_terminal_filter.h" + +static void require(int condition, const char *message) +{ + if (!condition) { + fprintf(stderr, "%s\n", message); + exit(1); + } +} + +static int process_chunks(const unsigned char *input, int input_len, int split, + unsigned char *output, int output_size) +{ + struct host_terminal_filter filter = { HOST_TERMINAL_TEXT }; + int first; + int second; + int tail; + + first = host_terminal_filter_process(&filter, input, split, output, output_size); + require(first >= 0, "first terminal-filter chunk should fit"); + + second = host_terminal_filter_process(&filter, input + split, input_len - split, + output + first, output_size - first); + require(second >= 0, "second terminal-filter chunk should fit"); + + tail = host_terminal_filter_finish(&filter, output + first + second, + output_size - first - second); + require(tail >= 0, "terminal-filter tail should fit"); + return first + second + tail; +} + +static void require_filtered_at_every_split(const unsigned char *input, int input_len, + const unsigned char *expected, int expected_len, + const char *message) +{ + unsigned char output[512]; + + for (int split = 0; split <= input_len; split++) { + int output_len; + + memset(output, 0, sizeof(output)); + output_len = process_chunks(input, input_len, split, output, sizeof(output)); + if (output_len != expected_len || memcmp(output, expected, expected_len) != 0) { + fprintf(stderr, "%s at split %d\n", message, split); + exit(1); + } + } +} + +static void test_plain_text(void) +{ + static const unsigned char input[] = "plain text\r\n"; + + require_filtered_at_every_split(input, sizeof(input) - 1, input, sizeof(input) - 1, + "plain text should be unchanged"); +} + +static void test_csi_conversion(void) +{ + static const unsigned char input[] = "\x1B[31mred\x1B[0m"; + static const unsigned char expected[] = "\233" "31mred" "\233" "0m"; + + require_filtered_at_every_split(input, sizeof(input) - 1, + expected, sizeof(expected) - 1, + "ANSI CSI should become Amiga CSI"); +} + +static void test_osc_st_filtering(void) +{ + static const unsigned char input[] = + "before\x1B]3008;start=01234567;machineid=abcdef;type=shell;cwd=/home/user\x1B\\after"; + static const unsigned char expected[] = "beforeafter"; + + require_filtered_at_every_split(input, sizeof(input) - 1, + expected, sizeof(expected) - 1, + "OSC terminated by ST should be discarded"); +} + +static void test_osc_bel_filtering(void) +{ + static const unsigned char input[] = "left\x1B]0;window title\x07right"; + static const unsigned char expected[] = "leftright"; + + require_filtered_at_every_split(input, sizeof(input) - 1, + expected, sizeof(expected) - 1, + "OSC terminated by BEL should be discarded"); +} + +static void test_incomplete_sequences(void) +{ + static const unsigned char dangling_escape[] = "text\x1B"; + static const unsigned char dangling_escape_expected[] = "text\x1B"; + static const unsigned char incomplete_osc[] = "text\x1B]3008;start=unfinished"; + static const unsigned char incomplete_osc_expected[] = "text"; + + require_filtered_at_every_split(dangling_escape, sizeof(dangling_escape) - 1, + dangling_escape_expected, + sizeof(dangling_escape_expected) - 1, + "a dangling non-OSC escape should be preserved"); + require_filtered_at_every_split(incomplete_osc, sizeof(incomplete_osc) - 1, + incomplete_osc_expected, + sizeof(incomplete_osc_expected) - 1, + "an incomplete OSC should be discarded"); +} + +static void test_unknown_escape(void) +{ + static const unsigned char input[] = "a\x1BPb"; + + require_filtered_at_every_split(input, sizeof(input) - 1, input, sizeof(input) - 1, + "an unknown escape should be preserved"); +} + +int main(void) +{ + test_plain_text(); + test_csi_conversion(); + test_osc_st_filtering(); + test_osc_bel_filtering(); + test_incomplete_sequences(); + test_unknown_escape(); + return 0; +} From 00eea6ec9a85949c4da9ee3ed3103f23b6105a0c Mon Sep 17 00:00:00 2001 From: Dimitris Panokostas Date: Tue, 21 Jul 2026 22:01:49 +0300 Subject: [PATCH 2/4] fix(host-shell): preserve UTF-8 output Bytes 0x9C and 0x9D can be UTF-8 continuation bytes. Recognize only the 7-bit OSC forms emitted by the PTY so multibyte output remains intact. --- src/host_terminal_filter.h | 6 ++---- tests/test_host_terminal_filter.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/host_terminal_filter.h b/src/host_terminal_filter.h index 2900874..d5657db 100644 --- a/src/host_terminal_filter.h +++ b/src/host_terminal_filter.h @@ -53,8 +53,6 @@ static inline int host_terminal_filter_process(struct host_terminal_filter *filt case HOST_TERMINAL_TEXT: if (c == 0x1B) { filter->state = HOST_TERMINAL_ESCAPE; - } else if (c == 0x9D) { - filter->state = HOST_TERMINAL_OSC; } else if (!host_terminal_filter_put(output, output_size, &output_len, c)) { return -1; } @@ -78,7 +76,7 @@ static inline int host_terminal_filter_process(struct host_terminal_filter *filt break; case HOST_TERMINAL_OSC: - if (c == 0x07 || c == 0x9C) { + if (c == 0x07) { filter->state = HOST_TERMINAL_TEXT; } else if (c == 0x1B) { filter->state = HOST_TERMINAL_OSC_ESCAPE; @@ -86,7 +84,7 @@ static inline int host_terminal_filter_process(struct host_terminal_filter *filt break; case HOST_TERMINAL_OSC_ESCAPE: - if (c == '\\' || c == 0x07 || c == 0x9C) { + if (c == '\\' || c == 0x07) { filter->state = HOST_TERMINAL_TEXT; } else if (c != 0x1B) { filter->state = HOST_TERMINAL_OSC; diff --git a/tests/test_host_terminal_filter.c b/tests/test_host_terminal_filter.c index e5c2576..e71a07f 100644 --- a/tests/test_host_terminal_filter.c +++ b/tests/test_host_terminal_filter.c @@ -95,6 +95,26 @@ static void test_osc_bel_filtering(void) "OSC terminated by BEL should be discarded"); } +static void test_utf8_output(void) +{ + static const unsigned char input[] = + "UTF-8 quotes: \xE2\x80\x9C" "left\xE2\x80\x9D" " right"; + + require_filtered_at_every_split(input, sizeof(input) - 1, input, sizeof(input) - 1, + "UTF-8 continuation bytes should be unchanged"); +} + +static void test_utf8_osc_payload(void) +{ + static const unsigned char input[] = + "before\x1B]0;UTF-8 \xE2\x80\x9C" "title\xE2\x80\x9D\x1B\\after"; + static const unsigned char expected[] = "beforeafter"; + + require_filtered_at_every_split(input, sizeof(input) - 1, + expected, sizeof(expected) - 1, + "UTF-8 OSC payload should remain filtered"); +} + static void test_incomplete_sequences(void) { static const unsigned char dangling_escape[] = "text\x1B"; @@ -126,6 +146,8 @@ int main(void) test_csi_conversion(); test_osc_st_filtering(); test_osc_bel_filtering(); + test_utf8_output(); + test_utf8_osc_payload(); test_incomplete_sequences(); test_unknown_escape(); return 0; From dd1af9213bec0c504af70ce732af66f414a42711 Mon Sep 17 00:00:00 2001 From: Dimitris Panokostas Date: Tue, 21 Jul 2026 22:14:28 +0300 Subject: [PATCH 3/4] fix(host-shell): handle C1 ST in UTF-8 Track UTF-8 continuation bytes inside discarded OSC payloads. A standalone 0x9C ends OSC while encoded 0x9C bytes remain payload. --- src/host-shell.c | 2 +- src/host_terminal_filter.h | 29 +++++++++++++++++++++++++++-- tests/test_host_terminal_filter.c | 13 ++++++++++++- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/host-shell.c b/src/host-shell.c index 95ebcea..8d93473 100644 --- a/src/host-shell.c +++ b/src/host-shell.c @@ -130,7 +130,7 @@ int main(int argc, char *argv[]) BPTR out = 0; long handle = 0; BOOL raw_mode = FALSE; - struct host_terminal_filter terminal_filter = { HOST_TERMINAL_TEXT }; + struct host_terminal_filter terminal_filter = { HOST_TERMINAL_TEXT, 0 }; long actual; ULONG status; int status_supported = 0; diff --git a/src/host_terminal_filter.h b/src/host_terminal_filter.h index d5657db..2bd843f 100644 --- a/src/host_terminal_filter.h +++ b/src/host_terminal_filter.h @@ -14,8 +14,23 @@ struct host_terminal_filter { int state; + int utf8_remaining; }; +static inline int host_terminal_filter_utf8_continuations(unsigned char value) +{ + if (value >= 0xC2 && value <= 0xDF) { + return 1; + } + if (value >= 0xE0 && value <= 0xEF) { + return 2; + } + if (value >= 0xF0 && value <= 0xF4) { + return 3; + } + return 0; +} + static inline int host_terminal_filter_put(unsigned char *output, int output_size, int *output_len, unsigned char value) { @@ -66,6 +81,7 @@ static inline int host_terminal_filter_process(struct host_terminal_filter *filt filter->state = HOST_TERMINAL_TEXT; } else if (c == ']') { filter->state = HOST_TERMINAL_OSC; + filter->utf8_remaining = 0; } else { if (!host_terminal_filter_put(output, output_size, &output_len, 0x1B) || !host_terminal_filter_put(output, output_size, &output_len, c)) { @@ -76,18 +92,26 @@ static inline int host_terminal_filter_process(struct host_terminal_filter *filt break; case HOST_TERMINAL_OSC: - if (c == 0x07) { + if (filter->utf8_remaining > 0 && c >= 0x80 && c <= 0xBF) { + filter->utf8_remaining--; + } else if (c == 0x07 || c == 0x9C) { filter->state = HOST_TERMINAL_TEXT; + filter->utf8_remaining = 0; } else if (c == 0x1B) { filter->state = HOST_TERMINAL_OSC_ESCAPE; + filter->utf8_remaining = 0; + } else { + filter->utf8_remaining = host_terminal_filter_utf8_continuations(c); } break; case HOST_TERMINAL_OSC_ESCAPE: - if (c == '\\' || c == 0x07) { + if (c == '\\' || c == 0x07 || c == 0x9C) { filter->state = HOST_TERMINAL_TEXT; + filter->utf8_remaining = 0; } else if (c != 0x1B) { filter->state = HOST_TERMINAL_OSC; + filter->utf8_remaining = host_terminal_filter_utf8_continuations(c); } break; @@ -114,6 +138,7 @@ static inline int host_terminal_filter_finish(struct host_terminal_filter *filte } filter->state = HOST_TERMINAL_TEXT; + filter->utf8_remaining = 0; return output_len; } diff --git a/tests/test_host_terminal_filter.c b/tests/test_host_terminal_filter.c index e71a07f..306e463 100644 --- a/tests/test_host_terminal_filter.c +++ b/tests/test_host_terminal_filter.c @@ -20,7 +20,7 @@ static void require(int condition, const char *message) static int process_chunks(const unsigned char *input, int input_len, int split, unsigned char *output, int output_size) { - struct host_terminal_filter filter = { HOST_TERMINAL_TEXT }; + struct host_terminal_filter filter = { HOST_TERMINAL_TEXT, 0 }; int first; int second; int tail; @@ -95,6 +95,16 @@ static void test_osc_bel_filtering(void) "OSC terminated by BEL should be discarded"); } +static void test_osc_c1_st_filtering(void) +{ + static const unsigned char input[] = "left\x1B]0;window title\x9C" "right"; + static const unsigned char expected[] = "leftright"; + + require_filtered_at_every_split(input, sizeof(input) - 1, + expected, sizeof(expected) - 1, + "OSC terminated by C1 ST should be discarded"); +} + static void test_utf8_output(void) { static const unsigned char input[] = @@ -146,6 +156,7 @@ int main(void) test_csi_conversion(); test_osc_st_filtering(); test_osc_bel_filtering(); + test_osc_c1_st_filtering(); test_utf8_output(); test_utf8_osc_payload(); test_incomplete_sequences(); From 5c8994c5e2d1351ed543410b45723f1ac6e0b3c6 Mon Sep 17 00:00:00 2001 From: Dimitris Panokostas Date: Tue, 21 Jul 2026 22:29:45 +0300 Subject: [PATCH 4/4] fix(host-shell): filter C1 OSC sequences Track UTF-8 continuation bytes in text state so standalone 0x9D starts OSC without dropping valid UTF-8 output. --- src/host_terminal_filter.h | 22 ++++++++++++++++++---- tests/test_host_terminal_filter.c | 17 +++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/host_terminal_filter.h b/src/host_terminal_filter.h index 2bd843f..6a0e087 100644 --- a/src/host_terminal_filter.h +++ b/src/host_terminal_filter.h @@ -66,10 +66,23 @@ static inline int host_terminal_filter_process(struct host_terminal_filter *filt switch (filter->state) { case HOST_TERMINAL_TEXT: - if (c == 0x1B) { - filter->state = HOST_TERMINAL_ESCAPE; - } else if (!host_terminal_filter_put(output, output_size, &output_len, c)) { - return -1; + if (filter->utf8_remaining > 0 && c >= 0x80 && c <= 0xBF) { + filter->utf8_remaining--; + if (!host_terminal_filter_put(output, output_size, &output_len, c)) { + return -1; + } + } else { + filter->utf8_remaining = 0; + if (c == 0x1B) { + filter->state = HOST_TERMINAL_ESCAPE; + } else if (c == 0x9D) { + filter->state = HOST_TERMINAL_OSC; + } else { + filter->utf8_remaining = host_terminal_filter_utf8_continuations(c); + if (!host_terminal_filter_put(output, output_size, &output_len, c)) { + return -1; + } + } } break; @@ -88,6 +101,7 @@ static inline int host_terminal_filter_process(struct host_terminal_filter *filt return -1; } filter->state = HOST_TERMINAL_TEXT; + filter->utf8_remaining = host_terminal_filter_utf8_continuations(c); } break; diff --git a/tests/test_host_terminal_filter.c b/tests/test_host_terminal_filter.c index 306e463..b9ccfdd 100644 --- a/tests/test_host_terminal_filter.c +++ b/tests/test_host_terminal_filter.c @@ -105,6 +105,22 @@ static void test_osc_c1_st_filtering(void) "OSC terminated by C1 ST should be discarded"); } +static void test_c1_osc_filtering(void) +{ + static const unsigned char st_input[] = + "left\x9D" "0;window title\x9C" "right"; + static const unsigned char bel_input[] = + "left\x9D" "0;window title\x07right"; + static const unsigned char expected[] = "leftright"; + + require_filtered_at_every_split(st_input, sizeof(st_input) - 1, + expected, sizeof(expected) - 1, + "C1 OSC terminated by C1 ST should be discarded"); + require_filtered_at_every_split(bel_input, sizeof(bel_input) - 1, + expected, sizeof(expected) - 1, + "C1 OSC terminated by BEL should be discarded"); +} + static void test_utf8_output(void) { static const unsigned char input[] = @@ -157,6 +173,7 @@ int main(void) test_osc_st_filtering(); test_osc_bel_filtering(); test_osc_c1_st_filtering(); + test_c1_osc_filtering(); test_utf8_output(); test_utf8_osc_payload(); test_incomplete_sequences();