changes to non-incremental searching to avoid pointer alias problems, undo issues

This commit is contained in:
Chet Ramey
2023-04-27 14:56:35 -04:00
parent ec02facd13
commit 7aae19bfe4
7 changed files with 256 additions and 99 deletions
+60
View File
@@ -6103,3 +6103,63 @@ bashline.c
- name_is_acceptable: allow FIGNORE suffixes to match the entire
pathname like tcsh does instead of requiring a non-empty prefix.
From Emanuele Torre <torreemanuele6@gmail.com>
4/23
----
lib/readline/misc.c
- _rl_unsave_line: new function, takes a HIST_ENTRY * as an argument,
generalized rl_maybe_unsave_line
- _rl_alloc_saved_line: allocate a new HIST_ENTRY *, populate it like
rl_saved_line_for_history
- _rl_free_saved_line: free a saved HIST_ENTRY *
- _rl_free_saved_history_line: call _rl_free_saved_line
- _rl_previous_history_internal: new function, internals of
rl_get_previous_history; change rl_get_previous_history to call it
lib/readline/history.h
- HIST_ENTRY_DEFINED: define sentinel if HIST_ENTRY struct defined
lib/readline/rlprivate.h
- _rl_alloc_saved_line,_rl_free_saved_line,_rl_unsave_line: new extern
function definitions
- _rl_free_saved_search_line: new extern definition
lib/readline/search.c
- _rl_saved_line_for_search: use private storage to save current line,
avoid clashes with rl_saved_line_for_history
- _rl_free_saved_search_line,_rl_unsave_saved_search_line: new functions
to manage _rl_saved_line_for_search
- noninc_dosearch,_rl_nsearch_abort: clean up _rl_saved_line_for_search
instead of rl_saved_line_for_history
- rl_history_search_internal: allocate private _rl_saved_line_for_search;
unsave or free it as appropriate
- _rl_history_search_reinit: free up any _rl_saved_line_for_search just
in case
lib/readline/vi_mode.c
- rl_vi_search: free _rl_saved_line_for_search, since that's what the
non-incremental search functions use now
- rl_domove_read_callback: if we read a numeric argument, then a motion
character, make sure the motion character is valid before returning
it and going on
From a report by minipython <599192367@qq.com>
4/27
----
lib/readline/display.c
- _rl_move_cursor_relative: when checking to see whether data is within
the invisible line, make sure to stay within the invisible line
line break boundaries
lib/readline/search.c
- dispose_saved_search_line: new function, either unsave the saved
search line (if we're not at the end of the history) or free it
(if we are). Needs to be immediately followed by call to
make_history_line_current, which resets rl_undo_list
- make_history_line_current: change strategy: rely on callers to
manage _rl_saved_line_for_search and rl_undo_list; just copy the
data from the passed history entry into the line buffer and reset
rl_undo_list
- noninc_dosearch,rl_history_search_internal: call dispose_saved_search_line
before calling make_history_line_current
+1 -1
View File
@@ -2831,7 +2831,7 @@ _rl_move_cursor_relative (int new, const char *data, const char *dataf)
(prompt_last_invisible) in the last line. IN_INVISLINE is the
offset of DATA in invisible_line */
in_invisline = 0;
if (data > invisible_line && data < invisible_line+inv_lbreaks[_rl_inv_botlin+1])
if (data > invisible_line && _rl_inv_botlin < inv_lbsize && data < invisible_line+inv_lbreaks[_rl_inv_botlin+1])
in_invisline = data - invisible_line;
/* Use NEW when comparing against the last invisible character in the
+5 -1
View File
@@ -1,6 +1,6 @@
/* history.h -- the names of functions that you can call in history. */
/* Copyright (C) 1989-2022 Free Software Foundation, Inc.
/* Copyright (C) 1989-2023 Free Software Foundation, Inc.
This file contains the GNU History Library (History), a set of
routines for managing the text of previously typed lines.
@@ -50,6 +50,10 @@ typedef struct _hist_entry {
histdata_t data;
} HIST_ENTRY;
#ifndef HIST_ENTRY_DEFINED
# define HIST_ENTRY_DEFINED
#endif
/* Size of the history-library-managed space in history entry HS. */
#define HISTENT_BYTES(hs) (strlen ((hs)->line) + strlen ((hs)->timestamp))
+95 -62
View File
@@ -1,6 +1,6 @@
/* misc.c -- miscellaneous bindable readline functions. */
/* Copyright (C) 1987-2022 Free Software Foundation, Inc.
/* Copyright (C) 1987-2023 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.
@@ -307,9 +307,7 @@ void
_rl_start_using_history (void)
{
using_history ();
if (_rl_saved_line_for_history)
_rl_free_saved_history_line ();
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
_rl_free_saved_history_line ();
_rl_history_search_pos = -99; /* some random invalid history position */
}
@@ -352,60 +350,71 @@ rl_maybe_replace_line (void)
return 0;
}
void
_rl_unsave_line (HIST_ENTRY *entry)
{
/* Can't call with `1' because rl_undo_list might point to an undo
list from a history entry, as in rl_replace_from_history() below. */
rl_replace_line (entry->line, 0);
rl_undo_list = (UNDO_LIST *)entry->data;
/* Doesn't free `data'. */
_rl_free_history_entry (entry);
rl_point = rl_end; /* rl_replace_line sets rl_end */
}
/* Restore the _rl_saved_line_for_history if there is one. */
int
rl_maybe_unsave_line (void)
{
if (_rl_saved_line_for_history)
{
/* Can't call with `1' because rl_undo_list might point to an undo
list from a history entry, as in rl_replace_from_history() below. */
rl_replace_line (_rl_saved_line_for_history->line, 0);
rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data;
/* Doesn't free `data'. */
_rl_free_history_entry (_rl_saved_line_for_history);
_rl_unsave_line (_rl_saved_line_for_history);
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
rl_point = rl_end; /* rl_replace_line sets rl_end */
}
else
rl_ding ();
return 0;
}
HIST_ENTRY *
_rl_alloc_saved_line (void)
{
HIST_ENTRY *ret;
ret = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
ret->line = savestring (rl_line_buffer);
ret->timestamp = (char *)NULL;
ret->data = (char *)rl_undo_list;
return ret;
}
/* Save the current line in _rl_saved_line_for_history. */
int
rl_maybe_save_line (void)
{
if (_rl_saved_line_for_history == 0)
{
_rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
_rl_saved_line_for_history->line = savestring (rl_line_buffer);
_rl_saved_line_for_history->timestamp = (char *)NULL;
_rl_saved_line_for_history->data = (char *)rl_undo_list;
}
_rl_saved_line_for_history = _rl_alloc_saved_line ();
return 0;
}
/* Just a wrapper, any self-respecting compiler will inline it. */
void
_rl_free_saved_line (HIST_ENTRY *entry)
{
_rl_free_history_entry (entry);
}
int
_rl_free_saved_history_line (void)
{
if (_rl_saved_line_for_history)
{
UNDO_LIST *sentinel;
_rl_free_saved_line (_rl_saved_line_for_history);
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
sentinel = (UNDO_LIST *)_rl_saved_line_for_history->data;
/* We should only free `data' if it's not the current rl_undo_list and
it's not the `data' member in a history entry somewhere. We have to
free it separately because only the callers know it's an undo list. */
if (sentinel && sentinel != rl_undo_list && _hs_search_history_data ((histdata_t *)sentinel) < 0)
_rl_free_undo_list (sentinel);
_rl_free_history_entry (_rl_saved_line_for_history);
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
}
return 0;
}
@@ -563,20 +572,11 @@ rl_end_of_history (int count, int key)
return 0;
}
/* Move down to the next history line. */
int
rl_get_next_history (int count, int key)
_rl_next_history_internal (int count)
{
HIST_ENTRY *temp;
if (count < 0)
return (rl_get_previous_history (-count, key));
if (count == 0)
return 0;
rl_maybe_replace_line ();
/* either not saved by rl_newline or at end of line, so set appropriately. */
if (_rl_history_saved_point == -1 && (rl_point || rl_end))
_rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
@@ -591,41 +591,48 @@ rl_get_next_history (int count, int key)
}
if (temp == 0)
rl_maybe_unsave_line ();
return 0;
else
{
rl_replace_from_history (temp, 0);
_rl_history_set_point ();
return 1;
}
}
/* Move down to the next history line. */
int
rl_get_next_history (int count, int key)
{
int r;
if (count < 0)
return (rl_get_previous_history (-count, key));
if (count == 0)
return 0;
rl_maybe_replace_line ();
r = _rl_next_history_internal (count);
if (r == 0)
rl_maybe_unsave_line ();
return 0;
}
/* Get the previous item out of our interactive history, making it the current
line. If there is no previous history, just ding. */
int
rl_get_previous_history (int count, int key)
_rl_previous_history_internal (int count)
{
HIST_ENTRY *old_temp, *temp;
int had_saved_line;
if (count < 0)
return (rl_get_next_history (-count, key));
if (count == 0 || history_list () == 0)
return 0;
temp = old_temp = (HIST_ENTRY *)NULL;
/* either not saved by rl_newline or at end of line, so set appropriately. */
if (_rl_history_saved_point == -1 && (rl_point || rl_end))
_rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
/* If we don't have a line saved, then save this one. */
had_saved_line = _rl_saved_line_for_history != 0;
rl_maybe_save_line ();
/* If the current line has changed, save the changes. */
rl_maybe_replace_line ();
temp = old_temp = (HIST_ENTRY *)NULL;
while (count)
{
temp = previous_history ();
@@ -643,15 +650,41 @@ rl_get_previous_history (int count, int key)
if (temp == 0)
{
if (had_saved_line == 0)
_rl_free_saved_history_line ();
rl_ding ();
return 0;
}
else
{
rl_replace_from_history (temp, 0);
_rl_history_set_point ();
return 1;
}
}
/* Get the previous item out of our interactive history, making it the current
line. If there is no previous history, just ding. */
int
rl_get_previous_history (int count, int key)
{
int had_saved_line, r;
if (count < 0)
return (rl_get_next_history (-count, key));
if (count == 0 || history_list () == 0)
return 0;
/* If we don't have a line saved, then save this one. */
had_saved_line = _rl_saved_line_for_history != 0;
rl_maybe_save_line ();
/* If the current line has changed, save the changes. */
rl_maybe_replace_line ();
r = _rl_previous_history_internal (count);
if (r == 0 && had_saved_line == 0) /* failed to find previous history */
_rl_free_saved_history_line ();
return 0;
}
+8
View File
@@ -369,7 +369,13 @@ extern int _rl_arg_callback (_rl_arg_cxt);
extern void _rl_reset_argument (void);
extern void _rl_start_using_history (void);
#if defined (HIST_ENTRY_DEFINED)
extern HIST_ENTRY *_rl_alloc_saved_line (void);
extern void _rl_free_saved_line (HIST_ENTRY *);
extern void _rl_unsave_line (HIST_ENTRY *);
#endif
extern int _rl_free_saved_history_line (void);
extern void _rl_set_insert_mode (int, int);
extern void _rl_revert_previous_lines (void);
@@ -406,6 +412,8 @@ extern int _rl_restore_tty_signals (void);
extern int _rl_nsearch_callback (_rl_search_cxt *);
extern int _rl_nsearch_cleanup (_rl_search_cxt *, int);
extern void _rl_free_saved_search_line (void);
/* signals.c */
extern void _rl_signal_handler (int);
+77 -33
View File
@@ -1,6 +1,6 @@
/* search.c - code for non-incremental searching in emacs and vi modes. */
/* Copyright (C) 1992-2022 Free Software Foundation, Inc.
/* Copyright (C) 1992-2023 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.
@@ -55,6 +55,8 @@
_rl_search_cxt *_rl_nscxt = 0;
static HIST_ENTRY *_rl_saved_line_for_search;
static char *noninc_search_string = (char *) NULL;
static int noninc_history_pos;
@@ -78,23 +80,57 @@ static _rl_search_cxt *_rl_nsearch_init (int, int);
static void _rl_nsearch_abort (_rl_search_cxt *);
static int _rl_nsearch_dispatch (_rl_search_cxt *, int);
void
_rl_free_saved_search_line (void)
{
if (_rl_saved_line_for_search)
_rl_free_saved_line (_rl_saved_line_for_search);
_rl_saved_line_for_search = (HIST_ENTRY *)NULL;
}
static inline void
_rl_unsave_saved_search_line (void)
{
if (_rl_saved_line_for_search)
_rl_unsave_line (_rl_saved_line_for_search);
_rl_saved_line_for_search = (HIST_ENTRY *)NULL;
}
/* We're going to replace the undo list with the one created by inserting
the matching line we found, so we want to free rl_undo_list if it's not
from a history entry. We assume the undo list does not come from a
history entry if we are at the end of the history, entering a new line.
The call to rl_maybe_replace_line() has already ensured that any undo
list pointing to a history entry has already been saved back to the
history and set rl_undo_list to NULL. */
static void
dispose_saved_search_line (void)
{
UNDO_LIST *xlist;
if (_hs_at_end_of_history () == 0)
_rl_unsave_saved_search_line ();
else if (_rl_saved_line_for_search)
{
xlist = _rl_saved_line_for_search ? (UNDO_LIST *)_rl_saved_line_for_search->data : 0;
if (xlist)
_rl_free_undo_list (xlist);
_rl_saved_line_for_search->data = 0;
_rl_free_saved_search_line ();
}
}
/* Make the data from the history entry ENTRY be the contents of the
current line. This doesn't do anything with rl_point; the caller
must set it. */
static void
make_history_line_current (HIST_ENTRY *entry)
{
UNDO_LIST *xlist;
xlist = _rl_saved_line_for_history ? (UNDO_LIST *)_rl_saved_line_for_history->data : 0;
/* At this point, rl_undo_list points to a private search string list. */
if (rl_undo_list && rl_undo_list != (UNDO_LIST *)entry->data && rl_undo_list != xlist &&
_hs_search_history_data ((histdata_t *)rl_undo_list) < 0)
rl_free_undo_list ();
rl_undo_list = 0; /* XXX */
/* 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_undo_list = 0; /* XXX */
_rl_replace_text (entry->line, 0, rl_end);
_rl_fix_point (1);
#if defined (VI_MODE)
@@ -105,15 +141,6 @@ make_history_line_current (HIST_ENTRY *entry)
current editing buffer. */
rl_free_undo_list ();
#endif
/* This will need to free the saved undo list associated with the original
(pre-search) line buffer.
XXX - look at _rl_free_saved_history_line and consider calling it if
rl_undo_list != xlist (or calling rl_free_undo list directly on
_rl_saved_line_for_history->data) */
if (_rl_saved_line_for_history)
_rl_free_history_entry (_rl_saved_line_for_history);
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
}
/* Search the history list for STRING starting at absolute history position
@@ -185,7 +212,7 @@ noninc_dosearch (char *string, int dir, int flags)
if (pos == -1)
{
/* Search failed, current history position unchanged. */
rl_maybe_unsave_line ();
_rl_unsave_saved_search_line ();
rl_clear_message ();
rl_point = 0;
rl_ding ();
@@ -194,6 +221,10 @@ noninc_dosearch (char *string, int dir, int flags)
noninc_history_pos = pos;
/* We're committed to making the line we found the current contents of
rl_line_buffer. We can dispose of _rl_saved_line_for_search. */
dispose_saved_search_line ();
oldpos = where_history ();
history_set_pos (noninc_history_pos);
entry = current_history (); /* will never be NULL after successful search */
@@ -240,7 +271,10 @@ _rl_nsearch_init (int dir, int pchar)
cxt->direction = dir;
cxt->history_pos = cxt->save_line;
rl_maybe_save_line ();
/* If the current line has changed, put it back into the history if necessary. */
rl_maybe_replace_line ();
_rl_saved_line_for_search = _rl_alloc_saved_line ();
/* Clear the undo list, since reading the search string should create its
own undo list, and the whole list will end up being freed when we
@@ -276,7 +310,7 @@ _rl_nsearch_cleanup (_rl_search_cxt *cxt, int r)
static void
_rl_nsearch_abort (_rl_search_cxt *cxt)
{
rl_maybe_unsave_line ();
_rl_unsave_saved_search_line ();
rl_point = cxt->save_point;
rl_mark = cxt->save_mark;
rl_restore_prompt ();
@@ -380,6 +414,7 @@ _rl_nsearch_dosearch (_rl_search_cxt *cxt)
{
if (noninc_search_string == 0)
{
_rl_free_saved_search_line ();
rl_ding ();
rl_restore_prompt ();
RL_UNSETSTATE (RL_STATE_NSEARCH);
@@ -393,12 +428,17 @@ _rl_nsearch_dosearch (_rl_search_cxt *cxt)
FREE (noninc_search_string);
noninc_search_string = savestring (rl_line_buffer);
/* If we don't want the subsequent undo list generated by the search
/* We don't want the subsequent undo list generated by the search
matching a history line to include the contents of the search string,
we need to clear rl_line_buffer here. For now, we just clear the
undo list generated by reading the search string. (If the search
fails, the old undo list will be restored by rl_maybe_unsave_line.) */
so we need to clear rl_line_buffer here. If we don't want that,
change the #if 1 to an #if 0 below. We clear the undo list
generated by reading the search string. (If the search fails, the
old undo list will be restored by _rl_unsave_line.) */
rl_free_undo_list ();
#if 1
rl_line_buffer[rl_point = rl_end = 0] = '\0';
#endif
}
rl_restore_prompt ();
@@ -534,11 +574,12 @@ rl_history_search_internal (int count, int dir)
{
HIST_ENTRY *temp;
int ret, oldpos, newcol;
int had_saved_line;
char *t;
had_saved_line = _rl_saved_line_for_history != 0;
rl_maybe_save_line ();
/* If the current line has changed, put it back into the history if necessary. */
rl_maybe_replace_line ();
_rl_saved_line_for_search = _rl_alloc_saved_line ();
temp = (HIST_ENTRY *)NULL;
/* Search COUNT times through the history for a line matching
@@ -570,8 +611,7 @@ rl_history_search_internal (int count, int dir)
/* If we didn't find anything at all, return. */
if (temp == 0)
{
/* XXX - check had_saved_line here? */
rl_maybe_unsave_line ();
_rl_unsave_saved_search_line ();
rl_ding ();
/* If you don't want the saved history line (last match) to show up
in the line buffer after the search fails, change the #if 0 to
@@ -584,12 +624,16 @@ rl_history_search_internal (int count, int dir)
rl_mark = 0;
}
#else
rl_point = _rl_history_search_len; /* rl_maybe_unsave_line changes it */
rl_point = _rl_history_search_len; /* _rl_unsave_line changes it */
rl_mark = rl_end;
#endif
return 1;
}
/* We're committed to making the line we found the current contents of
rl_line_buffer. We can dispose of _rl_saved_line_for_search. */
dispose_saved_search_line ();
/* Copy the line we found into the current line buffer. */
make_history_line_current (temp);
@@ -634,7 +678,7 @@ rl_history_search_reinit (int flags)
strncpy (history_search_string + sind, rl_line_buffer, rl_point);
history_search_string[rl_point + sind] = '\0';
}
_rl_free_saved_history_line (); /* XXX rl_undo_list? */
_rl_free_saved_search_line ();
}
/* Search forward in the history for the string of characters
+10 -2
View File
@@ -367,12 +367,12 @@ rl_vi_search (int count, int key)
switch (key)
{
case '?':
_rl_free_saved_history_line ();
_rl_free_saved_search_line (); /* just in case */
rl_noninc_forward_search (count, key);
break;
case '/':
_rl_free_saved_history_line ();
_rl_free_saved_search_line ();
rl_noninc_reverse_search (count, key);
break;
@@ -1340,6 +1340,13 @@ rl_domove_read_callback (_rl_vimotion_cxt *m)
m->motion = 0;
return -1;
}
else if (member (c, vi_motion) == 0)
{
m->motion = 0;
RL_UNSETSTATE (RL_STATE_VIMOTION);
RL_UNSETSTATE (RL_STATE_NUMERICARG);
return (1);
}
m->motion = c;
return (rl_domove_motion_callback (m));
}
@@ -1364,6 +1371,7 @@ _rl_vi_domove_callback (_rl_vimotion_cxt *m)
int c, r;
m->motion = c = rl_vi_domove_getchar (m);
if (c < 0)
return 1; /* EOF */
r = rl_domove_read_callback (m);