histsearch.c revision 21308
121308Sache/* histsearch.c -- searching the history list. */
221308Sache
321308Sache/* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
421308Sache
521308Sache   This file contains the GNU History Library (the Library), a set of
621308Sache   routines for managing the text of previously typed lines.
721308Sache
821308Sache   The Library is free software; you can redistribute it and/or modify
921308Sache   it under the terms of the GNU General Public License as published by
1021308Sache   the Free Software Foundation; either version 1, or (at your option)
1121308Sache   any later version.
1221308Sache
1321308Sache   The Library is distributed in the hope that it will be useful, but
1421308Sache   WITHOUT ANY WARRANTY; without even the implied warranty of
1521308Sache   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1621308Sache   General Public License for more details.
1721308Sache
1821308Sache   The GNU General Public License is often shipped with GNU software, and
1921308Sache   is generally kept in a file called COPYING or LICENSE.  If you do not
2021308Sache   have a copy of the license, write to the Free Software Foundation,
2121308Sache   675 Mass Ave, Cambridge, MA 02139, USA. */
2221308Sache
2321308Sache#define READLINE_LIBRARY
2421308Sache
2521308Sache#if defined (HAVE_CONFIG_H)
2621308Sache#  include <config.h>
2721308Sache#endif
2821308Sache
2921308Sache#include <stdio.h>
3021308Sache#if defined (HAVE_STDLIB_H)
3121308Sache#  include <stdlib.h>
3221308Sache#else
3321308Sache#  include "ansi_stdlib.h"
3421308Sache#endif /* HAVE_STDLIB_H */
3521308Sache#if defined (HAVE_UNISTD_H)
3621308Sache#  include <unistd.h>
3721308Sache#endif
3821308Sache#if defined (HAVE_STRING_H)
3921308Sache#  include <string.h>
4021308Sache#else
4121308Sache#  include <strings.h>
4221308Sache#endif /* !HAVE_STRING_H */
4321308Sache
4421308Sache#include "history.h"
4521308Sache#include "histlib.h"
4621308Sache
4721308Sache/* Variables imported from other history library files. */
4821308Sacheextern int history_offset;
4921308Sache
5021308Sache/* The list of alternate characters that can delimit a history search
5121308Sache   string. */
5221308Sachechar *history_search_delimiter_chars = (char *)NULL;
5321308Sache
5421308Sache/* Search the history for STRING, starting at history_offset.
5521308Sache   If DIRECTION < 0, then the search is through previous entries, else
5621308Sache   through subsequent.  If ANCHORED is non-zero, the string must
5721308Sache   appear at the beginning of a history line, otherwise, the string
5821308Sache   may appear anywhere in the line.  If the string is found, then
5921308Sache   current_history () is the history entry, and the value of this
6021308Sache   function is the offset in the line of that history entry that the
6121308Sache   string was found in.  Otherwise, nothing is changed, and a -1 is
6221308Sache   returned. */
6321308Sache
6421308Sachestatic int
6521308Sachehistory_search_internal (string, direction, anchored)
6621308Sache     char *string;
6721308Sache     int direction, anchored;
6821308Sache{
6921308Sache  register int i, reverse;
7021308Sache  register char *line;
7121308Sache  register int line_index;
7221308Sache  int string_len;
7321308Sache  HIST_ENTRY **the_history; 	/* local */
7421308Sache
7521308Sache  i = history_offset;
7621308Sache  reverse = (direction < 0);
7721308Sache
7821308Sache  /* Take care of trivial cases first. */
7921308Sache  if (string == 0 || *string == '\0')
8021308Sache    return (-1);
8121308Sache
8221308Sache  if (!history_length || ((i == history_length) && !reverse))
8321308Sache    return (-1);
8421308Sache
8521308Sache  if (reverse && (i == history_length))
8621308Sache    i--;
8721308Sache
8821308Sache#define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
8921308Sache
9021308Sache  the_history = history_list ();
9121308Sache  string_len = strlen (string);
9221308Sache  while (1)
9321308Sache    {
9421308Sache      /* Search each line in the history list for STRING. */
9521308Sache
9621308Sache      /* At limit for direction? */
9721308Sache      if ((reverse && i < 0) || (!reverse && i == history_length))
9821308Sache	return (-1);
9921308Sache
10021308Sache      line = the_history[i]->line;
10121308Sache      line_index = strlen (line);
10221308Sache
10321308Sache      /* If STRING is longer than line, no match. */
10421308Sache      if (string_len > line_index)
10521308Sache	{
10621308Sache	  NEXT_LINE ();
10721308Sache	  continue;
10821308Sache	}
10921308Sache
11021308Sache      /* Handle anchored searches first. */
11121308Sache      if (anchored == ANCHORED_SEARCH)
11221308Sache	{
11321308Sache	  if (STREQN (string, line, string_len))
11421308Sache	    {
11521308Sache	      history_offset = i;
11621308Sache	      return (0);
11721308Sache	    }
11821308Sache
11921308Sache	  NEXT_LINE ();
12021308Sache	  continue;
12121308Sache	}
12221308Sache
12321308Sache      /* Do substring search. */
12421308Sache      if (reverse)
12521308Sache	{
12621308Sache	  line_index -= string_len;
12721308Sache
12821308Sache	  while (line_index >= 0)
12921308Sache	    {
13021308Sache	      if (STREQN (string, line + line_index, string_len))
13121308Sache		{
13221308Sache		  history_offset = i;
13321308Sache		  return (line_index);
13421308Sache		}
13521308Sache	      line_index--;
13621308Sache	    }
13721308Sache	}
13821308Sache      else
13921308Sache	{
14021308Sache	  register int limit;
14121308Sache
14221308Sache	  limit = line_index - string_len + 1;
14321308Sache	  line_index = 0;
14421308Sache
14521308Sache	  while (line_index < limit)
14621308Sache	    {
14721308Sache	      if (STREQN (string, line + line_index, string_len))
14821308Sache		{
14921308Sache		  history_offset = i;
15021308Sache		  return (line_index);
15121308Sache		}
15221308Sache	      line_index++;
15321308Sache	    }
15421308Sache	}
15521308Sache      NEXT_LINE ();
15621308Sache    }
15721308Sache}
15821308Sache
15921308Sache/* Do a non-anchored search for STRING through the history in DIRECTION. */
16021308Sacheint
16121308Sachehistory_search (string, direction)
16221308Sache     char *string;
16321308Sache     int direction;
16421308Sache{
16521308Sache  return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
16621308Sache}
16721308Sache
16821308Sache/* Do an anchored search for string through the history in DIRECTION. */
16921308Sacheint
17021308Sachehistory_search_prefix (string, direction)
17121308Sache     char *string;
17221308Sache     int direction;
17321308Sache{
17421308Sache  return (history_search_internal (string, direction, ANCHORED_SEARCH));
17521308Sache}
17621308Sache
17721308Sache/* Search for STRING in the history list.  DIR is < 0 for searching
17821308Sache   backwards.  POS is an absolute index into the history list at
17921308Sache   which point to begin searching. */
18021308Sacheint
18121308Sachehistory_search_pos (string, dir, pos)
18221308Sache     char *string;
18321308Sache     int dir, pos;
18421308Sache{
18521308Sache  int ret, old;
18621308Sache
18721308Sache  old = where_history ();
18821308Sache  history_set_pos (pos);
18921308Sache  if (history_search (string, dir) == -1)
19021308Sache    {
19121308Sache      history_set_pos (old);
19221308Sache      return (-1);
19321308Sache    }
19421308Sache  ret = where_history ();
19521308Sache  history_set_pos (old);
19621308Sache  return ret;
19721308Sache}
198