121308Sache/* search.c - code for non-incremental searching in emacs and vi modes. */
221308Sache
3157184Sache/* Copyright (C) 1992-2005 Free Software Foundation, Inc.
421308Sache
521308Sache   This file is part of the Readline Library (the Library), a set of
621308Sache   routines for providing Emacs style line input to programs that ask
721308Sache   for it.
821308Sache
921308Sache   The Library is free software; you can redistribute it and/or modify
1021308Sache   it under the terms of the GNU General Public License as published by
1158310Sache   the Free Software Foundation; either version 2, or (at your option)
1221308Sache   any later version.
1321308Sache
1421308Sache   The Library is distributed in the hope that it will be useful, but
1521308Sache   WITHOUT ANY WARRANTY; without even the implied warranty of
1621308Sache   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1721308Sache   General Public License for more details.
1821308Sache
1921308Sache   The GNU General Public License is often shipped with GNU software, and
2021308Sache   is generally kept in a file called COPYING or LICENSE.  If you do not
2121308Sache   have a copy of the license, write to the Free Software Foundation,
2258310Sache   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
2321308Sache#define READLINE_LIBRARY
2421308Sache
2521308Sache#if defined (HAVE_CONFIG_H)
2621308Sache#  include <config.h>
2721308Sache#endif
2821308Sache
2921308Sache#include <sys/types.h>
3021308Sache#include <stdio.h>
3121308Sache
3221308Sache#if defined (HAVE_UNISTD_H)
3321308Sache#  include <unistd.h>
3421308Sache#endif
3521308Sache
3626497Sache#if defined (HAVE_STDLIB_H)
3726497Sache#  include <stdlib.h>
3826497Sache#else
3926497Sache#  include "ansi_stdlib.h"
4026497Sache#endif
4126497Sache
4221308Sache#include "rldefs.h"
43119610Sache#include "rlmbutil.h"
44119610Sache
4521308Sache#include "readline.h"
4621308Sache#include "history.h"
4721308Sache
4858310Sache#include "rlprivate.h"
4958310Sache#include "xmalloc.h"
5058310Sache
5126497Sache#ifdef abs
5226497Sache#  undef abs
5326497Sache#endif
5426497Sache#define abs(x)		(((x) >= 0) ? (x) : -(x))
5521308Sache
56157184Sache_rl_search_cxt *_rl_nscxt = 0;
57157184Sache
5875406Sacheextern HIST_ENTRY *_rl_saved_line_for_history;
5921308Sache
6021308Sache/* Functions imported from the rest of the library. */
61119610Sacheextern int _rl_free_history_entry PARAMS((HIST_ENTRY *));
6221308Sache
6321308Sachestatic char *noninc_search_string = (char *) NULL;
6421308Sachestatic int noninc_history_pos;
6558310Sache
6621308Sachestatic char *prev_line_found = (char *) NULL;
6721308Sache
6858310Sachestatic int rl_history_search_len;
6958310Sachestatic int rl_history_search_pos;
7058310Sachestatic char *history_search_string;
7158310Sachestatic int history_string_size;
7258310Sache
73119610Sachestatic void make_history_line_current PARAMS((HIST_ENTRY *));
74119610Sachestatic int noninc_search_from_pos PARAMS((char *, int, int));
75157184Sachestatic int noninc_dosearch PARAMS((char *, int));
76157184Sachestatic int noninc_search PARAMS((int, int));
77119610Sachestatic int rl_history_search_internal PARAMS((int, int));
78119610Sachestatic void rl_history_search_reinit PARAMS((void));
79119610Sache
80157184Sachestatic _rl_search_cxt *_rl_nsearch_init PARAMS((int, int));
81157184Sachestatic int _rl_nsearch_cleanup PARAMS((_rl_search_cxt *, int));
82157184Sachestatic void _rl_nsearch_abort PARAMS((_rl_search_cxt *));
83157184Sachestatic int _rl_nsearch_dispatch PARAMS((_rl_search_cxt *, int));
84157184Sache
8558310Sache/* Make the data from the history entry ENTRY be the contents of the
8658310Sache   current line.  This doesn't do anything with rl_point; the caller
8758310Sache   must set it. */
8858310Sachestatic void
8958310Sachemake_history_line_current (entry)
9058310Sache     HIST_ENTRY *entry;
9158310Sache{
92136644Sache  _rl_replace_text (entry->line, 0, rl_end);
93136644Sache  _rl_fix_point (1);
94157184Sache#if defined (VI_MODE)
95157184Sache  if (rl_editing_mode == vi_mode)
96157184Sache    /* POSIX.2 says that the `U' command doesn't affect the copy of any
97157184Sache       command lines to the edit line.  We're going to implement that by
98157184Sache       making the undo list start after the matching line is copied to the
99157184Sache       current editing buffer. */
100157184Sache    rl_free_undo_list ();
101136644Sache#endif
10258310Sache
10375406Sache  if (_rl_saved_line_for_history)
10475406Sache    _rl_free_history_entry (_rl_saved_line_for_history);
10575406Sache  _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
10658310Sache}
10758310Sache
10821308Sache/* Search the history list for STRING starting at absolute history position
10921308Sache   POS.  If STRING begins with `^', the search must match STRING at the
11021308Sache   beginning of a history line, otherwise a full substring match is performed
11121308Sache   for STRING.  DIR < 0 means to search backwards through the history list,
11221308Sache   DIR >= 0 means to search forward. */
11321308Sachestatic int
11421308Sachenoninc_search_from_pos (string, pos, dir)
11521308Sache     char *string;
11621308Sache     int pos, dir;
11721308Sache{
11821308Sache  int ret, old;
11921308Sache
12075406Sache  if (pos < 0)
12175406Sache    return -1;
12275406Sache
12321308Sache  old = where_history ();
12475406Sache  if (history_set_pos (pos) == 0)
12575406Sache    return -1;
12621308Sache
12775406Sache  RL_SETSTATE(RL_STATE_SEARCH);
12821308Sache  if (*string == '^')
12921308Sache    ret = history_search_prefix (string + 1, dir);
13021308Sache  else
13121308Sache    ret = history_search (string, dir);
13275406Sache  RL_UNSETSTATE(RL_STATE_SEARCH);
13321308Sache
13421308Sache  if (ret != -1)
13521308Sache    ret = where_history ();
13621308Sache
13721308Sache  history_set_pos (old);
13821308Sache  return (ret);
13921308Sache}
14021308Sache
14121308Sache/* Search for a line in the history containing STRING.  If DIR is < 0, the
14221308Sache   search is backwards through previous entries, else through subsequent
143157184Sache   entries.  Returns 1 if the search was successful, 0 otherwise. */
144157184Sachestatic int
14521308Sachenoninc_dosearch (string, dir)
14621308Sache     char *string;
14721308Sache     int dir;
14821308Sache{
14958310Sache  int oldpos, pos;
15021308Sache  HIST_ENTRY *entry;
15121308Sache
15221308Sache  if (string == 0 || *string == '\0' || noninc_history_pos < 0)
15321308Sache    {
15475406Sache      rl_ding ();
155157184Sache      return 0;
15621308Sache    }
15721308Sache
15821308Sache  pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
15921308Sache  if (pos == -1)
16021308Sache    {
16121308Sache      /* Search failed, current history position unchanged. */
16275406Sache      rl_maybe_unsave_line ();
16321308Sache      rl_clear_message ();
16421308Sache      rl_point = 0;
16575406Sache      rl_ding ();
166157184Sache      return 0;
16721308Sache    }
16821308Sache
16921308Sache  noninc_history_pos = pos;
17021308Sache
17121308Sache  oldpos = where_history ();
17221308Sache  history_set_pos (noninc_history_pos);
17321308Sache  entry = current_history ();
17421308Sache#if defined (VI_MODE)
17521308Sache  if (rl_editing_mode != vi_mode)
17621308Sache#endif
177157184Sache    history_set_pos (oldpos);
17821308Sache
17958310Sache  make_history_line_current (entry);
18021308Sache
18121308Sache  rl_point = 0;
182119610Sache  rl_mark = rl_end;
183119610Sache
18421308Sache  rl_clear_message ();
185157184Sache  return 1;
18621308Sache}
18721308Sache
188157184Sachestatic _rl_search_cxt *
189157184Sache_rl_nsearch_init (dir, pchar)
190157184Sache     int dir, pchar;
19121308Sache{
192157184Sache  _rl_search_cxt *cxt;
19321308Sache  char *p;
19421308Sache
195157184Sache  cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0);
196157184Sache  if (dir < 0)
197157184Sache    cxt->sflags |= SF_REVERSE;		/* not strictly needed */
198157184Sache
199157184Sache  cxt->direction = dir;
200157184Sache  cxt->history_pos = cxt->save_line;
201157184Sache
20275406Sache  rl_maybe_save_line ();
20321308Sache
204136644Sache  /* Clear the undo list, since reading the search string should create its
205136644Sache     own undo list, and the whole list will end up being freed when we
206136644Sache     finish reading the search string. */
207136644Sache  rl_undo_list = 0;
208136644Sache
20921308Sache  /* Use the line buffer to read the search string. */
21021308Sache  rl_line_buffer[0] = 0;
21121308Sache  rl_end = rl_point = 0;
21221308Sache
21321308Sache  p = _rl_make_prompt_for_search (pchar ? pchar : ':');
214165670Sache  rl_message ("%s", p, 0);
21521308Sache  free (p);
21621308Sache
21775406Sache  RL_SETSTATE(RL_STATE_NSEARCH);
21875406Sache
219157184Sache  _rl_nscxt = cxt;
220119610Sache
221157184Sache  return cxt;
222157184Sache}
22375406Sache
224157184Sachestatic int
225157184Sache_rl_nsearch_cleanup (cxt, r)
226157184Sache     _rl_search_cxt *cxt;
227157184Sache     int r;
228157184Sache{
229157184Sache  _rl_scxt_dispose (cxt, 0);
230157184Sache  _rl_nscxt = 0;
23121308Sache
232157184Sache  RL_UNSETSTATE(RL_STATE_NSEARCH);
23321308Sache
234157184Sache  return (r != 1);
235157184Sache}
23621308Sache
237157184Sachestatic void
238157184Sache_rl_nsearch_abort (cxt)
239157184Sache     _rl_search_cxt *cxt;
240157184Sache{
241157184Sache  rl_maybe_unsave_line ();
242157184Sache  rl_clear_message ();
243157184Sache  rl_point = cxt->save_point;
244157184Sache  rl_mark = cxt->save_mark;
245157184Sache  rl_restore_prompt ();
24621308Sache
247157184Sache  RL_UNSETSTATE (RL_STATE_NSEARCH);
248157184Sache}
24921308Sache
250157184Sache/* Process just-read character C according to search context CXT.  Return -1
251157184Sache   if the caller should abort the search, 0 if we should break out of the
252157184Sache   loop, and 1 if we should continue to read characters. */
253157184Sachestatic int
254157184Sache_rl_nsearch_dispatch (cxt, c)
255157184Sache     _rl_search_cxt *cxt;
256157184Sache     int c;
257157184Sache{
258157184Sache  switch (c)
259157184Sache    {
260157184Sache    case CTRL('W'):
261157184Sache      rl_unix_word_rubout (1, c);
262157184Sache      break;
263157184Sache
264157184Sache    case CTRL('U'):
265157184Sache      rl_unix_line_discard (1, c);
266157184Sache      break;
267157184Sache
268157184Sache    case RETURN:
269157184Sache    case NEWLINE:
270157184Sache      return 0;
271157184Sache
272157184Sache    case CTRL('H'):
273157184Sache    case RUBOUT:
274157184Sache      if (rl_point == 0)
275157184Sache	{
276157184Sache	  _rl_nsearch_abort (cxt);
277157184Sache	  return -1;
278157184Sache	}
279157184Sache      _rl_rubout_char (1, c);
280157184Sache      break;
281157184Sache
282157184Sache    case CTRL('C'):
283157184Sache    case CTRL('G'):
284157184Sache      rl_ding ();
285157184Sache      _rl_nsearch_abort (cxt);
286157184Sache      return -1;
287157184Sache
288157184Sache    default:
289119610Sache#if defined (HANDLE_MULTIBYTE)
290157184Sache      if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
291157184Sache	rl_insert_text (cxt->mb);
292157184Sache      else
293119610Sache#endif
294157184Sache	_rl_insert_char (1, c);
295157184Sache      break;
29621308Sache    }
29721308Sache
298157184Sache  (*rl_redisplay_function) ();
299157184Sache  return 1;
300157184Sache}
301119610Sache
302157184Sache/* Perform one search according to CXT, using NONINC_SEARCH_STRING.  Return
303157184Sache   -1 if the search should be aborted, any other value means to clean up
304157184Sache   using _rl_nsearch_cleanup ().  Returns 1 if the search was successful,
305157184Sache   0 otherwise. */
306157184Sachestatic int
307157184Sache_rl_nsearch_dosearch (cxt)
308157184Sache     _rl_search_cxt *cxt;
309157184Sache{
310157184Sache  rl_mark = cxt->save_mark;
311157184Sache
31221308Sache  /* If rl_point == 0, we want to re-use the previous search string and
31321308Sache     start from the saved history position.  If there's no previous search
31421308Sache     string, punt. */
31521308Sache  if (rl_point == 0)
31621308Sache    {
317157184Sache      if (noninc_search_string == 0)
31821308Sache	{
31975406Sache	  rl_ding ();
320157184Sache	  rl_restore_prompt ();
321157184Sache	  RL_UNSETSTATE (RL_STATE_NSEARCH);
322157184Sache	  return -1;
32321308Sache	}
32421308Sache    }
32521308Sache  else
32621308Sache    {
32721308Sache      /* We want to start the search from the current history position. */
328157184Sache      noninc_history_pos = cxt->save_line;
32958310Sache      FREE (noninc_search_string);
33021308Sache      noninc_search_string = savestring (rl_line_buffer);
331157184Sache
332157184Sache      /* If we don't want the subsequent undo list generated by the search
333157184Sache	 matching a history line to include the contents of the search string,
334157184Sache	 we need to clear rl_line_buffer here.  For now, we just clear the
335157184Sache	 undo list generated by reading the search string.  (If the search
336157184Sache	 fails, the old undo list will be restored by rl_maybe_unsave_line.) */
337157184Sache      rl_free_undo_list ();
33821308Sache    }
33921308Sache
34047558Sache  rl_restore_prompt ();
341157184Sache  return (noninc_dosearch (noninc_search_string, cxt->direction));
34221308Sache}
34321308Sache
344157184Sache/* Search non-interactively through the history list.  DIR < 0 means to
345157184Sache   search backwards through the history of previous commands; otherwise
346157184Sache   the search is for commands subsequent to the current position in the
347157184Sache   history list.  PCHAR is the character to use for prompting when reading
348157184Sache   the search string; if not specified (0), it defaults to `:'. */
349157184Sachestatic int
350157184Sachenoninc_search (dir, pchar)
351157184Sache     int dir;
352157184Sache     int pchar;
353157184Sache{
354157184Sache  _rl_search_cxt *cxt;
355157184Sache  int c, r;
356157184Sache
357157184Sache  cxt = _rl_nsearch_init (dir, pchar);
358157184Sache
359157184Sache  if (RL_ISSTATE (RL_STATE_CALLBACK))
360157184Sache    return (0);
361157184Sache
362157184Sache  /* Read the search string. */
363157184Sache  r = 0;
364157184Sache  while (1)
365157184Sache    {
366157184Sache      c = _rl_search_getchar (cxt);
367157184Sache
368157184Sache      if (c == 0)
369157184Sache	break;
370157184Sache
371157184Sache      r = _rl_nsearch_dispatch (cxt, c);
372157184Sache      if (r < 0)
373157184Sache        return 1;
374157184Sache      else if (r == 0)
375157184Sache	break;
376157184Sache    }
377157184Sache
378157184Sache  r = _rl_nsearch_dosearch (cxt);
379157184Sache  return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
380157184Sache}
381157184Sache
38221308Sache/* Search forward through the history list for a string.  If the vi-mode
38321308Sache   code calls this, KEY will be `?'. */
38421308Sacheint
38521308Sacherl_noninc_forward_search (count, key)
38621308Sache     int count, key;
38721308Sache{
388157184Sache  return noninc_search (1, (key == '?') ? '?' : 0);
38921308Sache}
39021308Sache
39121308Sache/* Reverse search the history list for a string.  If the vi-mode code
39221308Sache   calls this, KEY will be `/'. */
39321308Sacheint
39421308Sacherl_noninc_reverse_search (count, key)
39521308Sache     int count, key;
39621308Sache{
397157184Sache  return noninc_search (-1, (key == '/') ? '/' : 0);
39821308Sache}
39921308Sache
40021308Sache/* Search forward through the history list for the last string searched
40121308Sache   for.  If there is no saved search string, abort. */
40221308Sacheint
40321308Sacherl_noninc_forward_search_again (count, key)
40421308Sache     int count, key;
40521308Sache{
406157184Sache  int r;
407157184Sache
40821308Sache  if (!noninc_search_string)
40921308Sache    {
41075406Sache      rl_ding ();
41121308Sache      return (-1);
41221308Sache    }
413157184Sache  r = noninc_dosearch (noninc_search_string, 1);
414157184Sache  return (r != 1);
41521308Sache}
41621308Sache
41721308Sache/* Reverse search in the history list for the last string searched
41821308Sache   for.  If there is no saved search string, abort. */
41921308Sacheint
42021308Sacherl_noninc_reverse_search_again (count, key)
42121308Sache     int count, key;
42221308Sache{
423157184Sache  int r;
424157184Sache
42521308Sache  if (!noninc_search_string)
42621308Sache    {
42775406Sache      rl_ding ();
42821308Sache      return (-1);
42921308Sache    }
430157184Sache  r = noninc_dosearch (noninc_search_string, -1);
431157184Sache  return (r != 1);
43221308Sache}
43321308Sache
434157184Sache#if defined (READLINE_CALLBACKS)
435157184Sacheint
436157184Sache_rl_nsearch_callback (cxt)
437157184Sache     _rl_search_cxt *cxt;
438157184Sache{
439157184Sache  int c, r;
440157184Sache
441157184Sache  c = _rl_search_getchar (cxt);
442157184Sache  r = _rl_nsearch_dispatch (cxt, c);
443157184Sache  if (r != 0)
444157184Sache    return 1;
445157184Sache
446157184Sache  r = _rl_nsearch_dosearch (cxt);
447157184Sache  return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
448157184Sache}
449157184Sache#endif
450157184Sache
45121308Sachestatic int
45258310Sacherl_history_search_internal (count, dir)
45358310Sache     int count, dir;
45421308Sache{
45558310Sache  HIST_ENTRY *temp;
45658310Sache  int ret, oldpos;
45721308Sache
45875406Sache  rl_maybe_save_line ();
45958310Sache  temp = (HIST_ENTRY *)NULL;
46021308Sache
46158310Sache  /* Search COUNT times through the history for a line whose prefix
46258310Sache     matches history_search_string.  When this loop finishes, TEMP,
46358310Sache     if non-null, is the history line to copy into the line buffer. */
46421308Sache  while (count)
46521308Sache    {
46658310Sache      ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
46758310Sache      if (ret == -1)
46858310Sache	break;
46958310Sache
47058310Sache      /* Get the history entry we found. */
47158310Sache      rl_history_search_pos = ret;
47258310Sache      oldpos = where_history ();
47358310Sache      history_set_pos (rl_history_search_pos);
47458310Sache      temp = current_history ();
47558310Sache      history_set_pos (oldpos);
47658310Sache
47758310Sache      /* Don't find multiple instances of the same line. */
47858310Sache      if (prev_line_found && STREQ (prev_line_found, temp->line))
47958310Sache        continue;
48058310Sache      prev_line_found = temp->line;
48158310Sache      count--;
48221308Sache    }
48321308Sache
48458310Sache  /* If we didn't find anything at all, return. */
48521308Sache  if (temp == 0)
48621308Sache    {
48775406Sache      rl_maybe_unsave_line ();
48875406Sache      rl_ding ();
48958310Sache      /* If you don't want the saved history line (last match) to show up
49058310Sache         in the line buffer after the search fails, change the #if 0 to
49158310Sache         #if 1 */
49258310Sache#if 0
49358310Sache      if (rl_point > rl_history_search_len)
49458310Sache        {
49558310Sache          rl_point = rl_end = rl_history_search_len;
49658310Sache          rl_line_buffer[rl_end] = '\0';
497119610Sache          rl_mark = 0;
49858310Sache        }
49958310Sache#else
50075406Sache      rl_point = rl_history_search_len;	/* rl_maybe_unsave_line changes it */
501119610Sache      rl_mark = rl_end;
50258310Sache#endif
50358310Sache      return 1;
50421308Sache    }
50521308Sache
50658310Sache  /* Copy the line we found into the current line buffer. */
50758310Sache  make_history_line_current (temp);
50858310Sache
50958310Sache  rl_point = rl_history_search_len;
510119610Sache  rl_mark = rl_end;
511119610Sache
51221308Sache  return 0;
51321308Sache}
51421308Sache
51558310Sachestatic void
51658310Sacherl_history_search_reinit ()
51758310Sache{
51858310Sache  rl_history_search_pos = where_history ();
51958310Sache  rl_history_search_len = rl_point;
52058310Sache  prev_line_found = (char *)NULL;
52158310Sache  if (rl_point)
52258310Sache    {
52358310Sache      if (rl_history_search_len >= history_string_size - 2)
52458310Sache	{
52558310Sache	  history_string_size = rl_history_search_len + 2;
526119610Sache	  history_search_string = (char *)xrealloc (history_search_string, history_string_size);
52758310Sache	}
52858310Sache      history_search_string[0] = '^';
52958310Sache      strncpy (history_search_string + 1, rl_line_buffer, rl_point);
53058310Sache      history_search_string[rl_point + 1] = '\0';
53158310Sache    }
53275406Sache  _rl_free_saved_history_line ();
53358310Sache}
53458310Sache
53521308Sache/* Search forward in the history for the string of characters
53621308Sache   from the start of the line to rl_point.  This is a non-incremental
53721308Sache   search. */
53821308Sacheint
53921308Sacherl_history_search_forward (count, ignore)
54021308Sache     int count, ignore;
54121308Sache{
54221308Sache  if (count == 0)
54321308Sache    return (0);
54458310Sache
54558310Sache  if (rl_last_func != rl_history_search_forward &&
54658310Sache      rl_last_func != rl_history_search_backward)
54758310Sache    rl_history_search_reinit ();
54858310Sache
54958310Sache  if (rl_history_search_len == 0)
55058310Sache    return (rl_get_next_history (count, ignore));
55121308Sache  return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
55221308Sache}
55321308Sache
55421308Sache/* Search backward through the history for the string of characters
55521308Sache   from the start of the line to rl_point.  This is a non-incremental
55621308Sache   search. */
55721308Sacheint
55821308Sacherl_history_search_backward (count, ignore)
55921308Sache     int count, ignore;
56021308Sache{
56121308Sache  if (count == 0)
56221308Sache    return (0);
56358310Sache
56458310Sache  if (rl_last_func != rl_history_search_forward &&
56558310Sache      rl_last_func != rl_history_search_backward)
56658310Sache    rl_history_search_reinit ();
56758310Sache
56858310Sache  if (rl_history_search_len == 0)
56958310Sache    return (rl_get_previous_history (count, ignore));
57021308Sache  return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
57121308Sache}
572