diff options
Diffstat (limited to 'search.c')
-rw-r--r-- | search.c | 173 |
1 files changed, 124 insertions, 49 deletions
@@ -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 |