diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 9de61aafe8..efd690b076 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -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; diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c index 3d47cfebe2..806d4f54ca 100644 --- a/src/test/test-ellipsize.c +++ b/src/test/test-ellipsize.c @@ -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' };