mirror of
https://github.com/systemd/systemd.git
synced 2026-08-09 01:20:53 +00:00
string-util: don't miss ANSI sequence at the very end in previous_ansi_sequence()
The backwards scan started at offset length-3, so the last position at which a
sequence can begin, length-2, was never examined. CSI sequences are at least
three bytes long and were thus unaffected, but two byte Fe sequences (ESC
followed by 0x40…0x5F) terminating the examined slice were missed.
ellipsize_mem() calls this to figure out whether a sequence ends exactly at the
current position, so that it can be skipped over, which is precisely the case
that was broken: such a sequence was instead counted as two visible cells and
copied through as text, and the string was ellipsized more aggressively than
requested. For example ellipsize("🐱🐱\x1bM🐱🐱\x1bM", 5, 0) returned a three
cell wide string rather than the five cells asked for.
This commit is contained in:
committed by
Yu Watanabe
parent
3e04f8f450
commit
2bb179632f
@@ -293,13 +293,15 @@ static size_t previous_ansi_sequence(const char *s, size_t length, const char **
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = length - 2; i > 0; i--) { /* -2 because at least two bytes are needed */
|
||||
size_t slen = ansi_sequence_length(s + (i - 1), length - (i - 1));
|
||||
if (slen == 0)
|
||||
continue;
|
||||
for (size_t i = length - 2;; i--) { /* -2 because at least two bytes are needed */
|
||||
size_t slen = ansi_sequence_length(s + i, length - i);
|
||||
if (slen > 0) {
|
||||
*ret_where = s + i;
|
||||
return slen;
|
||||
}
|
||||
|
||||
*ret_where = s + (i - 1);
|
||||
return slen;
|
||||
if (i == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
*ret_where = NULL;
|
||||
|
||||
@@ -162,6 +162,21 @@ TEST(ellipsize_ansi_cats) {
|
||||
ASSERT_STREQ(h, "🐱…" ANSI_NORMAL "🐱" ANSI_NORMAL);
|
||||
}
|
||||
|
||||
TEST(ellipsize_ansi_two_byte) {
|
||||
_cleanup_free_ char *e = NULL, *f = NULL;
|
||||
|
||||
/* Fe escape sequences are just two bytes long (ESC followed by 0x40…0x5F). Make sure they are
|
||||
* skipped over like the longer CSI sequences are, in particular when one terminates the string. */
|
||||
|
||||
e = ellipsize("🐱🐱" "\x1bM" "🐱🐱" "\x1bM", 5, 0);
|
||||
puts(e);
|
||||
ASSERT_STREQ(e, "…" "\x1bM" "🐱🐱" "\x1bM");
|
||||
|
||||
f = ellipsize("ab" "\x1bM" "cd" "\x1bM", 4, 90);
|
||||
puts(f);
|
||||
ASSERT_STREQ(f, "ab" "\x1bM" "cd" "\x1bM");
|
||||
}
|
||||
|
||||
TEST(ellipsize_esc_infinite_loop) {
|
||||
/* Make sure we don't infinite loop on an ESC in the first half */
|
||||
static const char s[] = { 'A', 'B', 0x1B, ' ', 'D', '\0' };
|
||||
|
||||
Reference in New Issue
Block a user