| /* 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; |
| } |