From b4e5e5505cc4495c6237c32a65ba62ebcc497b31 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Mon, 7 Mar 2022 09:21:09 -0500 Subject: [PATCH] fix to readline redisplay of invisible chars at end of line; fix to here-document delimiter quote removal; prompt expansion makes invisible chars in w, W, s visible --- CWRU/CWRU.chlog | 57 +++++++++++++++++++++++++++++++++++- doc/bash.1 | 6 ++-- externs.h | 2 +- lib/readline/display.c | 10 ++++++- lib/readline/doc/readline.3 | 6 ++-- lib/readline/doc/rluser.texi | 7 +++-- lib/readline/search.c | 4 +++ lib/sh/shquote.c | 16 ++++++++-- lib/sh/strvis.c | 13 ++++---- make_cmd.c | 10 +++++-- parse.y | 8 ++--- shell.c | 6 ++++ support/bashbug.sh.in | 8 +++-- 13 files changed, 129 insertions(+), 24 deletions(-) diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index b1d47e03..ef39921f 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -3285,4 +3285,59 @@ lib/readline/misc.c Andreas Schwab , but does not make his scenario equivalent to incremental search - + 3/1 + --- +lib/readline/search.c + - make_history_line_current: save the current line before replacing it + with the found history entry using rl_maybe_save_line + - noninc_dosearch: we don't want the saved history line, so free it + after calling make_history_line_current + - _rl_history_search_internal: call rl_maybe_replace_line after making + changes to the line buffer with make_history_line_current so we can + save the undo list we constructed before we set the history position + + 3/2 + --- +lib/readline/display.c + - expand_prompt: add missing piece to patch from 10/26/2021: if we are + recalculating the number of invisible characters on the first line + of the prompt, we need to update INVFL, even if we already set it + when we hit the number of physical characters. This ends up being + assigned to prompt_invis_chars_first_line, and is used in several + subsequent calculations. Reported by + Andreas Schwab + +lib/readline/doc/{readline.3,rluser.texi},doc/bash.1 + - enable-bracketed-paste: add some language making it clearer that + bracketed paste prevents the pasted text from being interpreted as + editing commands. Suggested by Karl O. Pinc + + 3/4 + --- +make_cmd.c + - make_here_document: perform quote removal on the here-doc delimiter + only if it's marked as quoted, which prevents quotes from inside a + command substitution from being removed (they're supposed to begin a + new quoting context) when the word itself isn't flagged as quoted + (which means the body of the here-document gets expanded). You can't + perform quote removal *and* expand the here-document lines. From an + austin-group discussion back in early February + +lib/sh/strvis.c + - charvis -> sh_charvis; change caller + - sh_charvis: now take an additional SLEN argument to avoid having to + compute the string length every time; change callers + - sh_charvis: add a utf-8 locale-specific check before calling + COPY_CHAR_I (in practice, doesn't make any real difference) + +lib/sh/shquote.c + - sh_backslash_quote_for_double_quotes: if FLAGS&1, call sh_charvis on + every character to get the visible representation after possibly + adding a quoting backslash + +parse.y + - decode_prompt_string: make sure the expansion of \w, \W, and \s + are all run through sh_backslash_quote_for_double_quotes with the + `make visible' flag or through sh_strvis if we're not running the + prompt string through word expansions. Fixes issue reported by + Josh Harcome back in mid-January diff --git a/doc/bash.1 b/doc/bash.1 index d7380c71..d5d0e273 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -6084,8 +6084,10 @@ matching text found by incremental and non-incremental history searches. When set to \fBOn\fP, readline will configure the terminal in a way that will enable it to insert each paste into the editing buffer as a single string of characters, instead of treating each character as if -it had been read from the keyboard. This can prevent pasted characters -from being interpreted as editing commands. +it had been read from the keyboard +and executing any editing commands +bound to key sequences appearing in the pasted text. +This will prevent pasted characters from being interpreted as editing commands. .TP .B enable\-keypad (Off) When set to \fBOn\fP, readline will try to enable the application diff --git a/externs.h b/externs.h index 325703bb..86557501 100644 --- a/externs.h +++ b/externs.h @@ -472,7 +472,7 @@ extern int ansic_shouldquote PARAMS((const char *)); extern char *ansiexpand PARAMS((char *, int, int, int *)); /* declarations for functions defined in lib/sh/strvis.c */ -extern int charvis PARAMS((const char *, size_t *, char *, size_t *)); +extern int sh_charvis PARAMS((const char *, size_t *, size_t, char *, size_t *)); extern char *sh_strvis PARAMS((const char *)); /* declarations for functions defined in lib/sh/timeval.c. No prototypes diff --git a/lib/readline/display.c b/lib/readline/display.c index fe1e4cc9..3ac09c7c 100644 --- a/lib/readline/display.c +++ b/lib/readline/display.c @@ -439,7 +439,15 @@ expand_prompt (char *pmt, int flags, int *lp, int *lip, int *niflp, int *vlp) to add them, since update_line expects them to be counted before wrapping the line. */ if (can_add_invis) - local_prompt_newlines[newlines] = r - ret; + { + local_prompt_newlines[newlines] = r - ret; + /* If we're adding to the number of invisible characters on the + first line of the prompt, but we've already set the number of + invisible characters on that line, we need to adjust the + counter. */ + if (invflset && newlines == 1) + invfl = ninvis; + } if (p != (igstart + 1)) last = r - ret - 1; continue; diff --git a/lib/readline/doc/readline.3 b/lib/readline/doc/readline.3 index a3d26220..b61d5421 100644 --- a/lib/readline/doc/readline.3 +++ b/lib/readline/doc/readline.3 @@ -492,8 +492,10 @@ matching text found by incremental and non-incremental history searches. When set to \fBOn\fP, readline will configure the terminal in a way that will enable it to insert each paste into the editing buffer as a single string of characters, instead of treating each character as if -it had been read from the keyboard. This can prevent pasted characters -from being interpreted as editing commands. +it had been read from the keyboard +and executing any editing commands +bound to key sequences appearing in the pasted text. +This will prevent pasted characters from being interpreted as editing commands. .TP .B enable\-keypad (Off) When set to \fBOn\fP, readline will try to enable the application diff --git a/lib/readline/doc/rluser.texi b/lib/readline/doc/rluser.texi index 63e2c75d..deaff14d 100644 --- a/lib/readline/doc/rluser.texi +++ b/lib/readline/doc/rluser.texi @@ -591,8 +591,11 @@ The default is @samp{On}. When set to @samp{On}, Readline will configure the terminal in a way that will enable it to insert each paste into the editing buffer as a single string of characters, instead of treating each character as if -it had been read from the keyboard. This can prevent pasted characters -from being interpreted as editing commands. The default is @samp{On}. +it had been read from the keyboard +and executing any editing commands +bound to key sequences appearing in the pasted text. +This will prevent pasted characters from being interpreted as editing commands. +The default is @samp{On}. @item enable-keypad @vindex enable-keypad diff --git a/lib/readline/search.c b/lib/readline/search.c index c67519a4..22451663 100644 --- a/lib/readline/search.c +++ b/lib/readline/search.c @@ -93,6 +93,8 @@ make_history_line_current (HIST_ENTRY *entry) if (_rl_saved_line_for_history) _rl_free_saved_history_line (); + rl_maybe_save_line (); + /* Now we create a new undo list with a single insert for this text. WE DON'T CHANGE THE ORIGINAL HISTORY ENTRY UNDO LIST */ _rl_replace_text (entry->line, 0, rl_end); @@ -193,6 +195,7 @@ noninc_dosearch (char *string, int dir, int flags) history_set_pos (oldpos); make_history_line_current (entry); + _rl_free_saved_history_line (); if (_rl_enable_active_region && ((flags & SF_PATTERN) == 0) && ind > 0 && ind < rl_end) { @@ -585,6 +588,7 @@ rl_history_search_internal (int count, int dir) /* Make sure we set the current history position to the last line found so we can do things like operate-and-get-next from here. This is similar to how incremental search behaves. */ + rl_maybe_replace_line (); history_set_pos (_rl_history_search_pos); /* XXX */ /* decide where to put rl_point -- need to change this for pattern search */ diff --git a/lib/sh/shquote.c b/lib/sh/shquote.c index c67be253..622fcbb0 100644 --- a/lib/sh/shquote.c +++ b/lib/sh/shquote.c @@ -39,6 +39,8 @@ extern char *ansic_quote PARAMS((char *, int, int *)); extern int ansic_shouldquote PARAMS((const char *)); +extern int sh_charvis PARAMS((const char *, size_t *, size_t, char *, size_t *)); + /* Default set of characters that should be backslash-quoted in strings */ static const char bstab[256] = { @@ -314,7 +316,8 @@ sh_backslash_quote (string, table, flags) #if defined (PROMPT_STRING_DECODE) || defined (TRANSLATABLE_STRINGS) /* Quote characters that get special treatment when in double quotes in STRING using backslashes. If FLAGS == 1, also make `unsafe' characters visible by - translating them to a standard ^X/M-X representation (not yet implemented). + translating them to a standard ^X/M-X representation by calling sh_charvis, + which handles multibyte characters as well. Return a new string. */ char * sh_backslash_quote_for_double_quotes (string, flags) @@ -330,7 +333,8 @@ sh_backslash_quote_for_double_quotes (string, flags) slen = strlen (string); send = string + slen; mb_cur_max = MB_CUR_MAX; - result = (char *)xmalloc ((flags == 1 ? 3 : 2) * slen + 1); + /* Max is 4*string length (backslash + three-character visible representation) */ + result = (char *)xmalloc (4 * slen + 1); for (rind = sind = 0; c = string[sind]; sind++) { @@ -338,6 +342,14 @@ sh_backslash_quote_for_double_quotes (string, flags) if ((sh_syntaxtab[c] & CBSDQUOTE) && c != '\n') result[rind++] = '\\'; + + if (flags & 1) + { + sh_charvis (string, &sind, slen, result, &rind); + sind--; /* sh_charvis consumes an extra character */ + continue; + } + /* I should probably use the CSPECL flag for these in sh_syntaxtab[] */ else if (c == CTLESC || c == CTLNUL) result[rind++] = CTLESC; /* could be '\\'? */ diff --git a/lib/sh/strvis.c b/lib/sh/strvis.c index 2ad8b70f..97eee1fc 100644 --- a/lib/sh/strvis.c +++ b/lib/sh/strvis.c @@ -52,10 +52,11 @@ #define UNMETA(c) ((c) & 0x7f) #endif -static int -charvis (s, sindp, ret, rindp) +int +sh_charvis (s, sindp, slen, ret, rindp) const char *s; size_t *sindp; + size_t slen; char *ret; size_t *rindp; { @@ -68,7 +69,7 @@ charvis (s, sindp, ret, rindp) ri = *rindp; c = s[*sindp]; - send = (locale_mb_cur_max > 1) ? s + strlen (s) : 0; + send = (locale_mb_cur_max > 1) ? s + slen : 0; if (SAFECHAR (c)) { @@ -87,7 +88,9 @@ charvis (s, sindp, ret, rindp) ret[ri++] = UNCTRL (c); si++; } - else if (locale_mb_cur_max > 1) + else if (locale_utf8locale && (c & 0x80)) + COPY_CHAR_I (ret, ri, s, send, si); + else if (locale_mb_cur_max > 1 && is_basic (c) == 0) COPY_CHAR_I (ret, ri, s, send, si); else if (META_CHAR (c)) { @@ -138,7 +141,7 @@ sh_strvis (string) sind = 0; while (string[sind]) - sind = charvis (string, &sind, ret, &retind); + sind = sh_charvis (string, &sind, slen, ret, &retind); ret[retind] = '\0'; return ret; diff --git a/make_cmd.c b/make_cmd.c index 16e37623..98151a41 100644 --- a/make_cmd.c +++ b/make_cmd.c @@ -575,9 +575,16 @@ make_here_document (temp, lineno) full_line = document = (char *)NULL; document_index = document_size = 0; + delim_unquoted = (temp->redirectee.filename->flags & W_QUOTED) == 0; + /* Quote removal is the only expansion performed on the delimiter for here documents, making it an extremely special case. */ - redir_word = string_quote_removal (temp->redirectee.filename->word, 0); + /* "If any part of word is quoted, the delimiter shall be formed by + performing quote removal on word." */ + if (delim_unquoted == 0) + redir_word = string_quote_removal (temp->redirectee.filename->word, 0); + else + redir_word = savestring (temp->redirectee.filename->word); /* redirection_expand will return NULL if the expansion results in multiple words or no words. Check for that here, and just abort @@ -604,7 +611,6 @@ make_here_document (temp, lineno) /* If the here-document delimiter was quoted, the lines should be read verbatim from the input. If it was not quoted, we need to perform backslash-quoted newline removal. */ - delim_unquoted = (temp->redirectee.filename->flags & W_QUOTED) == 0; while (full_line = read_secondary_line (delim_unquoted)) { register char *line; diff --git a/parse.y b/parse.y index c61db457..777188c0 100644 --- a/parse.y +++ b/parse.y @@ -5742,9 +5742,9 @@ decode_prompt_string (string) temp = base_pathname (shell_name); /* Try to quote anything the user can set in the file system */ if (promptvars || posixly_correct) - temp = sh_backslash_quote_for_double_quotes (temp, 0); + temp = sh_backslash_quote_for_double_quotes (temp, 1); else - temp = savestring (temp); + temp = sh_strvis (temp); goto add_string; case 'v': @@ -5819,9 +5819,9 @@ decode_prompt_string (string) /* Make sure that expand_prompt_string is called with a second argument of Q_DOUBLE_QUOTES if we use this function here. */ - temp = sh_backslash_quote_for_double_quotes (t_string, 0); + temp = sh_backslash_quote_for_double_quotes (t_string, 1); else - temp = savestring (t_string); + temp = sh_strvis (t_string); goto add_string; } diff --git a/shell.c b/shell.c index a58f2678..ee9d445d 100644 --- a/shell.c +++ b/shell.c @@ -1128,6 +1128,7 @@ run_startup_files () #endif int sourced_login, run_by_ssh; +#if 1 /* TAG:bash-5.3 andrew.gregory.8@gmail.com 2/21/2022 */ /* get the rshd/sshd case out of the way first. */ if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 && act_like_sh == 0 && command_execution_string) @@ -1137,11 +1138,16 @@ run_startup_files () (find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0); #else run_by_ssh = 0; +#endif #endif /* If we were run by sshd or we think we were run by rshd, execute ~/.bashrc if we are a top-level shell. */ +#if 1 /* TAG:bash-5.3 */ if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2) +#else + if (isnetconn (fileno (stdin) && shell_level < 2) +#endif { #ifdef SYS_BASHRC # if defined (__OPENNT) diff --git a/support/bashbug.sh.in b/support/bashbug.sh.in index d6759d76..77e14e56 100644 --- a/support/bashbug.sh.in +++ b/support/bashbug.sh.in @@ -4,7 +4,7 @@ # # The bug address depends on the release status of the shell. Versions # with status `devel', `alpha', `beta', or `rc' mail bug reports to -# chet@cwru.edu and, optionally, to bash-testers@cwru.edu. +# chet.ramey@case.edu and, optionally, to bash-testers@cwru.edu. # Other versions send mail to bug-bash@gnu.org. # # Copyright (C) 1996-2021 Free Software Foundation, Inc. @@ -102,7 +102,7 @@ esac BASHTESTERS="bash-testers@cwru.edu" case "$RELSTATUS" in -alpha*|beta*|devel*|rc*) BUGBASH=chet@cwru.edu ;; +alpha*|beta*|devel*|rc*) BUGBASH=chet.ramey@case.edu ;; *) BUGBASH=bug-bash@gnu.org ;; esac @@ -132,6 +132,10 @@ if [ -z "$DEFEDITOR" ] && [ -z "$EDITOR" ]; then DEFEDITOR=emacs elif [ -x /usr/bin/xemacs ]; then DEFEDITOR=xemacs + elif [ -x /usr/bin/vim; then + DEFEDITOR=vim + elif [ -x /usr/bin/gvim; then + DEFEDITOR=gvim elif [ -x /usr/bin/nano ]; then DEFEDITOR=nano elif [ -x /usr/contrib/bin/jove ]; then