From e7a56619a2f8d8d8e49ba96b9febc22bce1f74f0 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Mon, 21 Feb 2022 10:06:44 -0500 Subject: [PATCH] changes to make EOF state available to readline applications; fix for command substitution parsing inside conditional command --- CWRU/CWRU.chlog | 61 +++++++++++++++++++++++++++++++++++ lib/readline/callback.c | 8 ++++- lib/readline/doc/rltech.texi | 11 +++++++ lib/readline/doc/version.texi | 4 +-- lib/readline/history.h | 2 +- lib/readline/misc.c | 3 +- lib/readline/readline.c | 24 +++++++++----- lib/readline/readline.h | 9 ++++-- lib/readline/rlprivate.h | 2 +- lib/readline/rltty.c | 4 +-- lib/readline/search.c | 46 +++++++++++++------------- parse.y | 6 +++- parser.h | 2 +- pathexp.c | 1 + 14 files changed, 140 insertions(+), 43 deletions(-) diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index f54788ff..ac14de65 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -3184,3 +3184,64 @@ builtins/shopt.def the range of the compatNN options, just leave it alone when unsetting one of the options (which by definition was already unset). Fixes issue reported by Mihai Moldovan + + 2/16 + ---- +lib/readline/search.c + - rl_history_search_{pos,len,flags}: rename to have a leading `_' + - _rl_history_search_pos: no longer static so other parts of readline + can see it + +lib/readline/rlprivate.h + - _rl_history_search_pos: extern declaration + +lib/readline/readline.c + - readline_internal_teardown: don't run the undo list against the + current history entry if the non-incremental search functions have + set _rl_history_search_pos to it, since it doesn't reflect the + current contents of the line buffer. Fixes issue reported by + Andreas Schwab + +lib/readline/misc.c + - _rl_start_using_history: initialize _rl_history_search_pos to + something invalid so it doesn't match where_history() + + 2/17 + ---- +lib/readline/callback.c + - rl_callback_read_char: make sure _rl_eof_found is set to the value + of eof before calling the deprep terminal function, so it can do + different things based on whether the input code read EOF (or the + user entered the EOF character). From a gdb discussion started by + Andrew Burgess (still more to do, since this + is not part of the public API) + + 2/18 + ---- +lib/readline/readline.h + - RL_STATE_EOF: new readline state value; set when readline reads an + EOF character on an empty line or a read returns an error + - rl_eof_found: new public variable + +lib/readline/rprivate.h + - _rl_eof_found: renamed to rl_eof_found, so not declared here + +lib/readline/{callback,readline}.c + - RL_STATE_EOF: set appropriately when readline gets an EOF. Suggested + by Andrew Burgess + - RL_STATE_EOF: make sure it's not set when readline starts + - rl_eof_found: set appropriately when readline gets an EOF + +lib/readline/{callback,readline,rltty}.c + - rl_eof_found: new name for _rl_eof_found + +lib/readline/doc/rltech.texi + - RL_STATE_EOF: document + + 2/19 + ---- +parse.y + - parse_comsub: turn off parser state flags we don't want to inherit + into this call to the parser (PST_REGEXP, PST_EXTPAT, PST_CONDCMD, + PST_CONDEXPR for now). Fixes bug reported by konsolebox + diff --git a/lib/readline/callback.c b/lib/readline/callback.c index cfff6502..1a3235f1 100644 --- a/lib/readline/callback.c +++ b/lib/readline/callback.c @@ -1,6 +1,6 @@ /* callback.c -- functions to use readline as an X `callback' mechanism. */ -/* Copyright (C) 1987-2017 Free Software Foundation, Inc. +/* Copyright (C) 1987-2022 Free Software Foundation, Inc. This file is part of the GNU Readline Library (Readline), a library for reading lines of text with interactive input and history editing. @@ -136,6 +136,8 @@ rl_callback_read_char (void) abort (); } + eof = 0; + memcpy ((void *)olevel, (void *)_rl_top_level, sizeof (procenv_t)); #if defined (HAVE_POSIX_SIGSETJMP) jcode = sigsetjmp (_rl_top_level, 0); @@ -276,6 +278,10 @@ rl_callback_read_char (void) _rl_want_redisplay = 0; } + /* Make sure application hooks can see whether we saw EOF. */ + if (rl_eof_found = eof) + RL_SETSTATE(RL_STATE_EOF); + if (rl_done) { line = readline_internal_teardown (eof); diff --git a/lib/readline/doc/rltech.texi b/lib/readline/doc/rltech.texi index 01343edc..6f7ffb93 100644 --- a/lib/readline/doc/rltech.texi +++ b/lib/readline/doc/rltech.texi @@ -323,6 +323,14 @@ and point define a @emph{region}. @deftypevar int rl_done Setting this to a non-zero value causes Readline to return the current line immediately. +Readline will set this variable when it has read a key sequence bound +to @code{accept-line} and is about to return the line to the caller. +@end deftypevar + +@deftypevar int rl_eof_found +Readline will set this variable when it has read an EOF character (e.g., the +stty @samp{EOF} character) on an empty line or encountered a read error and +is about to return a NULL line to the caller. @end deftypevar @deftypevar int rl_num_chars_to_read @@ -597,6 +605,9 @@ and is about to return the line to the caller. Readline has timed out (it did not receive a line or specified number of characters before the timeout duration specified by @code{rl_set_timeout} elapsed) and is returning that status to the caller. +@item RL_STATE_EOF +Readline has read an EOF character (e.g., the stty @samp{EOF} character) +or encountered a read error and is about to return a NULL line to the caller. @end table @end deftypevar diff --git a/lib/readline/doc/version.texi b/lib/readline/doc/version.texi index 46c88bdb..42ead150 100644 --- a/lib/readline/doc/version.texi +++ b/lib/readline/doc/version.texi @@ -5,7 +5,7 @@ Copyright (C) 1988-2022 Free Software Foundation, Inc. @set EDITION 8.2 @set VERSION 8.2 -@set UPDATED Thu Feb 10 10:56:04 EST 2022 +@set UPDATED 18 February 2022 @set UPDATED-MONTH February 2022 -@set LASTCHANGE Thu Feb 10 10:56:20 EST 2022 +@set LASTCHANGE Fri Feb 18 11:12:48 EST 2022 diff --git a/lib/readline/history.h b/lib/readline/history.h index ad2ce70a..5208f9a4 100644 --- a/lib/readline/history.h +++ b/lib/readline/history.h @@ -1,6 +1,6 @@ /* history.h -- the names of functions that you can call in history. */ -/* Copyright (C) 1989-2021 Free Software Foundation, Inc. +/* Copyright (C) 1989-2022 Free Software Foundation, Inc. This file contains the GNU History Library (History), a set of routines for managing the text of previously typed lines. diff --git a/lib/readline/misc.c b/lib/readline/misc.c index 5670cdac..622ebec5 100644 --- a/lib/readline/misc.c +++ b/lib/readline/misc.c @@ -1,6 +1,6 @@ /* misc.c -- miscellaneous bindable readline functions. */ -/* Copyright (C) 1987-2021 Free Software Foundation, Inc. +/* Copyright (C) 1987-2022 Free Software Foundation, Inc. This file is part of the GNU Readline Library (Readline), a library for reading lines of text with interactive input and history editing. @@ -308,6 +308,7 @@ _rl_start_using_history (void) if (_rl_saved_line_for_history) _rl_free_saved_history_line (); _rl_saved_line_for_history = (HIST_ENTRY *)NULL; + _rl_history_search_pos = -99; /* some random invalid history position */ } /* Free the contents (and containing structure) of a HIST_ENTRY. */ diff --git a/lib/readline/readline.c b/lib/readline/readline.c index 371e1fbc..888612c6 100644 --- a/lib/readline/readline.c +++ b/lib/readline/readline.c @@ -1,7 +1,7 @@ /* readline.c -- a general facility for reading lines of input with emacs style editing and completion. */ -/* Copyright (C) 1987-2021 Free Software Foundation, Inc. +/* Copyright (C) 1987-2022 Free Software Foundation, Inc. This file is part of the GNU Readline Library (Readline), a library for reading lines of text with interactive input and history editing. @@ -164,6 +164,9 @@ int rl_end; /* Make this non-zero to return the current input_line. */ int rl_done; +/* If non-zero when readline_internal returns, it means we found EOF */ +int rl_eof_found = 0; + /* The last function executed by readline. */ rl_command_func_t *rl_last_func = (rl_command_func_t *)NULL; @@ -217,9 +220,6 @@ int _rl_eof_char = CTRL ('D'); /* Non-zero makes this the next keystroke to read. */ int rl_pending_input = 0; -/* If non-zero when readline_internal returns, it means we found EOF */ -int _rl_eof_found = 0; - /* Pointer to a useful terminal name. */ const char *rl_terminal_name = (const char *)NULL; @@ -479,11 +479,17 @@ readline_internal_teardown (int eof) RL_CHECK_SIGNALS (); + if (eof) + RL_SETSTATE (RL_STATE_EOF); /* XXX */ + /* Restore the original of this history line, iff the line that we are editing was originally in the history, AND the line has changed. */ entry = current_history (); - if (entry && rl_undo_list) + /* We don't want to do this if we executed functions that call + history_set_pos to set the history offset to the line containing the + non-incremental search string. */ + if (entry && rl_undo_list && _rl_history_search_pos != where_history ()) { temp = savestring (the_line); rl_revert_line (1, 0); @@ -615,6 +621,7 @@ readline_internal_charloop (void) RL_SETSTATE(RL_STATE_DONE); return (rl_done = 1); #else + RL_SETSTATE(RL_STATE_EOF); eof_found = 1; break; #endif @@ -655,6 +662,7 @@ readline_internal_charloop (void) RL_SETSTATE(RL_STATE_DONE); return (rl_done = 1); #else + RL_SETSTATE(RL_STATE_EOF); eof_found = 1; break; #endif @@ -717,8 +725,8 @@ static char * readline_internal (void) { readline_internal_setup (); - _rl_eof_found = readline_internal_charloop (); - return (readline_internal_teardown (_rl_eof_found)); + rl_eof_found = readline_internal_charloop (); + return (readline_internal_teardown (rl_eof_found)); } void @@ -1178,7 +1186,7 @@ rl_initialize (void) /* We aren't done yet. We haven't even gotten started yet! */ rl_done = 0; - RL_UNSETSTATE(RL_STATE_DONE); + RL_UNSETSTATE(RL_STATE_DONE|RL_STATE_TIMEOUT|RL_STATE_EOF); /* Tell the history routines what is going on. */ _rl_start_using_history (); diff --git a/lib/readline/readline.h b/lib/readline/readline.h index 7cf1fcf5..cac269f0 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -1,6 +1,6 @@ /* Readline.h -- the names of functions callable from within readline. */ -/* Copyright (C) 1987-2021 Free Software Foundation, Inc. +/* Copyright (C) 1987-2022 Free Software Foundation, Inc. This file is part of the GNU Readline Library (Readline), a library for reading lines of text with interactive input and history editing. @@ -562,6 +562,10 @@ extern int rl_mark; line and should return it. */ extern int rl_done; +/* Flag to indicate that readline has read an EOF character or read has + returned 0 or error, and is returning a NULL line as a result. */ +extern int rl_eof_found; + /* If set to a character value, that will be the next keystroke read. */ extern int rl_pending_input; @@ -917,7 +921,8 @@ extern int rl_persistent_signal_handlers; #define RL_STATE_REDISPLAYING 0x1000000 /* updating terminal display */ #define RL_STATE_DONE 0x2000000 /* done; accepted line */ -#define RL_STATE_TIMEOUT 0x4000000 +#define RL_STATE_TIMEOUT 0x4000000 /* done; timed out */ +#define RL_STATE_EOF 0x8000000 /* done; got eof on read */ #define RL_SETSTATE(x) (rl_readline_state |= (x)) #define RL_UNSETSTATE(x) (rl_readline_state &= ~(x)) diff --git a/lib/readline/rlprivate.h b/lib/readline/rlprivate.h index db20b92c..70ff01c2 100644 --- a/lib/readline/rlprivate.h +++ b/lib/readline/rlprivate.h @@ -563,7 +563,6 @@ extern FILE *_rl_in_stream; extern FILE *_rl_out_stream; extern int _rl_last_command_was_kill; extern int _rl_eof_char; -extern int _rl_eof_found; extern procenv_t _rl_top_level; extern _rl_keyseq_cxt *_rl_kscxt; extern int _rl_keyseq_timeout; @@ -574,6 +573,7 @@ extern rl_hook_func_t *_rl_internal_startup_hook; /* search.c */ extern _rl_search_cxt *_rl_nscxt; +extern int _rl_history_search_pos; /* signals.c */ extern int volatile _rl_caught_signal; diff --git a/lib/readline/rltty.c b/lib/readline/rltty.c index b34de2a4..882a3d46 100644 --- a/lib/readline/rltty.c +++ b/lib/readline/rltty.c @@ -1,7 +1,7 @@ /* rltty.c -- functions to prepare and restore the terminal for readline's use. */ -/* Copyright (C) 1992-2021 Free Software Foundation, Inc. +/* Copyright (C) 1992-2022 Free Software Foundation, Inc. This file is part of the GNU Readline Library (Readline), a library for reading lines of text with interactive input and history editing. @@ -694,7 +694,7 @@ rl_deprep_terminal (void) fprintf (rl_outstream, BRACK_PASTE_FINI); /* Since the last character in BRACK_PASTE_FINI is \r */ _rl_last_c_pos = 0; - if (_rl_eof_found && (RL_ISSTATE (RL_STATE_TIMEOUT) == 0)) + if (rl_eof_found && (RL_ISSTATE (RL_STATE_TIMEOUT) == 0)) fprintf (rl_outstream, "\n"); else if (_rl_echoing_p == 0) fprintf (rl_outstream, "\n"); diff --git a/lib/readline/search.c b/lib/readline/search.c index 325d51ec..89f5961a 100644 --- a/lib/readline/search.c +++ b/lib/readline/search.c @@ -1,6 +1,6 @@ /* search.c - code for non-incremental searching in emacs and vi modes. */ -/* Copyright (C) 1992-2021 Free Software Foundation, Inc. +/* Copyright (C) 1992-2022 Free Software Foundation, Inc. This file is part of the GNU Readline Library (Readline), a library for reading lines of text with interactive input and history editing. @@ -60,9 +60,9 @@ static int noninc_history_pos; static char *prev_line_found = (char *) NULL; -static int rl_history_search_len; -static int rl_history_search_pos; -static int rl_history_search_flags; +static int _rl_history_search_len; +/*static*/ int _rl_history_search_pos; +static int _rl_history_search_flags; static char *history_search_string; static int history_string_size; @@ -539,14 +539,14 @@ rl_history_search_internal (int count, int dir) while (count) { RL_CHECK_SIGNALS (); - ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir, 0, &newcol); + ret = noninc_search_from_pos (history_search_string, _rl_history_search_pos + dir, dir, 0, &newcol); if (ret == -1) break; /* Get the history entry we found. */ - rl_history_search_pos = ret; + _rl_history_search_pos = ret; oldpos = where_history (); - history_set_pos (rl_history_search_pos); + history_set_pos (_rl_history_search_pos); temp = current_history (); /* will never be NULL after successful search */ history_set_pos (oldpos); @@ -566,14 +566,14 @@ rl_history_search_internal (int count, int dir) in the line buffer after the search fails, change the #if 0 to #if 1 */ #if 0 - if (rl_point > rl_history_search_len) + if (rl_point > _rl_history_search_len) { - rl_point = rl_end = rl_history_search_len; + rl_point = rl_end = _rl_history_search_len; rl_line_buffer[rl_end] = '\0'; rl_mark = 0; } #else - rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */ + rl_point = _rl_history_search_len; /* rl_maybe_unsave_line changes it */ rl_mark = rl_end; #endif return 1; @@ -585,16 +585,16 @@ 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. */ - history_set_pos (rl_history_search_pos); /* XXX */ + history_set_pos (_rl_history_search_pos); /* XXX */ /* decide where to put rl_point -- need to change this for pattern search */ - if (rl_history_search_flags & ANCHORED_SEARCH) - rl_point = rl_history_search_len; /* easy case */ + if (_rl_history_search_flags & ANCHORED_SEARCH) + rl_point = _rl_history_search_len; /* easy case */ else { #if 0 t = strstr (rl_line_buffer, history_search_string); /* XXX */ - rl_point = t ? (int)(t - rl_line_buffer) + rl_history_search_len : rl_end; + rl_point = t ? (int)(t - rl_line_buffer) + _rl_history_search_len : rl_end; #else rl_point = (newcol >= 0) ? newcol : rl_end; #endif @@ -609,17 +609,17 @@ rl_history_search_reinit (int flags) { int sind; - rl_history_search_pos = where_history (); - rl_history_search_len = rl_point; - rl_history_search_flags = flags; + _rl_history_search_pos = where_history (); + _rl_history_search_len = rl_point; + _rl_history_search_flags = flags; prev_line_found = (char *)NULL; if (rl_point) { /* Allocate enough space for anchored and non-anchored searches */ - if (rl_history_search_len >= history_string_size - 2) + if (_rl_history_search_len >= history_string_size - 2) { - history_string_size = rl_history_search_len + 2; + history_string_size = _rl_history_search_len + 2; history_search_string = (char *)xrealloc (history_search_string, history_string_size); } sind = 0; @@ -644,7 +644,7 @@ rl_history_search_forward (int count, int ignore) rl_last_func != rl_history_search_backward) rl_history_search_reinit (ANCHORED_SEARCH); - if (rl_history_search_len == 0) + if (_rl_history_search_len == 0) return (rl_get_next_history (count, ignore)); return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); } @@ -662,7 +662,7 @@ rl_history_search_backward (int count, int ignore) rl_last_func != rl_history_search_backward) rl_history_search_reinit (ANCHORED_SEARCH); - if (rl_history_search_len == 0) + if (_rl_history_search_len == 0) return (rl_get_previous_history (count, ignore)); return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); } @@ -681,7 +681,7 @@ rl_history_substr_search_forward (int count, int ignore) rl_last_func != rl_history_substr_search_backward) rl_history_search_reinit (NON_ANCHORED_SEARCH); - if (rl_history_search_len == 0) + if (_rl_history_search_len == 0) return (rl_get_next_history (count, ignore)); return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1)); } @@ -699,7 +699,7 @@ rl_history_substr_search_backward (int count, int ignore) rl_last_func != rl_history_substr_search_backward) rl_history_search_reinit (NON_ANCHORED_SEARCH); - if (rl_history_search_len == 0) + if (_rl_history_search_len == 0) return (rl_get_previous_history (count, ignore)); return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1)); } diff --git a/parse.y b/parse.y index a4798224..c61db457 100644 --- a/parse.y +++ b/parse.y @@ -3419,7 +3419,7 @@ read_token (command) goto tokword; /* Shell meta-characters. */ - if MBTEST(shellmeta (character) && ((parser_state & PST_DBLPAREN) == 0)) + if MBTEST(shellmeta (character)) { #if defined (ALIAS) /* Turn off alias tokenization iff this character sequence would @@ -4061,6 +4061,10 @@ parse_comsub (qc, open, close, lenp, flags) save_parser_state (&ps); pushed_string_list = (STRING_SAVER *)NULL; + + /* State flags we don't want to persist into command substitutions. */ + parser_state &= ~(PST_REGEXP|PST_EXTPAT|PST_CONDCMD|PST_CONDEXPR); + /* State flags we want to set for this run through the parser. */ parser_state |= PST_CMDSUBST|PST_EOFTOKEN|PST_NOEXPAND; shell_eof_token = close; diff --git a/parser.h b/parser.h index e3621d6c..59bf0fec 100644 --- a/parser.h +++ b/parser.h @@ -30,7 +30,7 @@ #define PST_ALEXPNEXT 0x000002 /* expand next word for aliases */ #define PST_ALLOWOPNBRC 0x000004 /* allow open brace for function def */ #define PST_NEEDCLOSBRC 0x000008 /* need close brace */ -#define PST_DBLPAREN 0x000010 /* double-paren parsing */ +#define PST_DBLPAREN 0x000010 /* double-paren parsing - unused */ #define PST_SUBSHELL 0x000020 /* ( ... ) subshell */ #define PST_CMDSUBST 0x000040 /* $( ... ) command substitution */ #define PST_CASESTMT 0x000080 /* parsing a case statement */ diff --git a/pathexp.c b/pathexp.c index 6e7ef283..cfa87e81 100644 --- a/pathexp.c +++ b/pathexp.c @@ -171,6 +171,7 @@ ere_char (c) return (0); } +/* This is only used to determine whether to backslash-quote a character. */ int glob_char_p (s) const char *s;