1 /* search.c - code for non-incremental searching in emacs and vi modes. */
2 
3 /* Copyright (C) 1992-2020 Free Software Foundation, Inc.
4 
5    This file is part of the GNU Readline Library (Readline), a library
6    for reading lines of text with interactive input and history editing.
7 
8    Readline is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation, either version 3 of the License, or
11    (at your option) any later version.
12 
13    Readline is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with Readline.  If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #define READLINE_LIBRARY
23 
24 #if defined (HAVE_CONFIG_H)
25 #  include <config.h>
26 #endif
27 
28 #include <sys/types.h>
29 #include <stdio.h>
30 
31 #if defined (HAVE_UNISTD_H)
32 #  include <unistd.h>
33 #endif
34 
35 #if defined (HAVE_STDLIB_H)
36 #  include <stdlib.h>
37 #else
38 #  include "ansi_stdlib.h"
39 #endif
40 
41 #include "rldefs.h"
42 #include "rlmbutil.h"
43 
44 #include "readline.h"
45 #include "history.h"
46 #include "histlib.h"
47 
48 #include "rlprivate.h"
49 #include "xmalloc.h"
50 
51 #ifdef abs
52 #  undef abs
53 #endif
54 #define abs(x)		(((x) >= 0) ? (x) : -(x))
55 
56 _rl_search_cxt *_rl_nscxt = 0;
57 
58 extern HIST_ENTRY *_rl_saved_line_for_history;
59 
60 /* Functions imported from the rest of the library. */
61 extern void _rl_free_history_entry PARAMS((HIST_ENTRY *));
62 
63 static char *noninc_search_string = (char *) NULL;
64 static int noninc_history_pos;
65 
66 static char *prev_line_found = (char *) NULL;
67 
68 static int rl_history_search_len;
69 static int rl_history_search_pos;
70 static int rl_history_search_flags;
71 
72 static char *history_search_string;
73 static int history_string_size;
74 
75 static void make_history_line_current PARAMS((HIST_ENTRY *));
76 static int noninc_search_from_pos PARAMS((char *, int, int, int, int *));
77 static int noninc_dosearch PARAMS((char *, int, int));
78 static int noninc_search PARAMS((int, int));
79 static int rl_history_search_internal PARAMS((int, int));
80 static void rl_history_search_reinit PARAMS((int));
81 
82 static _rl_search_cxt *_rl_nsearch_init PARAMS((int, int));
83 static void _rl_nsearch_abort PARAMS((_rl_search_cxt *));
84 static int _rl_nsearch_dispatch PARAMS((_rl_search_cxt *, int));
85 
86 /* Make the data from the history entry ENTRY be the contents of the
87    current line.  This doesn't do anything with rl_point; the caller
88    must set it. */
89 static void
make_history_line_current(HIST_ENTRY * entry)90 make_history_line_current (HIST_ENTRY *entry)
91 {
92   _rl_replace_text (entry->line, 0, rl_end);
93   _rl_fix_point (1);
94 #if defined (VI_MODE)
95   if (rl_editing_mode == vi_mode)
96     /* POSIX.2 says that the `U' command doesn't affect the copy of any
97        command lines to the edit line.  We're going to implement that by
98        making the undo list start after the matching line is copied to the
99        current editing buffer. */
100     rl_free_undo_list ();
101 #endif
102 
103   if (_rl_saved_line_for_history)
104     _rl_free_history_entry (_rl_saved_line_for_history);
105   _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
106 }
107 
108 /* Search the history list for STRING starting at absolute history position
109    POS.  If STRING begins with `^', the search must match STRING at the
110    beginning of a history line, otherwise a full substring match is performed
111    for STRING.  DIR < 0 means to search backwards through the history list,
112    DIR >= 0 means to search forward. */
113 static int
noninc_search_from_pos(char * string,int pos,int dir,int flags,int * ncp)114 noninc_search_from_pos (char *string, int pos, int dir, int flags, int *ncp)
115 {
116   int ret, old, sflags;
117   char *s;
118 
119   if (pos < 0)
120     return -1;
121 
122   old = where_history ();
123   if (history_set_pos (pos) == 0)
124     return -1;
125 
126   RL_SETSTATE(RL_STATE_SEARCH);
127   /* These functions return the match offset in the line; history_offset gives
128      the matching line in the history list */
129   if (flags & SF_PATTERN)
130     {
131       s = string;
132       sflags = 0;		/* Non-anchored search */
133       if (*s == '^')
134 	{
135 	  sflags |= ANCHORED_SEARCH;
136 	  s++;
137 	}
138       ret = _hs_history_patsearch (s, dir, sflags);
139     }
140   else if (*string == '^')
141     ret = history_search_prefix (string + 1, dir);
142   else
143     ret = history_search (string, dir);
144   RL_UNSETSTATE(RL_STATE_SEARCH);
145 
146   if (ncp)
147     *ncp = ret;		/* caller will catch -1 to indicate no-op */
148 
149   if (ret != -1)
150     ret = where_history ();
151 
152   history_set_pos (old);
153   return (ret);
154 }
155 
156 /* Search for a line in the history containing STRING.  If DIR is < 0, the
157    search is backwards through previous entries, else through subsequent
158    entries.  Returns 1 if the search was successful, 0 otherwise. */
159 static int
noninc_dosearch(char * string,int dir,int flags)160 noninc_dosearch (char *string, int dir, int flags)
161 {
162   int oldpos, pos, ind;
163   HIST_ENTRY *entry;
164 
165   if (string == 0 || *string == '\0' || noninc_history_pos < 0)
166     {
167       rl_ding ();
168       return 0;
169     }
170 
171   pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir, flags, &ind);
172   if (pos == -1)
173     {
174       /* Search failed, current history position unchanged. */
175       rl_maybe_unsave_line ();
176       rl_clear_message ();
177       rl_point = 0;
178       rl_ding ();
179       return 0;
180     }
181 
182   noninc_history_pos = pos;
183 
184   oldpos = where_history ();
185   history_set_pos (noninc_history_pos);
186   entry = current_history ();		/* will never be NULL after successful search */
187 
188 #if defined (VI_MODE)
189   if (rl_editing_mode != vi_mode)
190 #endif
191     history_set_pos (oldpos);
192 
193   make_history_line_current (entry);
194 
195   if (_rl_enable_active_region && ((flags & SF_PATTERN) == 0) && ind > 0 && ind < rl_end)
196     {
197       rl_point = ind;
198       rl_mark = ind + strlen (string);
199       if (rl_mark > rl_end)
200 	rl_mark = rl_end;	/* can't happen? */
201       rl_activate_mark ();
202     }
203   else
204     {
205       rl_point = 0;
206       rl_mark = rl_end;
207     }
208 
209   rl_clear_message ();
210   return 1;
211 }
212 
213 static _rl_search_cxt *
_rl_nsearch_init(int dir,int pchar)214 _rl_nsearch_init (int dir, int pchar)
215 {
216   _rl_search_cxt *cxt;
217   char *p;
218 
219   cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0);
220   if (dir < 0)
221     cxt->sflags |= SF_REVERSE;		/* not strictly needed */
222 #if defined (VI_MODE)
223   if (VI_COMMAND_MODE() && (pchar == '?' || pchar == '/'))
224     cxt->sflags |= SF_PATTERN;
225 #endif
226 
227   cxt->direction = dir;
228   cxt->history_pos = cxt->save_line;
229 
230   rl_maybe_save_line ();
231 
232   /* Clear the undo list, since reading the search string should create its
233      own undo list, and the whole list will end up being freed when we
234      finish reading the search string. */
235   rl_undo_list = 0;
236 
237   /* Use the line buffer to read the search string. */
238   rl_line_buffer[0] = 0;
239   rl_end = rl_point = 0;
240 
241   p = _rl_make_prompt_for_search (pchar ? pchar : ':');
242   rl_message ("%s", p);
243   xfree (p);
244 
245   RL_SETSTATE(RL_STATE_NSEARCH);
246 
247   _rl_nscxt = cxt;
248 
249   return cxt;
250 }
251 
252 int
_rl_nsearch_cleanup(_rl_search_cxt * cxt,int r)253 _rl_nsearch_cleanup (_rl_search_cxt *cxt, int r)
254 {
255   _rl_scxt_dispose (cxt, 0);
256   _rl_nscxt = 0;
257 
258   RL_UNSETSTATE(RL_STATE_NSEARCH);
259 
260   return (r != 1);
261 }
262 
263 static void
_rl_nsearch_abort(_rl_search_cxt * cxt)264 _rl_nsearch_abort (_rl_search_cxt *cxt)
265 {
266   rl_maybe_unsave_line ();
267   rl_clear_message ();
268   rl_point = cxt->save_point;
269   rl_mark = cxt->save_mark;
270   _rl_fix_point (1);
271   rl_restore_prompt ();
272 
273   RL_UNSETSTATE (RL_STATE_NSEARCH);
274 }
275 
276 /* Process just-read character C according to search context CXT.  Return -1
277    if the caller should abort the search, 0 if we should break out of the
278    loop, and 1 if we should continue to read characters. */
279 static int
_rl_nsearch_dispatch(_rl_search_cxt * cxt,int c)280 _rl_nsearch_dispatch (_rl_search_cxt *cxt, int c)
281 {
282   int n;
283 
284   if (c < 0)
285     c = CTRL ('C');
286 
287   switch (c)
288     {
289     case CTRL('W'):
290       rl_unix_word_rubout (1, c);
291       break;
292 
293     case CTRL('U'):
294       rl_unix_line_discard (1, c);
295       break;
296 
297     case RETURN:
298     case NEWLINE:
299       return 0;
300 
301     case CTRL('H'):
302     case RUBOUT:
303       if (rl_point == 0)
304 	{
305 	  _rl_nsearch_abort (cxt);
306 	  return -1;
307 	}
308       _rl_rubout_char (1, c);
309       break;
310 
311     case CTRL('C'):
312     case CTRL('G'):
313       rl_ding ();
314       _rl_nsearch_abort (cxt);
315       return -1;
316 
317     case ESC:
318       /* XXX - experimental code to allow users to bracketed-paste into the
319 	 search string. Similar code is in isearch.c:_rl_isearch_dispatch().
320 	 The difference here is that the bracketed paste sometimes doesn't
321 	 paste everything, so checking for the prefix and the suffix in the
322 	 input queue doesn't work well. We just have to check to see if the
323 	 number of chars in the input queue is enough for the bracketed paste
324 	 prefix and hope for the best. */
325       if (_rl_enable_bracketed_paste && ((n = _rl_nchars_available ()) >= (BRACK_PASTE_SLEN-1)))
326 	{
327 	  if (_rl_read_bracketed_paste_prefix (c) == 1)
328 	    rl_bracketed_paste_begin (1, c);
329 	  else
330 	    {
331 	      c = rl_read_key ();	/* get the ESC that got pushed back */
332 	      _rl_insert_char (1, c);
333 	    }
334         }
335       else
336         _rl_insert_char (1, c);
337       break;
338 
339     default:
340 #if defined (HANDLE_MULTIBYTE)
341       if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
342 	rl_insert_text (cxt->mb);
343       else
344 #endif
345 	_rl_insert_char (1, c);
346       break;
347     }
348 
349   (*rl_redisplay_function) ();
350   rl_deactivate_mark ();
351   return 1;
352 }
353 
354 /* Perform one search according to CXT, using NONINC_SEARCH_STRING.  Return
355    -1 if the search should be aborted, any other value means to clean up
356    using _rl_nsearch_cleanup ().  Returns 1 if the search was successful,
357    0 otherwise. */
358 static int
_rl_nsearch_dosearch(_rl_search_cxt * cxt)359 _rl_nsearch_dosearch (_rl_search_cxt *cxt)
360 {
361   rl_mark = cxt->save_mark;
362 
363   /* If rl_point == 0, we want to re-use the previous search string and
364      start from the saved history position.  If there's no previous search
365      string, punt. */
366   if (rl_point == 0)
367     {
368       if (noninc_search_string == 0)
369 	{
370 	  rl_ding ();
371 	  rl_restore_prompt ();
372 	  RL_UNSETSTATE (RL_STATE_NSEARCH);
373 	  return -1;
374 	}
375     }
376   else
377     {
378       /* We want to start the search from the current history position. */
379       noninc_history_pos = cxt->save_line;
380       FREE (noninc_search_string);
381       noninc_search_string = savestring (rl_line_buffer);
382 
383       /* If we don't want the subsequent undo list generated by the search
384 	 matching a history line to include the contents of the search string,
385 	 we need to clear rl_line_buffer here.  For now, we just clear the
386 	 undo list generated by reading the search string.  (If the search
387 	 fails, the old undo list will be restored by rl_maybe_unsave_line.) */
388       rl_free_undo_list ();
389     }
390 
391   rl_restore_prompt ();
392   return (noninc_dosearch (noninc_search_string, cxt->direction, cxt->sflags&SF_PATTERN));
393 }
394 
395 /* Search non-interactively through the history list.  DIR < 0 means to
396    search backwards through the history of previous commands; otherwise
397    the search is for commands subsequent to the current position in the
398    history list.  PCHAR is the character to use for prompting when reading
399    the search string; if not specified (0), it defaults to `:'. */
400 static int
noninc_search(int dir,int pchar)401 noninc_search (int dir, int pchar)
402 {
403   _rl_search_cxt *cxt;
404   int c, r;
405 
406   cxt = _rl_nsearch_init (dir, pchar);
407 
408   if (RL_ISSTATE (RL_STATE_CALLBACK))
409     return (0);
410 
411   /* Read the search string. */
412   r = 0;
413   while (1)
414     {
415       c = _rl_search_getchar (cxt);
416 
417       if (c < 0)
418 	{
419 	  _rl_nsearch_abort (cxt);
420 	  return 1;
421 	}
422 
423       if (c == 0)
424 	break;
425 
426       r = _rl_nsearch_dispatch (cxt, c);
427       if (r < 0)
428         return 1;
429       else if (r == 0)
430 	break;
431     }
432 
433   r = _rl_nsearch_dosearch (cxt);
434   return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
435 }
436 
437 /* Search forward through the history list for a string.  If the vi-mode
438    code calls this, KEY will be `?'. */
439 int
rl_noninc_forward_search(int count,int key)440 rl_noninc_forward_search (int count, int key)
441 {
442   return noninc_search (1, (key == '?') ? '?' : 0);
443 }
444 
445 /* Reverse search the history list for a string.  If the vi-mode code
446    calls this, KEY will be `/'. */
447 int
rl_noninc_reverse_search(int count,int key)448 rl_noninc_reverse_search (int count, int key)
449 {
450   return noninc_search (-1, (key == '/') ? '/' : 0);
451 }
452 
453 /* Search forward through the history list for the last string searched
454    for.  If there is no saved search string, abort.  If the vi-mode code
455    calls this, KEY will be `N'. */
456 int
rl_noninc_forward_search_again(int count,int key)457 rl_noninc_forward_search_again (int count, int key)
458 {
459   int r;
460 
461   if (!noninc_search_string)
462     {
463       rl_ding ();
464       return (1);
465     }
466 #if defined (VI_MODE)
467   if (VI_COMMAND_MODE() && key == 'N')
468     r = noninc_dosearch (noninc_search_string, 1, SF_PATTERN);
469   else
470 #endif
471     r = noninc_dosearch (noninc_search_string, 1, 0);
472   return (r != 1);
473 }
474 
475 /* Reverse search in the history list for the last string searched
476    for.  If there is no saved search string, abort.  If the vi-mode code
477    calls this, KEY will be `n'. */
478 int
rl_noninc_reverse_search_again(int count,int key)479 rl_noninc_reverse_search_again (int count, int key)
480 {
481   int r;
482 
483   if (!noninc_search_string)
484     {
485       rl_ding ();
486       return (1);
487     }
488 #if defined (VI_MODE)
489   if (VI_COMMAND_MODE() && key == 'n')
490     r = noninc_dosearch (noninc_search_string, -1, SF_PATTERN);
491   else
492 #endif
493     r = noninc_dosearch (noninc_search_string, -1, 0);
494   return (r != 1);
495 }
496 
497 #if defined (READLINE_CALLBACKS)
498 int
_rl_nsearch_callback(_rl_search_cxt * cxt)499 _rl_nsearch_callback (_rl_search_cxt *cxt)
500 {
501   int c, r;
502 
503   c = _rl_search_getchar (cxt);
504   if (c <= 0)
505     {
506       if (c < 0)
507         _rl_nsearch_abort (cxt);
508       return 1;
509     }
510   r = _rl_nsearch_dispatch (cxt, c);
511   if (r != 0)
512     return 1;
513 
514   r = _rl_nsearch_dosearch (cxt);
515   return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
516 }
517 #endif
518 
519 static int
rl_history_search_internal(int count,int dir)520 rl_history_search_internal (int count, int dir)
521 {
522   HIST_ENTRY *temp;
523   int ret, oldpos, newcol;
524   char *t;
525 
526   rl_maybe_save_line ();
527   temp = (HIST_ENTRY *)NULL;
528 
529   /* Search COUNT times through the history for a line matching
530      history_search_string.  If history_search_string[0] == '^', the
531      line must match from the start; otherwise any substring can match.
532      When this loop finishes, TEMP, if non-null, is the history line to
533      copy into the line buffer. */
534   while (count)
535     {
536       RL_CHECK_SIGNALS ();
537       ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir, 0, &newcol);
538       if (ret == -1)
539 	break;
540 
541       /* Get the history entry we found. */
542       rl_history_search_pos = ret;
543       oldpos = where_history ();
544       history_set_pos (rl_history_search_pos);
545       temp = current_history ();	/* will never be NULL after successful search */
546       history_set_pos (oldpos);
547 
548       /* Don't find multiple instances of the same line. */
549       if (prev_line_found && STREQ (prev_line_found, temp->line))
550         continue;
551       prev_line_found = temp->line;
552       count--;
553     }
554 
555   /* If we didn't find anything at all, return. */
556   if (temp == 0)
557     {
558       rl_maybe_unsave_line ();
559       rl_ding ();
560       /* If you don't want the saved history line (last match) to show up
561          in the line buffer after the search fails, change the #if 0 to
562          #if 1 */
563 #if 0
564       if (rl_point > rl_history_search_len)
565         {
566           rl_point = rl_end = rl_history_search_len;
567           rl_line_buffer[rl_end] = '\0';
568           rl_mark = 0;
569         }
570 #else
571       rl_point = rl_history_search_len;	/* rl_maybe_unsave_line changes it */
572       rl_mark = rl_end;
573 #endif
574       return 1;
575     }
576 
577   /* Copy the line we found into the current line buffer. */
578   make_history_line_current (temp);
579 
580   /* decide where to put rl_point -- need to change this for pattern search */
581   if (rl_history_search_flags & ANCHORED_SEARCH)
582     rl_point = rl_history_search_len;	/* easy case */
583   else
584     {
585 #if 0
586       t = strstr (rl_line_buffer, history_search_string);	/* XXX */
587       rl_point = t ? (int)(t - rl_line_buffer) + rl_history_search_len : rl_end;
588 #else
589       rl_point = (newcol >= 0) ? newcol : rl_end;
590 #endif
591     }
592   rl_mark = rl_end;
593 
594   return 0;
595 }
596 
597 static void
rl_history_search_reinit(int flags)598 rl_history_search_reinit (int flags)
599 {
600   int sind;
601 
602   rl_history_search_pos = where_history ();
603   rl_history_search_len = rl_point;
604   rl_history_search_flags = flags;
605 
606   prev_line_found = (char *)NULL;
607   if (rl_point)
608     {
609       /* Allocate enough space for anchored and non-anchored searches */
610       if (rl_history_search_len >= history_string_size - 2)
611 	{
612 	  history_string_size = rl_history_search_len + 2;
613 	  history_search_string = (char *)xrealloc (history_search_string, history_string_size);
614 	}
615       sind = 0;
616       if (flags & ANCHORED_SEARCH)
617 	history_search_string[sind++] = '^';
618       strncpy (history_search_string + sind, rl_line_buffer, rl_point);
619       history_search_string[rl_point + sind] = '\0';
620     }
621   _rl_free_saved_history_line ();
622 }
623 
624 /* Search forward in the history for the string of characters
625    from the start of the line to rl_point.  This is a non-incremental
626    search.  The search is anchored to the beginning of the history line. */
627 int
rl_history_search_forward(int count,int ignore)628 rl_history_search_forward (int count, int ignore)
629 {
630   if (count == 0)
631     return (0);
632 
633   if (rl_last_func != rl_history_search_forward &&
634       rl_last_func != rl_history_search_backward)
635     rl_history_search_reinit (ANCHORED_SEARCH);
636 
637   if (rl_history_search_len == 0)
638     return (rl_get_next_history (count, ignore));
639   return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
640 }
641 
642 /* Search backward through the history for the string of characters
643    from the start of the line to rl_point.  This is a non-incremental
644    search. */
645 int
rl_history_search_backward(int count,int ignore)646 rl_history_search_backward (int count, int ignore)
647 {
648   if (count == 0)
649     return (0);
650 
651   if (rl_last_func != rl_history_search_forward &&
652       rl_last_func != rl_history_search_backward)
653     rl_history_search_reinit (ANCHORED_SEARCH);
654 
655   if (rl_history_search_len == 0)
656     return (rl_get_previous_history (count, ignore));
657   return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
658 }
659 
660 /* Search forward in the history for the string of characters
661    from the start of the line to rl_point.  This is a non-incremental
662    search.  The search succeeds if the search string is present anywhere
663    in the history line. */
664 int
rl_history_substr_search_forward(int count,int ignore)665 rl_history_substr_search_forward (int count, int ignore)
666 {
667   if (count == 0)
668     return (0);
669 
670   if (rl_last_func != rl_history_substr_search_forward &&
671       rl_last_func != rl_history_substr_search_backward)
672     rl_history_search_reinit (NON_ANCHORED_SEARCH);
673 
674   if (rl_history_search_len == 0)
675     return (rl_get_next_history (count, ignore));
676   return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
677 }
678 
679 /* Search backward through the history for the string of characters
680    from the start of the line to rl_point.  This is a non-incremental
681    search. */
682 int
rl_history_substr_search_backward(int count,int ignore)683 rl_history_substr_search_backward (int count, int ignore)
684 {
685   if (count == 0)
686     return (0);
687 
688   if (rl_last_func != rl_history_substr_search_forward &&
689       rl_last_func != rl_history_substr_search_backward)
690     rl_history_search_reinit (NON_ANCHORED_SEARCH);
691 
692   if (rl_history_search_len == 0)
693     return (rl_get_previous_history (count, ignore));
694   return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
695 }
696