search.c revision 75406
121308Sache/* search.c - code for non-incremental searching in emacs and vi modes. */
221308Sache
321308Sache/* Copyright (C) 1992 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"
4321308Sache#include "readline.h"
4421308Sache#include "history.h"
4521308Sache
4658310Sache#include "rlprivate.h"
4758310Sache#include "xmalloc.h"
4858310Sache
4926497Sache#ifdef abs
5026497Sache#  undef abs
5126497Sache#endif
5226497Sache#define abs(x)		(((x) >= 0) ? (x) : -(x))
5321308Sache
5475406Sacheextern HIST_ENTRY *_rl_saved_line_for_history;
5521308Sache
5621308Sache/* Functions imported from the rest of the library. */
5758310Sacheextern int _rl_free_history_entry __P((HIST_ENTRY *));
5821308Sache
5921308Sachestatic char *noninc_search_string = (char *) NULL;
6021308Sachestatic int noninc_history_pos;
6158310Sache
6221308Sachestatic char *prev_line_found = (char *) NULL;
6321308Sache
6458310Sachestatic int rl_history_search_len;
6558310Sachestatic int rl_history_search_pos;
6658310Sachestatic char *history_search_string;
6758310Sachestatic int history_string_size;
6858310Sache
6958310Sache/* Make the data from the history entry ENTRY be the contents of the
7058310Sache   current line.  This doesn't do anything with rl_point; the caller
7158310Sache   must set it. */
7258310Sachestatic void
7358310Sachemake_history_line_current (entry)
7458310Sache     HIST_ENTRY *entry;
7558310Sache{
7658310Sache  int line_len;
7758310Sache
7858310Sache  line_len = strlen (entry->line);
7958310Sache  if (line_len >= rl_line_buffer_len)
8058310Sache    rl_extend_line_buffer (line_len);
8158310Sache  strcpy (rl_line_buffer, entry->line);
8258310Sache
8358310Sache  rl_undo_list = (UNDO_LIST *)entry->data;
8458310Sache  rl_end = line_len;
8558310Sache
8675406Sache  if (_rl_saved_line_for_history)
8775406Sache    _rl_free_history_entry (_rl_saved_line_for_history);
8875406Sache  _rl_saved_line_for_history = (HIST_ENTRY *)NULL;
8958310Sache}
9058310Sache
9121308Sache/* Search the history list for STRING starting at absolute history position
9221308Sache   POS.  If STRING begins with `^', the search must match STRING at the
9321308Sache   beginning of a history line, otherwise a full substring match is performed
9421308Sache   for STRING.  DIR < 0 means to search backwards through the history list,
9521308Sache   DIR >= 0 means to search forward. */
9621308Sachestatic int
9721308Sachenoninc_search_from_pos (string, pos, dir)
9821308Sache     char *string;
9921308Sache     int pos, dir;
10021308Sache{
10121308Sache  int ret, old;
10221308Sache
10375406Sache  if (pos < 0)
10475406Sache    return -1;
10575406Sache
10621308Sache  old = where_history ();
10775406Sache  if (history_set_pos (pos) == 0)
10875406Sache    return -1;
10921308Sache
11075406Sache  RL_SETSTATE(RL_STATE_SEARCH);
11121308Sache  if (*string == '^')
11221308Sache    ret = history_search_prefix (string + 1, dir);
11321308Sache  else
11421308Sache    ret = history_search (string, dir);
11575406Sache  RL_UNSETSTATE(RL_STATE_SEARCH);
11621308Sache
11721308Sache  if (ret != -1)
11821308Sache    ret = where_history ();
11921308Sache
12021308Sache  history_set_pos (old);
12121308Sache  return (ret);
12221308Sache}
12321308Sache
12421308Sache/* Search for a line in the history containing STRING.  If DIR is < 0, the
12521308Sache   search is backwards through previous entries, else through subsequent
12621308Sache   entries. */
12721308Sachestatic void
12821308Sachenoninc_dosearch (string, dir)
12921308Sache     char *string;
13021308Sache     int dir;
13121308Sache{
13258310Sache  int oldpos, pos;
13321308Sache  HIST_ENTRY *entry;
13421308Sache
13521308Sache  if (string == 0 || *string == '\0' || noninc_history_pos < 0)
13621308Sache    {
13775406Sache      rl_ding ();
13821308Sache      return;
13921308Sache    }
14021308Sache
14121308Sache  pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
14221308Sache  if (pos == -1)
14321308Sache    {
14421308Sache      /* Search failed, current history position unchanged. */
14575406Sache      rl_maybe_unsave_line ();
14621308Sache      rl_clear_message ();
14721308Sache      rl_point = 0;
14875406Sache      rl_ding ();
14921308Sache      return;
15021308Sache    }
15121308Sache
15221308Sache  noninc_history_pos = pos;
15321308Sache
15421308Sache  oldpos = where_history ();
15521308Sache  history_set_pos (noninc_history_pos);
15621308Sache  entry = current_history ();
15721308Sache#if defined (VI_MODE)
15821308Sache  if (rl_editing_mode != vi_mode)
15921308Sache#endif
16021308Sache  history_set_pos (oldpos);
16121308Sache
16258310Sache  make_history_line_current (entry);
16321308Sache
16421308Sache  rl_point = 0;
16521308Sache  rl_clear_message ();
16621308Sache}
16721308Sache
16821308Sache/* Search non-interactively through the history list.  DIR < 0 means to
16921308Sache   search backwards through the history of previous commands; otherwise
17021308Sache   the search is for commands subsequent to the current position in the
17121308Sache   history list.  PCHAR is the character to use for prompting when reading
17221308Sache   the search string; if not specified (0), it defaults to `:'. */
17321308Sachestatic void
17421308Sachenoninc_search (dir, pchar)
17521308Sache     int dir;
17621308Sache     int pchar;
17721308Sache{
17821308Sache  int saved_point, c;
17921308Sache  char *p;
18021308Sache
18175406Sache  rl_maybe_save_line ();
18221308Sache  saved_point = rl_point;
18321308Sache
18421308Sache  /* Use the line buffer to read the search string. */
18521308Sache  rl_line_buffer[0] = 0;
18621308Sache  rl_end = rl_point = 0;
18721308Sache
18821308Sache  p = _rl_make_prompt_for_search (pchar ? pchar : ':');
18921308Sache  rl_message (p, 0, 0);
19021308Sache  free (p);
19121308Sache
19275406Sache#define SEARCH_RETURN rl_restore_prompt (); RL_UNSETSTATE(RL_STATE_NSEARCH); return
19321308Sache
19475406Sache  RL_SETSTATE(RL_STATE_NSEARCH);
19521308Sache  /* Read the search string. */
19675406Sache  while (1)
19721308Sache    {
19875406Sache      RL_SETSTATE(RL_STATE_MOREINPUT);
19975406Sache      c = rl_read_key ();
20075406Sache      RL_UNSETSTATE(RL_STATE_MOREINPUT);
20175406Sache
20275406Sache      if (c == 0)
20375406Sache	break;
20475406Sache
20521308Sache      switch (c)
20621308Sache	{
20721308Sache	case CTRL('H'):
20821308Sache	case RUBOUT:
20921308Sache	  if (rl_point == 0)
21021308Sache	    {
21175406Sache	      rl_maybe_unsave_line ();
21221308Sache	      rl_clear_message ();
21321308Sache	      rl_point = saved_point;
21421308Sache	      SEARCH_RETURN;
21521308Sache	    }
21621308Sache	  rl_rubout (1, c);
21721308Sache	  break;
21821308Sache
21921308Sache	case CTRL('W'):
22021308Sache	  rl_unix_word_rubout (1, c);
22121308Sache	  break;
22221308Sache
22321308Sache	case CTRL('U'):
22421308Sache	  rl_unix_line_discard (1, c);
22521308Sache	  break;
22621308Sache
22721308Sache	case RETURN:
22821308Sache	case NEWLINE:
22921308Sache	  goto dosearch;
23021308Sache	  /* NOTREACHED */
23121308Sache	  break;
23221308Sache
23321308Sache	case CTRL('C'):
23421308Sache	case CTRL('G'):
23575406Sache	  rl_maybe_unsave_line ();
23621308Sache	  rl_clear_message ();
23721308Sache	  rl_point = saved_point;
23875406Sache	  rl_ding ();
23921308Sache	  SEARCH_RETURN;
24021308Sache
24121308Sache	default:
24221308Sache	  rl_insert (1, c);
24321308Sache	  break;
24421308Sache	}
24521308Sache      (*rl_redisplay_function) ();
24621308Sache    }
24721308Sache
24821308Sache dosearch:
24921308Sache  /* If rl_point == 0, we want to re-use the previous search string and
25021308Sache     start from the saved history position.  If there's no previous search
25121308Sache     string, punt. */
25221308Sache  if (rl_point == 0)
25321308Sache    {
25421308Sache      if (!noninc_search_string)
25521308Sache	{
25675406Sache	  rl_ding ();
25721308Sache	  SEARCH_RETURN;
25821308Sache	}
25921308Sache    }
26021308Sache  else
26121308Sache    {
26221308Sache      /* We want to start the search from the current history position. */
26321308Sache      noninc_history_pos = where_history ();
26458310Sache      FREE (noninc_search_string);
26521308Sache      noninc_search_string = savestring (rl_line_buffer);
26621308Sache    }
26721308Sache
26847558Sache  rl_restore_prompt ();
26921308Sache  noninc_dosearch (noninc_search_string, dir);
27075406Sache  RL_UNSETSTATE(RL_STATE_NSEARCH);
27121308Sache}
27221308Sache
27321308Sache/* Search forward through the history list for a string.  If the vi-mode
27421308Sache   code calls this, KEY will be `?'. */
27521308Sacheint
27621308Sacherl_noninc_forward_search (count, key)
27721308Sache     int count, key;
27821308Sache{
27921308Sache  noninc_search (1, (key == '?') ? '?' : 0);
28021308Sache  return 0;
28121308Sache}
28221308Sache
28321308Sache/* Reverse search the history list for a string.  If the vi-mode code
28421308Sache   calls this, KEY will be `/'. */
28521308Sacheint
28621308Sacherl_noninc_reverse_search (count, key)
28721308Sache     int count, key;
28821308Sache{
28921308Sache  noninc_search (-1, (key == '/') ? '/' : 0);
29021308Sache  return 0;
29121308Sache}
29221308Sache
29321308Sache/* Search forward through the history list for the last string searched
29421308Sache   for.  If there is no saved search string, abort. */
29521308Sacheint
29621308Sacherl_noninc_forward_search_again (count, key)
29721308Sache     int count, key;
29821308Sache{
29921308Sache  if (!noninc_search_string)
30021308Sache    {
30175406Sache      rl_ding ();
30221308Sache      return (-1);
30321308Sache    }
30421308Sache  noninc_dosearch (noninc_search_string, 1);
30521308Sache  return 0;
30621308Sache}
30721308Sache
30821308Sache/* Reverse search in the history list for the last string searched
30921308Sache   for.  If there is no saved search string, abort. */
31021308Sacheint
31121308Sacherl_noninc_reverse_search_again (count, key)
31221308Sache     int count, key;
31321308Sache{
31421308Sache  if (!noninc_search_string)
31521308Sache    {
31675406Sache      rl_ding ();
31721308Sache      return (-1);
31821308Sache    }
31921308Sache  noninc_dosearch (noninc_search_string, -1);
32021308Sache  return 0;
32121308Sache}
32221308Sache
32321308Sachestatic int
32458310Sacherl_history_search_internal (count, dir)
32558310Sache     int count, dir;
32621308Sache{
32758310Sache  HIST_ENTRY *temp;
32858310Sache  int ret, oldpos;
32921308Sache
33075406Sache  rl_maybe_save_line ();
33158310Sache  temp = (HIST_ENTRY *)NULL;
33221308Sache
33358310Sache  /* Search COUNT times through the history for a line whose prefix
33458310Sache     matches history_search_string.  When this loop finishes, TEMP,
33558310Sache     if non-null, is the history line to copy into the line buffer. */
33621308Sache  while (count)
33721308Sache    {
33858310Sache      ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
33958310Sache      if (ret == -1)
34058310Sache	break;
34158310Sache
34258310Sache      /* Get the history entry we found. */
34358310Sache      rl_history_search_pos = ret;
34458310Sache      oldpos = where_history ();
34558310Sache      history_set_pos (rl_history_search_pos);
34658310Sache      temp = current_history ();
34758310Sache      history_set_pos (oldpos);
34858310Sache
34958310Sache      /* Don't find multiple instances of the same line. */
35058310Sache      if (prev_line_found && STREQ (prev_line_found, temp->line))
35158310Sache        continue;
35258310Sache      prev_line_found = temp->line;
35358310Sache      count--;
35421308Sache    }
35521308Sache
35658310Sache  /* If we didn't find anything at all, return. */
35721308Sache  if (temp == 0)
35821308Sache    {
35975406Sache      rl_maybe_unsave_line ();
36075406Sache      rl_ding ();
36158310Sache      /* If you don't want the saved history line (last match) to show up
36258310Sache         in the line buffer after the search fails, change the #if 0 to
36358310Sache         #if 1 */
36458310Sache#if 0
36558310Sache      if (rl_point > rl_history_search_len)
36658310Sache        {
36758310Sache          rl_point = rl_end = rl_history_search_len;
36858310Sache          rl_line_buffer[rl_end] = '\0';
36958310Sache        }
37058310Sache#else
37175406Sache      rl_point = rl_history_search_len;	/* rl_maybe_unsave_line changes it */
37258310Sache#endif
37358310Sache      return 1;
37421308Sache    }
37521308Sache
37658310Sache  /* Copy the line we found into the current line buffer. */
37758310Sache  make_history_line_current (temp);
37858310Sache
37958310Sache  rl_point = rl_history_search_len;
38021308Sache  return 0;
38121308Sache}
38221308Sache
38358310Sachestatic void
38458310Sacherl_history_search_reinit ()
38558310Sache{
38658310Sache  rl_history_search_pos = where_history ();
38758310Sache  rl_history_search_len = rl_point;
38858310Sache  prev_line_found = (char *)NULL;
38958310Sache  if (rl_point)
39058310Sache    {
39158310Sache      if (rl_history_search_len >= history_string_size - 2)
39258310Sache	{
39358310Sache	  history_string_size = rl_history_search_len + 2;
39458310Sache	  history_search_string = xrealloc (history_search_string, history_string_size);
39558310Sache	}
39658310Sache      history_search_string[0] = '^';
39758310Sache      strncpy (history_search_string + 1, rl_line_buffer, rl_point);
39858310Sache      history_search_string[rl_point + 1] = '\0';
39958310Sache    }
40075406Sache  _rl_free_saved_history_line ();
40158310Sache}
40258310Sache
40321308Sache/* Search forward in the history for the string of characters
40421308Sache   from the start of the line to rl_point.  This is a non-incremental
40521308Sache   search. */
40621308Sacheint
40721308Sacherl_history_search_forward (count, ignore)
40821308Sache     int count, ignore;
40921308Sache{
41021308Sache  if (count == 0)
41121308Sache    return (0);
41258310Sache
41358310Sache  if (rl_last_func != rl_history_search_forward &&
41458310Sache      rl_last_func != rl_history_search_backward)
41558310Sache    rl_history_search_reinit ();
41658310Sache
41758310Sache  if (rl_history_search_len == 0)
41858310Sache    return (rl_get_next_history (count, ignore));
41921308Sache  return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
42021308Sache}
42121308Sache
42221308Sache/* Search backward through the history for the string of characters
42321308Sache   from the start of the line to rl_point.  This is a non-incremental
42421308Sache   search. */
42521308Sacheint
42621308Sacherl_history_search_backward (count, ignore)
42721308Sache     int count, ignore;
42821308Sache{
42921308Sache  if (count == 0)
43021308Sache    return (0);
43158310Sache
43258310Sache  if (rl_last_func != rl_history_search_forward &&
43358310Sache      rl_last_func != rl_history_search_backward)
43458310Sache    rl_history_search_reinit ();
43558310Sache
43658310Sache  if (rl_history_search_len == 0)
43758310Sache    return (rl_get_previous_history (count, ignore));
43821308Sache  return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
43921308Sache}
440