From: Bruno Haible Date: Wed, 28 Feb 2024 22:15:35 +0000 (+0100) Subject: libtextstyle: Avoid crashing the terminal emulator when using ncurses. X-Git-Tag: v0.23~264 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4a66b793721ec4f111b8764b984d407468c1be56;p=thirdparty%2Fgettext.git libtextstyle: Avoid crashing the terminal emulator when using ncurses. Reported by Adriaan de Groot in . Long explanation: * libtextstyle/gnulib-local/lib/term-ostream.oo.c (out_data_string, out_data_string_unchecked): New functions. (out_hyperlink_change): Don't use tputs on strings that are not escape sequences. --- diff --git a/libtextstyle/gnulib-local/lib/term-ostream.oo.c b/libtextstyle/gnulib-local/lib/term-ostream.oo.c index 1dd1a273f..94f01e09a 100644 --- a/libtextstyle/gnulib-local/lib/term-ostream.oo.c +++ b/libtextstyle/gnulib-local/lib/term-ostream.oo.c @@ -1208,6 +1208,16 @@ out_char (int c) return 0; } +/* Output an entire string (not an escape sequence) to out_fd. */ +static void +out_data_string (const char *s) +{ + size_t n = strlen (s); + if (n > 0) + if (full_write (out_fd, s, n) < n) + out_error (); +} + /* Output a single char to out_fd. Ignore errors. */ static _GL_ASYNC_SAFE int out_char_unchecked (int c) @@ -1219,6 +1229,16 @@ out_char_unchecked (int c) return 0; } +/* Output an entire string (not an escape sequence) to out_fd. + Ignore errors. */ +static _GL_ASYNC_SAFE void +out_data_string_unchecked (const char *s) +{ + size_t n = strlen (s); + if (n > 0) + full_write (out_fd, s, n); +} + /* Output escape sequences to switch the foreground color to NEW_COLOR. */ static _GL_ASYNC_SAFE void out_color_change (term_ostream_t stream, term_color_t new_color, @@ -1583,11 +1603,23 @@ out_hyperlink_change (term_ostream_t stream, hyperlink_t *new_hyperlink, if (new_hyperlink != NULL) { assert (new_hyperlink->real_id != NULL); - tputs ("\033]8;id=", 1, out_ch); - tputs (new_hyperlink->real_id, 1, out_ch); - tputs (";", 1, out_ch); - tputs (new_hyperlink->ref, 1, out_ch); - tputs ("\033\\", 1, out_ch); + /* We need to output the hyperlink's id and ref directly, not through + tputs(), because + - The tputs() documentation says that its first argument "must be + a terminfo string variable or the return value from tparm, + tgetstr, or tgoto." + - Some ncurses versions do special processing if the first argument + starts with a digit. Cf. BSD_TPUTS in the ncurses source code. + Maybe we should better pass the entire escape sequence to a single + tputs() call. But this would require a memory allocation, which can + fail. (The length limits on id and ref are not enforced.) */ + void (*out_string) (const char *) = + (async_safe ? out_data_string_unchecked : out_data_string); + tputs ("\033]8;id=", 1, out_ch); + out_string (new_hyperlink->real_id); + out_string (";"); + out_string (new_hyperlink->ref); + tputs ("\033\\", 1, out_ch); } else tputs ("\033]8;;\033\\", 1, out_ch);