From dfa16f84deb0bf0d1f1cc8d223f695b2f971fc40 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Fri, 5 Mar 2021 12:48:06 +0000 Subject: winansi: fix ansi emulation The following commands (reported in GitHub issue #201): printf "\033[38;2;255;0;0mX\033[m\n" printf "\033[38;2;255;0;0m;\033[m\n" produce different results. The first correctly displays a red 'X' while the second incorrectly displays a white ';'. The problem is that process_24bit() overruns the extent of the escape sequence. As a result the loop in process_escape() which handles 'ESC[...m' sequences sees the ';' in the text as a continuation of the escape sequence. Fix this by: - reworking process_24bit() so that the overrun is avoided; - changing the test in the loop in process_escape() so that even if an overrun happens it stops processing at the end of the escape sequence. Also, save a few bytes by replacing '++str' with 'str + 1' in a few places. --- win32/winansi.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/win32/winansi.c b/win32/winansi.c index 971702f18..68b568b81 100644 --- a/win32/winansi.c +++ b/win32/winansi.c @@ -375,17 +375,18 @@ static WORD rgb_to_console(int *rgb) /* 24-bit colour */ static char *process_24bit(char *str, WORD *attr) { - int count = 0; - int rgb[3] = {0, 0, 0}; + int count; + int rgb[3]; - do { - rgb[count++] = strtol(str, (char **)&str, 10); - ++str; - } while (*(str-1) == ';' && count < 3); + for (count = 0; count < 3; ++count) { + rgb[count] = strtol(str, (char **)&str, 10); + if (*str == ';') + ++str; + } *attr = rgb_to_console(rgb); - return str; + return *(str - 1) == ';' ? str - 1 : str; } /* 8-bit colour */ @@ -435,10 +436,10 @@ static char *process_colour(char *str, WORD *attr) *attr = -1; /* error return */ switch (val) { case 2: - str = process_24bit(++str, attr); + str = process_24bit(str + 1, attr); break; case 5: - str = process_8bit(++str, attr); + str = process_8bit(str + 1, attr); break; default: break; @@ -541,7 +542,7 @@ static char *process_escape(char *pos) attr |= colour_1bit[val - 30]; break; case 38: /* 8/24 bit */ - str = process_colour(++str, &t); + str = process_colour(str + 1, &t); if (t != -1) { attr &= ~(FOREGROUND_ALL|FOREGROUND_INTENSITY); attr |= t; @@ -565,7 +566,7 @@ static char *process_escape(char *pos) attr |= colour_1bit[val - 40] << 4; break; case 48: /* 8/24 bit */ - str = process_colour(++str, &t); + str = process_colour(str + 1, &t); if (t != -1) { attr &= ~(BACKGROUND_ALL|BACKGROUND_INTENSITY); attr |= t << 4; @@ -581,7 +582,7 @@ static char *process_escape(char *pos) return pos; } str++; - } while (*(str-1) == ';'); + } while (str < func); current_attr = attr; if (reverse) -- cgit v1.2.3-55-g6feb