summaryrefslogtreecommitdiff
path: root/search.c
diff options
context:
space:
mode:
Diffstat (limited to 'search.c')
-rw-r--r--search.c173
1 files changed, 124 insertions, 49 deletions
diff --git a/search.c b/search.c
index eea2301..a22c43d 100644
--- a/search.c
+++ b/search.c
@@ -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-2024 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;
@@ -65,7 +67,7 @@ static int _rl_history_search_len;
static int _rl_history_search_flags;
static char *history_search_string;
-static int history_string_size;
+static size_t history_string_size;
static void make_history_line_current (HIST_ENTRY *);
static int noninc_search_from_pos (char *, int, int, int, int *);
@@ -78,21 +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)
- rl_free_undo_list ();
-
/* 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)
@@ -103,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
@@ -135,21 +164,23 @@ noninc_search_from_pos (char *string, int pos, int dir, int flags, int *ncp)
RL_SETSTATE(RL_STATE_SEARCH);
/* These functions return the match offset in the line; history_offset gives
the matching line in the history list */
- if (flags & SF_PATTERN)
+
+ sflags = 0; /* Non-anchored search */
+ s = string;
+ if (*s == '^')
{
- s = string;
- sflags = 0; /* Non-anchored search */
- if (*s == '^')
- {
- sflags |= ANCHORED_SEARCH;
- s++;
- }
- ret = _hs_history_patsearch (s, dir, sflags);
+ sflags |= ANCHORED_SEARCH;
+ s++;
}
- else if (*string == '^')
- ret = history_search_prefix (string + 1, dir);
+
+ if (flags & SF_PATTERN)
+ ret = _hs_history_patsearch (s, dir, sflags);
else
- ret = history_search (string, dir);
+ {
+ if (_rl_search_case_fold)
+ sflags |= CASEFOLD_SEARCH;
+ ret = _hs_history_search (s, dir, sflags);
+ }
RL_UNSETSTATE(RL_STATE_SEARCH);
if (ncp)
@@ -181,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 ();
@@ -190,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 */
@@ -201,7 +236,7 @@ noninc_dosearch (char *string, int dir, int flags)
make_history_line_current (entry);
- if (_rl_enable_active_region && ((flags & SF_PATTERN) == 0) && ind > 0 && ind < rl_end)
+ if (_rl_enable_active_region && ((flags & SF_PATTERN) == 0) && ind >= 0 && ind < rl_end)
{
rl_point = ind;
rl_mark = ind + strlen (string);
@@ -236,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
@@ -248,6 +286,7 @@ _rl_nsearch_init (int dir, int pchar)
rl_end = rl_point = 0;
p = _rl_make_prompt_for_search (pchar ? pchar : ':');
+ cxt->sflags |= SF_FREEPMT;
rl_message ("%s", p);
xfree (p);
@@ -272,16 +311,27 @@ _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 ();
+ if (cxt->sflags & SF_FREEPMT)
+ rl_restore_prompt (); /* _rl_make_prompt_for_search saved it */
+ cxt->sflags &= ~SF_FREEPMT;
rl_clear_message ();
_rl_fix_point (1);
RL_UNSETSTATE (RL_STATE_NSEARCH);
}
+int
+_rl_nsearch_sigcleanup (_rl_search_cxt *cxt, int r)
+{
+ if (cxt->sflags & SF_FREEPMT)
+ rl_restore_prompt (); /* _rl_make_prompt_for_search saved it */
+ cxt->sflags &= ~SF_FREEPMT;
+ return (_rl_nsearch_cleanup (cxt, r));
+}
+
/* Process just-read character C according to search context CXT. Return -1
if the caller should abort the search, 0 if we should break out of the
loop, and 1 if we should continue to read characters. */
@@ -303,6 +353,17 @@ _rl_nsearch_dispatch (_rl_search_cxt *cxt, int c)
rl_unix_line_discard (1, c);
break;
+ case CTRL('Q'):
+ case CTRL('V'):
+ n = rl_quoted_insert (1, c);
+ if (n < 0)
+ {
+ _rl_nsearch_abort (cxt);
+ return -1;
+ }
+ cxt->lastc = (rl_point > 0) ? rl_line_buffer[rl_point - 1] : rl_line_buffer[0];
+ break;
+
case RETURN:
case NEWLINE:
return 0;
@@ -376,8 +437,11 @@ _rl_nsearch_dosearch (_rl_search_cxt *cxt)
{
if (noninc_search_string == 0)
{
+ _rl_free_saved_search_line ();
rl_ding ();
- rl_restore_prompt ();
+ if (cxt->sflags & SF_FREEPMT)
+ rl_restore_prompt ();
+ cxt->sflags &= ~SF_FREEPMT;
RL_UNSETSTATE (RL_STATE_NSEARCH);
return -1;
}
@@ -389,15 +453,22 @@ _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 ();
+ if (cxt->sflags & SF_FREEPMT)
+ rl_restore_prompt ();
+ cxt->sflags &= ~SF_FREEPMT;
return (noninc_dosearch (noninc_search_string, cxt->direction, cxt->sflags&SF_PATTERN));
}
@@ -530,11 +601,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
@@ -566,8 +638,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
@@ -580,12 +651,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);
@@ -619,7 +694,7 @@ rl_history_search_reinit (int flags)
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 + 2 >= history_string_size)
{
history_string_size = _rl_history_search_len + 2;
history_search_string = (char *)xrealloc (history_search_string, history_string_size);
@@ -630,7 +705,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