summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2024-10-31 11:22:39 +0100
committerLennart Poettering <lennart@poettering.net>2024-10-31 11:38:18 +0100
commita39c51799b27531183e7393ea9c669f6148f257a (patch)
tree0ab6caa97c9221e7d7166cc66c1db7bd4bdf6ffa /src
parentterminal-util: define ANSI_OSC as macro for the OSC terminal sequence prefix (diff)
downloadsystemd-a39c51799b27531183e7393ea9c669f6148f257a.tar.xz
systemd-a39c51799b27531183e7393ea9c669f6148f257a.zip
string-util: also check for 0x1b 0x5c ST when stripping ANSI from strings
Diffstat (limited to 'src')
-rw-r--r--src/basic/string-util.c25
-rw-r--r--src/test/test-strip-tab-ansi.c9
2 files changed, 31 insertions, 3 deletions
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index 9526443e50..171a368059 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -699,6 +699,7 @@ char* strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
STATE_ESCAPE,
STATE_CSI,
STATE_OSC,
+ STATE_OSC_CLOSING,
} state = STATE_OTHER;
_cleanup_(memstream_done) MemStream m = {};
size_t isz, shift[2] = {}, n_carriage_returns = 0;
@@ -711,7 +712,7 @@ char* strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
*
* 1. Replaces TABs by 8 spaces
* 2. Strips ANSI color sequences (a subset of CSI), i.e. ESC '[' … 'm' sequences
- * 3. Strips ANSI operating system sequences (OSC), i.e. ESC ']' … BEL sequences
+ * 3. Strips ANSI operating system sequences (OSC), i.e. ESC ']' … ST sequences
* 4. Strip trailing \r characters (since they would "move the cursor", but have no
* other effect).
*
@@ -796,14 +797,32 @@ char* strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
case STATE_OSC:
assert(n_carriage_returns == 0);
+ /* There are three kinds of OSC terminators: \x07, \x1b\x5c or \x9c. We only support
+ * the first two, because the last one is a valid UTF-8 codepoint and hence creates
+ * an ambiguity (many Terminal emulators refuse to support it as well). */
if (i >= *ibuf + isz || /* EOT … */
- (*i != '\a' && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */
+ (!IN_SET(*i, '\x07', '\x1b') && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */
fputc('\x1B', f);
fputc(']', f);
advance_offsets(i - *ibuf, highlight, shift, 2);
state = STATE_OTHER;
i = begin-1;
- } else if (*i == '\a')
+ } else if (*i == '\x07') /* Single character ST */
+ state = STATE_OTHER;
+ else if (*i == '\x1B')
+ state = STATE_OSC_CLOSING;
+
+ break;
+
+ case STATE_OSC_CLOSING:
+ if (i >= *ibuf + isz || /* EOT … */
+ *i != '\x5c') { /* … or incomplete two-byte ST in sequence */
+ fputc('\x1B', f);
+ fputc(']', f);
+ advance_offsets(i - *ibuf, highlight, shift, 2);
+ state = STATE_OTHER;
+ i = begin-1;
+ } else if (*i == '\x5c')
state = STATE_OTHER;
break;
diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c
index 3ad0fcd90e..00bd7cdaf1 100644
--- a/src/test/test-strip-tab-ansi.c
+++ b/src/test/test-strip-tab-ansi.c
@@ -67,6 +67,15 @@ TEST(strip_tab_ansi) {
assert_se(strip_tab_ansi(&q, NULL, NULL));
ASSERT_STREQ(q, qq);
}
+
+ /* Test that both kinds of ST are recognized after OSC */
+ assert_se(p = strdup("before" ANSI_OSC "inside1" ANSI_ST
+ "between1" ANSI_OSC "inside2\a"
+ "between2" ANSI_OSC "inside3\x1b\x5c"
+ "after"));
+ assert_se(strip_tab_ansi(&p, NULL, NULL));
+ ASSERT_STREQ(p, "beforebetween1between2after");
+ free(p);
}
DEFINE_TEST_MAIN(LOG_INFO);