194 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* histsearch.c -- searching the history list. */
 | |
| 
 | |
| /* Copyright (C) 1989, 1992-2009 Free Software Foundation, Inc.
 | |
| 
 | |
|    This file contains the GNU History Library (History), a set of
 | |
|    routines for managing the text of previously typed lines.
 | |
| 
 | |
|    History is free software: you can redistribute it and/or modify
 | |
|    it under the terms of the GNU General Public License as published by
 | |
|    the Free Software Foundation, either version 3 of the License, or
 | |
|    (at your option) any later version.
 | |
| 
 | |
|    History is distributed in the hope that it will be useful,
 | |
|    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|    GNU General Public License for more details.
 | |
| 
 | |
|    You should have received a copy of the GNU General Public License
 | |
|    along with History.  If not, see <http://www.gnu.org/licenses/>.
 | |
| */
 | |
| 
 | |
| #define READLINE_LIBRARY
 | |
| 
 | |
| #if defined (HAVE_CONFIG_H)
 | |
| #  include <config.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdio.h>
 | |
| #if defined (HAVE_STDLIB_H)
 | |
| #  include <stdlib.h>
 | |
| #else
 | |
| #  include "ansi_stdlib.h"
 | |
| #endif /* HAVE_STDLIB_H */
 | |
| 
 | |
| #if defined (HAVE_UNISTD_H)
 | |
| #  ifdef _MINIX
 | |
| #    include <sys/types.h>
 | |
| #  endif
 | |
| #  include <unistd.h>
 | |
| #endif
 | |
| 
 | |
| #include "history.h"
 | |
| #include "histlib.h"
 | |
| 
 | |
| /* The list of alternate characters that can delimit a history search
 | |
|    string. */
 | |
| char *history_search_delimiter_chars = (char *)NULL;
 | |
| 
 | |
| static int history_search_internal PARAMS((const char *, int, int));
 | |
| 
 | |
| /* Search the history for STRING, starting at history_offset.
 | |
|    If DIRECTION < 0, then the search is through previous entries, else
 | |
|    through subsequent.  If ANCHORED is non-zero, the string must
 | |
|    appear at the beginning of a history line, otherwise, the string
 | |
|    may appear anywhere in the line.  If the string is found, then
 | |
|    current_history () is the history entry, and the value of this
 | |
|    function is the offset in the line of that history entry that the
 | |
|    string was found in.  Otherwise, nothing is changed, and a -1 is
 | |
|    returned. */
 | |
| 
 | |
| static int
 | |
| history_search_internal (string, direction, anchored)
 | |
|      const char *string;
 | |
|      int direction, anchored;
 | |
| {
 | |
|   register int i, reverse;
 | |
|   register char *line;
 | |
|   register int line_index;
 | |
|   int string_len;
 | |
|   HIST_ENTRY **the_history; 	/* local */
 | |
| 
 | |
|   i = history_offset;
 | |
|   reverse = (direction < 0);
 | |
| 
 | |
|   /* Take care of trivial cases first. */
 | |
|   if (string == 0 || *string == '\0')
 | |
|     return (-1);
 | |
| 
 | |
|   if (!history_length || ((i >= history_length) && !reverse))
 | |
|     return (-1);
 | |
| 
 | |
|   if (reverse && (i >= history_length))
 | |
|     i = history_length - 1;
 | |
| 
 | |
| #define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
 | |
| 
 | |
|   the_history = history_list ();
 | |
|   string_len = strlen (string);
 | |
|   while (1)
 | |
|     {
 | |
|       /* Search each line in the history list for STRING. */
 | |
| 
 | |
|       /* At limit for direction? */
 | |
|       if ((reverse && i < 0) || (!reverse && i == history_length))
 | |
| 	return (-1);
 | |
| 
 | |
|       line = the_history[i]->line;
 | |
|       line_index = strlen (line);
 | |
| 
 | |
|       /* If STRING is longer than line, no match. */
 | |
|       if (string_len > line_index)
 | |
| 	{
 | |
| 	  NEXT_LINE ();
 | |
| 	  continue;
 | |
| 	}
 | |
| 
 | |
|       /* Handle anchored searches first. */
 | |
|       if (anchored == ANCHORED_SEARCH)
 | |
| 	{
 | |
| 	  if (STREQN (string, line, string_len))
 | |
| 	    {
 | |
| 	      history_offset = i;
 | |
| 	      return (0);
 | |
| 	    }
 | |
| 
 | |
| 	  NEXT_LINE ();
 | |
| 	  continue;
 | |
| 	}
 | |
| 
 | |
|       /* Do substring search. */
 | |
|       if (reverse)
 | |
| 	{
 | |
| 	  line_index -= string_len;
 | |
| 
 | |
| 	  while (line_index >= 0)
 | |
| 	    {
 | |
| 	      if (STREQN (string, line + line_index, string_len))
 | |
| 		{
 | |
| 		  history_offset = i;
 | |
| 		  return (line_index);
 | |
| 		}
 | |
| 	      line_index--;
 | |
| 	    }
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  register int limit;
 | |
| 
 | |
| 	  limit = line_index - string_len + 1;
 | |
| 	  line_index = 0;
 | |
| 
 | |
| 	  while (line_index < limit)
 | |
| 	    {
 | |
| 	      if (STREQN (string, line + line_index, string_len))
 | |
| 		{
 | |
| 		  history_offset = i;
 | |
| 		  return (line_index);
 | |
| 		}
 | |
| 	      line_index++;
 | |
| 	    }
 | |
| 	}
 | |
|       NEXT_LINE ();
 | |
|     }
 | |
| }
 | |
| 
 | |
| /* Do a non-anchored search for STRING through the history in DIRECTION. */
 | |
| int
 | |
| history_search (string, direction)
 | |
|      const char *string;
 | |
|      int direction;
 | |
| {
 | |
|   return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
 | |
| }
 | |
| 
 | |
| /* Do an anchored search for string through the history in DIRECTION. */
 | |
| int
 | |
| history_search_prefix (string, direction)
 | |
|      const char *string;
 | |
|      int direction;
 | |
| {
 | |
|   return (history_search_internal (string, direction, ANCHORED_SEARCH));
 | |
| }
 | |
| 
 | |
| /* Search for STRING in the history list.  DIR is < 0 for searching
 | |
|    backwards.  POS is an absolute index into the history list at
 | |
|    which point to begin searching. */
 | |
| int
 | |
| history_search_pos (string, dir, pos)
 | |
|      const char *string;
 | |
|      int dir, pos;
 | |
| {
 | |
|   int ret, old;
 | |
| 
 | |
|   old = where_history ();
 | |
|   history_set_pos (pos);
 | |
|   if (history_search (string, dir) == -1)
 | |
|     {
 | |
|       history_set_pos (old);
 | |
|       return (-1);
 | |
|     }
 | |
|   ret = where_history ();
 | |
|   history_set_pos (old);
 | |
|   return ret;
 | |
| }
 | 
