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
1058310Sache   the Free Software Foundation; either version 2, 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,
2158310Sache   59 Temple Place, Suite 330, Boston, MA 02111 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 */
35119610Sache
3621308Sache#if defined (HAVE_UNISTD_H)
3735486Sache#  ifdef _MINIX
3835486Sache#    include <sys/types.h>
3935486Sache#  endif
4021308Sache#  include <unistd.h>
4121308Sache#endif
4221308Sache
4321308Sache#include "history.h"
4421308Sache#include "histlib.h"
4521308Sache
4621308Sache/* The list of alternate characters that can delimit a history search
4721308Sache   string. */
4821308Sachechar *history_search_delimiter_chars = (char *)NULL;
4921308Sache
50119610Sachestatic int history_search_internal PARAMS((const char *, int, int));
51119610Sache
5221308Sache/* Search the history for STRING, starting at history_offset.
5321308Sache   If DIRECTION < 0, then the search is through previous entries, else
5421308Sache   through subsequent.  If ANCHORED is non-zero, the string must
5521308Sache   appear at the beginning of a history line, otherwise, the string
5621308Sache   may appear anywhere in the line.  If the string is found, then
5721308Sache   current_history () is the history entry, and the value of this
5821308Sache   function is the offset in the line of that history entry that the
5921308Sache   string was found in.  Otherwise, nothing is changed, and a -1 is
6021308Sache   returned. */
6121308Sache
6221308Sachestatic int
6321308Sachehistory_search_internal (string, direction, anchored)
6475406Sache     const char *string;
6521308Sache     int direction, anchored;
6621308Sache{
6721308Sache  register int i, reverse;
6821308Sache  register char *line;
6921308Sache  register int line_index;
7021308Sache  int string_len;
7121308Sache  HIST_ENTRY **the_history; 	/* local */
7221308Sache
7321308Sache  i = history_offset;
7421308Sache  reverse = (direction < 0);
7521308Sache
7621308Sache  /* Take care of trivial cases first. */
7721308Sache  if (string == 0 || *string == '\0')
7821308Sache    return (-1);
7921308Sache
80136644Sache  if (!history_length || ((i >= history_length) && !reverse))
8121308Sache    return (-1);
8221308Sache
83136644Sache  if (reverse && (i >= history_length))
84136644Sache    i = history_length - 1;
8521308Sache
8621308Sache#define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
8721308Sache
8821308Sache  the_history = history_list ();
8921308Sache  string_len = strlen (string);
9021308Sache  while (1)
9121308Sache    {
9221308Sache      /* Search each line in the history list for STRING. */
9321308Sache
9421308Sache      /* At limit for direction? */
9521308Sache      if ((reverse && i < 0) || (!reverse && i == history_length))
9621308Sache	return (-1);
9721308Sache
9821308Sache      line = the_history[i]->line;
9921308Sache      line_index = strlen (line);
10021308Sache
10121308Sache      /* If STRING is longer than line, no match. */
10221308Sache      if (string_len > line_index)
10321308Sache	{
10421308Sache	  NEXT_LINE ();
10521308Sache	  continue;
10621308Sache	}
10721308Sache
10821308Sache      /* Handle anchored searches first. */
10921308Sache      if (anchored == ANCHORED_SEARCH)
11021308Sache	{
11121308Sache	  if (STREQN (string, line, string_len))
11221308Sache	    {
11321308Sache	      history_offset = i;
11421308Sache	      return (0);
11521308Sache	    }
11621308Sache
11721308Sache	  NEXT_LINE ();
11821308Sache	  continue;
11921308Sache	}
12021308Sache
12121308Sache      /* Do substring search. */
12221308Sache      if (reverse)
12321308Sache	{
12421308Sache	  line_index -= string_len;
12521308Sache
12621308Sache	  while (line_index >= 0)
12721308Sache	    {
12821308Sache	      if (STREQN (string, line + line_index, string_len))
12921308Sache		{
13021308Sache		  history_offset = i;
13121308Sache		  return (line_index);
13221308Sache		}
13321308Sache	      line_index--;
13421308Sache	    }
13521308Sache	}
13621308Sache      else
13721308Sache	{
13821308Sache	  register int limit;
13921308Sache
14021308Sache	  limit = line_index - string_len + 1;
14121308Sache	  line_index = 0;
14221308Sache
14321308Sache	  while (line_index < limit)
14421308Sache	    {
14521308Sache	      if (STREQN (string, line + line_index, string_len))
14621308Sache		{
14721308Sache		  history_offset = i;
14821308Sache		  return (line_index);
14921308Sache		}
15021308Sache	      line_index++;
15121308Sache	    }
15221308Sache	}
15321308Sache      NEXT_LINE ();
15421308Sache    }
15521308Sache}
15621308Sache
15721308Sache/* Do a non-anchored search for STRING through the history in DIRECTION. */
15821308Sacheint
15921308Sachehistory_search (string, direction)
16075406Sache     const char *string;
16121308Sache     int direction;
16221308Sache{
16321308Sache  return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
16421308Sache}
16521308Sache
16621308Sache/* Do an anchored search for string through the history in DIRECTION. */
16721308Sacheint
16821308Sachehistory_search_prefix (string, direction)
16975406Sache     const char *string;
17021308Sache     int direction;
17121308Sache{
17221308Sache  return (history_search_internal (string, direction, ANCHORED_SEARCH));
17321308Sache}
17421308Sache
17521308Sache/* Search for STRING in the history list.  DIR is < 0 for searching
17621308Sache   backwards.  POS is an absolute index into the history list at
17721308Sache   which point to begin searching. */
17821308Sacheint
17921308Sachehistory_search_pos (string, dir, pos)
18075406Sache     const char *string;
18121308Sache     int dir, pos;
18221308Sache{
18321308Sache  int ret, old;
18421308Sache
18521308Sache  old = where_history ();
18621308Sache  history_set_pos (pos);
18721308Sache  if (history_search (string, dir) == -1)
18821308Sache    {
18921308Sache      history_set_pos (old);
19021308Sache      return (-1);
19121308Sache    }
19221308Sache  ret = where_history ();
19321308Sache  history_set_pos (old);
19421308Sache  return ret;
19521308Sache}
196