search.c revision 47558
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
1121308Sache   the Free Software Foundation; either version 1, 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,
2221308Sache   675 Mass Ave, Cambridge, MA 02139, 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
4626497Sache#ifdef abs
4726497Sache#  undef abs
4826497Sache#endif
4926497Sache#define abs(x)		(((x) >= 0) ? (x) : -(x))
5021308Sache
5121308Sacheextern char *xmalloc (), *xrealloc ();
5221308Sache
5321308Sache/* Variables imported from readline.c */
5421308Sacheextern int rl_point, rl_end, rl_line_buffer_len;
5521308Sacheextern int rl_editing_mode;
5621308Sacheextern char *rl_prompt;
5721308Sacheextern char *rl_line_buffer;
5821308Sacheextern HIST_ENTRY *saved_line_for_history;
5921308Sacheextern Function *rl_last_func;
6021308Sache
6121308Sache/* Functions imported from the rest of the library. */
6221308Sacheextern int _rl_free_history_entry ();
6321308Sacheextern char *_rl_make_prompt_for_search ();
6421308Sacheextern void rl_extend_line_buffer ();
6521308Sache
6621308Sachestatic char *noninc_search_string = (char *) NULL;
6721308Sachestatic int noninc_history_pos;
6821308Sachestatic char *prev_line_found = (char *) NULL;
6921308Sache
7021308Sache/* Search the history list for STRING starting at absolute history position
7121308Sache   POS.  If STRING begins with `^', the search must match STRING at the
7221308Sache   beginning of a history line, otherwise a full substring match is performed
7321308Sache   for STRING.  DIR < 0 means to search backwards through the history list,
7421308Sache   DIR >= 0 means to search forward. */
7521308Sachestatic int
7621308Sachenoninc_search_from_pos (string, pos, dir)
7721308Sache     char *string;
7821308Sache     int pos, dir;
7921308Sache{
8021308Sache  int ret, old;
8121308Sache
8221308Sache  old = where_history ();
8321308Sache  history_set_pos (pos);
8421308Sache
8521308Sache  if (*string == '^')
8621308Sache    ret = history_search_prefix (string + 1, dir);
8721308Sache  else
8821308Sache    ret = history_search (string, dir);
8921308Sache
9021308Sache  if (ret != -1)
9121308Sache    ret = where_history ();
9221308Sache
9321308Sache  history_set_pos (old);
9421308Sache  return (ret);
9521308Sache}
9621308Sache
9721308Sache/* Search for a line in the history containing STRING.  If DIR is < 0, the
9821308Sache   search is backwards through previous entries, else through subsequent
9921308Sache   entries. */
10021308Sachestatic void
10121308Sachenoninc_dosearch (string, dir)
10221308Sache     char *string;
10321308Sache     int dir;
10421308Sache{
10521308Sache  int oldpos, pos, line_len;
10621308Sache  HIST_ENTRY *entry;
10721308Sache
10821308Sache  if (string == 0 || *string == '\0' || noninc_history_pos < 0)
10921308Sache    {
11021308Sache      ding ();
11121308Sache      return;
11221308Sache    }
11321308Sache
11421308Sache  pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
11521308Sache  if (pos == -1)
11621308Sache    {
11721308Sache      /* Search failed, current history position unchanged. */
11821308Sache      maybe_unsave_line ();
11921308Sache      rl_clear_message ();
12021308Sache      rl_point = 0;
12121308Sache      ding ();
12221308Sache      return;
12321308Sache    }
12421308Sache
12521308Sache  noninc_history_pos = pos;
12621308Sache
12721308Sache  oldpos = where_history ();
12821308Sache  history_set_pos (noninc_history_pos);
12921308Sache  entry = current_history ();
13021308Sache#if defined (VI_MODE)
13121308Sache  if (rl_editing_mode != vi_mode)
13221308Sache#endif
13321308Sache  history_set_pos (oldpos);
13421308Sache
13521308Sache  line_len = strlen (entry->line);
13621308Sache  if (line_len >= rl_line_buffer_len)
13721308Sache    rl_extend_line_buffer (line_len);
13821308Sache  strcpy (rl_line_buffer, entry->line);
13921308Sache
14021308Sache  rl_undo_list = (UNDO_LIST *)entry->data;
14121308Sache  rl_end = strlen (rl_line_buffer);
14221308Sache  rl_point = 0;
14321308Sache  rl_clear_message ();
14421308Sache
14521308Sache  if (saved_line_for_history)
14621308Sache    _rl_free_history_entry (saved_line_for_history);
14721308Sache  saved_line_for_history = (HIST_ENTRY *)NULL;
14821308Sache}
14921308Sache
15021308Sache/* Search non-interactively through the history list.  DIR < 0 means to
15121308Sache   search backwards through the history of previous commands; otherwise
15221308Sache   the search is for commands subsequent to the current position in the
15321308Sache   history list.  PCHAR is the character to use for prompting when reading
15421308Sache   the search string; if not specified (0), it defaults to `:'. */
15521308Sachestatic void
15621308Sachenoninc_search (dir, pchar)
15721308Sache     int dir;
15821308Sache     int pchar;
15921308Sache{
16021308Sache  int saved_point, c;
16121308Sache  char *p;
16221308Sache
16321308Sache  maybe_save_line ();
16421308Sache  saved_point = rl_point;
16521308Sache
16621308Sache  /* Use the line buffer to read the search string. */
16721308Sache  rl_line_buffer[0] = 0;
16821308Sache  rl_end = rl_point = 0;
16921308Sache
17021308Sache  p = _rl_make_prompt_for_search (pchar ? pchar : ':');
17121308Sache  rl_message (p, 0, 0);
17221308Sache  free (p);
17321308Sache
17447558Sache#define SEARCH_RETURN rl_restore_prompt (); return
17521308Sache
17621308Sache  /* Read the search string. */
17721308Sache  while (c = rl_read_key ())
17821308Sache    {
17921308Sache      switch (c)
18021308Sache	{
18121308Sache	case CTRL('H'):
18221308Sache	case RUBOUT:
18321308Sache	  if (rl_point == 0)
18421308Sache	    {
18521308Sache	      maybe_unsave_line ();
18621308Sache	      rl_clear_message ();
18721308Sache	      rl_point = saved_point;
18821308Sache	      SEARCH_RETURN;
18921308Sache	    }
19021308Sache	  rl_rubout (1, c);
19121308Sache	  break;
19221308Sache
19321308Sache	case CTRL('W'):
19421308Sache	  rl_unix_word_rubout (1, c);
19521308Sache	  break;
19621308Sache
19721308Sache	case CTRL('U'):
19821308Sache	  rl_unix_line_discard (1, c);
19921308Sache	  break;
20021308Sache
20121308Sache	case RETURN:
20221308Sache	case NEWLINE:
20321308Sache	  goto dosearch;
20421308Sache	  /* NOTREACHED */
20521308Sache	  break;
20621308Sache
20721308Sache	case CTRL('C'):
20821308Sache	case CTRL('G'):
20921308Sache	  maybe_unsave_line ();
21021308Sache	  rl_clear_message ();
21121308Sache	  rl_point = saved_point;
21221308Sache	  ding ();
21321308Sache	  SEARCH_RETURN;
21421308Sache
21521308Sache	default:
21621308Sache	  rl_insert (1, c);
21721308Sache	  break;
21821308Sache	}
21921308Sache      (*rl_redisplay_function) ();
22021308Sache    }
22121308Sache
22221308Sache dosearch:
22321308Sache  /* If rl_point == 0, we want to re-use the previous search string and
22421308Sache     start from the saved history position.  If there's no previous search
22521308Sache     string, punt. */
22621308Sache  if (rl_point == 0)
22721308Sache    {
22821308Sache      if (!noninc_search_string)
22921308Sache	{
23021308Sache	  ding ();
23121308Sache	  SEARCH_RETURN;
23221308Sache	}
23321308Sache    }
23421308Sache  else
23521308Sache    {
23621308Sache      /* We want to start the search from the current history position. */
23721308Sache      noninc_history_pos = where_history ();
23821308Sache      if (noninc_search_string)
23921308Sache	free (noninc_search_string);
24021308Sache      noninc_search_string = savestring (rl_line_buffer);
24121308Sache    }
24221308Sache
24347558Sache  rl_restore_prompt ();
24421308Sache  noninc_dosearch (noninc_search_string, dir);
24521308Sache}
24621308Sache
24721308Sache/* Search forward through the history list for a string.  If the vi-mode
24821308Sache   code calls this, KEY will be `?'. */
24921308Sacheint
25021308Sacherl_noninc_forward_search (count, key)
25121308Sache     int count, key;
25221308Sache{
25321308Sache  noninc_search (1, (key == '?') ? '?' : 0);
25421308Sache  return 0;
25521308Sache}
25621308Sache
25721308Sache/* Reverse search the history list for a string.  If the vi-mode code
25821308Sache   calls this, KEY will be `/'. */
25921308Sacheint
26021308Sacherl_noninc_reverse_search (count, key)
26121308Sache     int count, key;
26221308Sache{
26321308Sache  noninc_search (-1, (key == '/') ? '/' : 0);
26421308Sache  return 0;
26521308Sache}
26621308Sache
26721308Sache/* Search forward through the history list for the last string searched
26821308Sache   for.  If there is no saved search string, abort. */
26921308Sacheint
27021308Sacherl_noninc_forward_search_again (count, key)
27121308Sache     int count, key;
27221308Sache{
27321308Sache  if (!noninc_search_string)
27421308Sache    {
27521308Sache      ding ();
27621308Sache      return (-1);
27721308Sache    }
27821308Sache  noninc_dosearch (noninc_search_string, 1);
27921308Sache  return 0;
28021308Sache}
28121308Sache
28221308Sache/* Reverse search in the history list for the last string searched
28321308Sache   for.  If there is no saved search string, abort. */
28421308Sacheint
28521308Sacherl_noninc_reverse_search_again (count, key)
28621308Sache     int count, key;
28721308Sache{
28821308Sache  if (!noninc_search_string)
28921308Sache    {
29021308Sache      ding ();
29121308Sache      return (-1);
29221308Sache    }
29321308Sache  noninc_dosearch (noninc_search_string, -1);
29421308Sache  return 0;
29521308Sache}
29621308Sache
29721308Sachestatic int
29821308Sacherl_history_search_internal (count, direction)
29921308Sache     int count, direction;
30021308Sache{
30121308Sache  HIST_ENTRY *temp, *old_temp;
30221308Sache  int line_len;
30321308Sache
30421308Sache  maybe_save_line ();
30521308Sache
30621308Sache  temp = old_temp = (HIST_ENTRY *)NULL;
30721308Sache  while (count)
30821308Sache    {
30921308Sache      temp = (direction < 0) ? previous_history () : next_history ();
31021308Sache      if (temp == 0)
31121308Sache        break;
31221308Sache      /* On an empty prefix, make this the same as previous-history. */
31321308Sache      if (rl_point == 0)
31421308Sache	{
31521308Sache	  count--;
31621308Sache	  continue;
31721308Sache	}
31821308Sache      if (STREQN (rl_line_buffer, temp->line, rl_point))
31921308Sache	{
32021308Sache	  /* Don't find multiple instances of the same line. */
32121308Sache	  if (prev_line_found && STREQ (prev_line_found, temp->line))
32221308Sache	    continue;
32321308Sache          if (direction < 0)
32421308Sache            old_temp = temp;
32521308Sache          prev_line_found = temp->line;
32621308Sache          count--;
32721308Sache	}
32821308Sache    }
32921308Sache
33021308Sache  if (temp == 0)
33121308Sache    {
33221308Sache      if (direction < 0 && old_temp)
33321308Sache	temp = old_temp;
33421308Sache      else
33521308Sache	{
33621308Sache	  maybe_unsave_line ();
33721308Sache	  ding ();
33821308Sache	  return 1;
33921308Sache	}
34021308Sache    }
34121308Sache
34221308Sache  line_len = strlen (temp->line);
34321308Sache  if (line_len >= rl_line_buffer_len)
34421308Sache    rl_extend_line_buffer (line_len);
34521308Sache  strcpy (rl_line_buffer, temp->line);
34621308Sache  rl_undo_list = (UNDO_LIST *)temp->data;
34721308Sache  rl_end = line_len;
34821308Sache  return 0;
34921308Sache}
35021308Sache
35121308Sache/* Search forward in the history for the string of characters
35221308Sache   from the start of the line to rl_point.  This is a non-incremental
35321308Sache   search. */
35421308Sacheint
35521308Sacherl_history_search_forward (count, ignore)
35621308Sache     int count, ignore;
35721308Sache{
35821308Sache  if (count == 0)
35921308Sache    return (0);
36021308Sache  if (rl_last_func != rl_history_search_forward)
36121308Sache    prev_line_found = (char *)NULL;
36221308Sache  return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
36321308Sache}
36421308Sache
36521308Sache/* Search backward through the history for the string of characters
36621308Sache   from the start of the line to rl_point.  This is a non-incremental
36721308Sache   search. */
36821308Sacheint
36921308Sacherl_history_search_backward (count, ignore)
37021308Sache     int count, ignore;
37121308Sache{
37221308Sache  if (count == 0)
37321308Sache    return (0);
37421308Sache  if (rl_last_func != rl_history_search_backward)
37521308Sache    prev_line_found = (char *)NULL;
37621308Sache  return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
37721308Sache}
378