From cd42ba388bbdd66b9bcc587defd55e2c449450a5 Mon Sep 17 00:00:00 2001 From: Adam Saponara Date: Wed, 24 Jul 2024 22:12:24 -0400 Subject: [PATCH] send non-printable codepoints as U+FFFD --- termbox2.h | 13 +++++++------ tests/test_invalid_utf8/expected.ansi | 2 +- tests/test_invalid_utf8/test.php | 6 +++++- tests/test_non_printable/expected.ansi | 24 ++++++++++++++++++++++++ tests/test_non_printable/test.php | 25 +++++++++++++++++++++++++ 5 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 tests/test_non_printable/expected.ansi create mode 100755 tests/test_non_printable/test.php diff --git a/termbox2.h b/termbox2.h index 5fc791f..d8ca3ad 100644 --- a/termbox2.h +++ b/termbox2.h @@ -51,6 +51,7 @@ SOFTWARE. #include #include #include +#include #ifdef PATH_MAX #define TB_PATH_MAX PATH_MAX @@ -493,6 +494,9 @@ int tb_hide_cursor(void); * * Function tb_extend_cell() is a shortcut for appending 1 codepoint to * cell->ech. + * + * Non-printable (`iswprint(3)`) codepoints are replaced with U+FFFD at render + * time. */ int tb_set_cell(int x, int y, uint32_t ch, uintattr_t fg, uintattr_t bg); int tb_set_cell_ex(int x, int y, uint32_t *ch, size_t nch, uintattr_t fg, @@ -3224,13 +3228,10 @@ static int send_cluster(int x, int y, uint32_t *ch, size_t nch) { int i; for (i = 0; i < (int)nch; i++) { uint32_t ch32 = *(ch + i); - int chu8_len; - if (ch32 == 0) { // replace null with space (from termbox 19dbee5) - chu8_len = 1; - chu8[0] = ' '; - } else { - chu8_len = tb_utf8_unicode_to_char(chu8, ch32); + if (!iswprint((wint_t)ch32)) { + ch32 = 0xfffd; // replace non-printable codepoints with U+FFFD } + int chu8_len = tb_utf8_unicode_to_char(chu8, ch32); if_err_return(rv, bytebuf_nputs(&global.out, chu8, (size_t)chu8_len)); } diff --git a/tests/test_invalid_utf8/expected.ansi b/tests/test_invalid_utf8/expected.ansi index b440b63..ec78ff0 100644 --- a/tests/test_invalid_utf8/expected.ansi +++ b/tests/test_invalid_utf8/expected.ansi @@ -1,5 +1,5 @@ #5foo� - +#5� diff --git a/tests/test_invalid_utf8/test.php b/tests/test_invalid_utf8/test.php index 76480dd..fc956cc 100755 --- a/tests/test_invalid_utf8/test.php +++ b/tests/test_invalid_utf8/test.php @@ -2,7 +2,11 @@ declare(strict_types=1); $test->ffi->tb_init(); -$test->ffi->tb_print_ex(0, 0, 0, 0, NULL, "foo\xc2\x00password"); + +$y = 0; +$test->ffi->tb_print_ex(0, $y++, 0, 0, NULL, "foo\xc2\x00password"); // stop at NULL +$test->ffi->tb_set_cell(0, $y++, 0xffff, 0, 0); // invalid codepoint + $test->ffi->tb_present(); $test->screencap(); diff --git a/tests/test_non_printable/expected.ansi b/tests/test_non_printable/expected.ansi new file mode 100644 index 0000000..a243cb7 --- /dev/null +++ b/tests/test_non_printable/expected.ansi @@ -0,0 +1,24 @@ +#50x00 � +#50x01 � +#50x08 � +#50x09 � +#50x0a � +#50x1f � +#50x7f � + + + + + + + + + + + + + + + + + diff --git a/tests/test_non_printable/test.php b/tests/test_non_printable/test.php new file mode 100755 index 0000000..e2c72da --- /dev/null +++ b/tests/test_non_printable/test.php @@ -0,0 +1,25 @@ +ffi->tb_init(); + +$codepoints = [ + 0x00, // NULL + 0x01, // control code + 0x08, // backspace + 0x09, // tab + 0x0a, // newline + 0x1f, // control code + 0x7f, // delete +]; + +$y = 0; +foreach ($codepoints as $ch) { + $test->ffi->tb_printf(0, $y, 0, 0, "0x%02x ", $ch); + $test->ffi->tb_set_cell(5, $y, $ch, 0, 0); + $y += 1; +} + +$test->ffi->tb_present(); + +$test->screencap(); -- 2.39.5