From 8648f52857e95d7b2bff71bddf1f0b1362a1d80a Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Wed, 17 Feb 2021 15:38:46 -0800 Subject: [PATCH] Use wcs2string when outputting the screen The screen output code predates the ENCODE_DIRECT scheme, and directly-encoded bytes were not being properly output. This manifested as private-user characters being mangled when printed as part of fish_prompt. Just use str2wcstring instead. Fixes #7723 --- src/output.cpp | 61 +++----------------------------------------------- src/output.h | 9 +++++--- 2 files changed, 9 insertions(+), 61 deletions(-) diff --git a/src/output.cpp b/src/output.cpp index 2dfe1566b..5dde264bc 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -309,64 +309,9 @@ int outputter_t::term_puts(const char *str, int affcnt) { return res; } -/// Write a wide character to the outputter. This should only be used when writing characters from -/// user supplied strings. This is needed due to our use of the ENCODE_DIRECT_BASE mechanism to -/// allow the user to specify arbitrary byte values to be output. Such as in a `printf` invocation -/// that includes literal byte values such as `\x1B`. This should not be used for writing non-user -/// supplied characters. -int outputter_t::writech(wint_t ch) { - char buff[MB_LEN_MAX + 1]; - size_t len; - - if (ch >= ENCODE_DIRECT_BASE && ch < ENCODE_DIRECT_BASE + 256) { - buff[0] = ch - ENCODE_DIRECT_BASE; - len = 1; - } else if (MB_CUR_MAX == 1) { - // single-byte locale (C/POSIX/ISO-8859) - // If `wc` contains a wide character we emit a question-mark. - buff[0] = ch & ~0xFF ? '?' : ch; - len = 1; - } else { - mbstate_t state = {}; - len = std::wcrtomb(buff, ch, &state); - if (len == static_cast(-1)) { - return 1; - } - } - this->writestr(buff, len); - return 0; -} - -/// Write a wide character string to stdout. This should not be used to output things like warning -/// messages; just use debug() or std::fwprintf() for that. It should only be used to output user -/// supplied strings that might contain literal bytes; e.g., "\342\224\214" from issue #1894. This -/// is needed because those strings may contain chars specially encoded using ENCODE_DIRECT_BASE. -void outputter_t::writestr(const wchar_t *str) { - assert(str && "Empty input string"); - - if (MB_CUR_MAX == 1) { - // Single-byte locale (C/POSIX/ISO-8859). - while (*str) writech(*str++); - return; - } - size_t len = wcstombs(nullptr, str, 0); // figure amount of space needed - if (len == static_cast(-1)) { - FLOGF(output_invalid, L"Tried to print invalid wide character string"); - return; - } - - // Convert the string. - len++; - char *buffer, static_buffer[256]; - if (len <= sizeof static_buffer) { - buffer = static_buffer; - } else { - buffer = new char[len]; - } - - int new_len = wcstombs(buffer, str, len); - this->writestr(buffer, new_len); - if (buffer != static_buffer) delete[] buffer; +void outputter_t::writestr(const wchar_t *str, size_t len) { + wcs2string_appending(str, len, &contents_); + maybe_flush(); } outputter_t &outputter_t::stdoutput() { diff --git a/src/output.h b/src/output.h index 548ad352c..8fa7fb725 100644 --- a/src/output.h +++ b/src/output.h @@ -59,17 +59,20 @@ class outputter_t { void set_color(rgb_color_t c, rgb_color_t c2); /// Write a wide character to the receiver. - int writech(wint_t ch); + void writech(wchar_t ch) { writestr(&ch, 1); } /// Write a NUL-terminated wide character string to the receiver. - void writestr(const wchar_t *str); + void writestr(const wchar_t *str) { writestr(str, wcslen(str)); } /// Write a wide character string to the receiver. - void writestr(const wcstring &str) { writestr(str.c_str()); } + void writestr(const wcstring &str) { writestr(str.data(), str.size()); } /// Write the given terminfo string to the receiver, like tputs(). int term_puts(const char *str, int affcnt); + /// Write a wide string of the given length. + void writestr(const wchar_t *str, size_t len); + /// Write a narrow string of the given length. void writestr(const char *str, size_t len) { contents_.append(str, len);