1 /* histsearch.c -- searching the history list. */
3 /* Copyright (C) 1989, 1992-2009,2017 Free Software Foundation, Inc.
5 This file contains the GNU History Library (History), a set of
6 routines for managing the text of previously typed lines.
8 History is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 History is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with History. If not, see <http://www.gnu.org/licenses/>.
22 #define READLINE_LIBRARY
24 #if defined (HAVE_CONFIG_H)
29 #if defined (HAVE_STDLIB_H)
32 # include "ansi_stdlib.h"
33 #endif /* HAVE_STDLIB_H */
35 #if defined (HAVE_UNISTD_H)
37 # include <sys/types.h>
42 #if defined (HAVE_FNMATCH)
50 /* The list of alternate characters that can delimit a history search
52 char *history_search_delimiter_chars = (char *)NULL;
54 static int history_search_internal PARAMS((const char *, int, int));
56 /* Search the history for STRING, starting at history_offset.
57 If DIRECTION < 0, then the search is through previous entries, else
58 through subsequent. If ANCHORED is non-zero, the string must
59 appear at the beginning of a history line, otherwise, the string
60 may appear anywhere in the line. If the string is found, then
61 current_history () is the history entry, and the value of this
62 function is the offset in the line of that history entry that the
63 string was found in. Otherwise, nothing is changed, and a -1 is
67 history_search_internal (const char *string, int direction, int flags)
69 register int i, reverse;
71 register int line_index;
72 int string_len, anchored, patsearch;
73 HIST_ENTRY **the_history; /* local */
76 reverse = (direction < 0);
77 anchored = (flags & ANCHORED_SEARCH);
78 #if defined (HAVE_FNMATCH)
79 patsearch = (flags & PATTERN_SEARCH);
84 /* Take care of trivial cases first. */
85 if (string == 0 || *string == '\0')
88 if (!history_length || ((i >= history_length) && !reverse))
91 if (reverse && (i >= history_length))
92 i = history_length - 1;
94 #define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
96 the_history = history_list ();
97 string_len = strlen (string);
100 /* Search each line in the history list for STRING. */
102 /* At limit for direction? */
103 if ((reverse && i < 0) || (!reverse && i == history_length))
106 line = the_history[i]->line;
107 line_index = strlen (line);
109 /* If STRING is longer than line, no match. */
110 if (patsearch == 0 && (string_len > line_index))
116 /* Handle anchored searches first. */
117 if (anchored == ANCHORED_SEARCH)
119 #if defined (HAVE_FNMATCH)
122 if (fnmatch (string, line, 0) == 0)
130 if (STREQN (string, line, string_len))
140 /* Do substring search. */
143 line_index -= (patsearch == 0) ? string_len : 1;
145 while (line_index >= 0)
147 #if defined (HAVE_FNMATCH)
150 if (fnmatch (string, line + line_index, 0) == 0)
158 if (STREQN (string, line + line_index, string_len))
170 limit = line_index - string_len + 1;
173 while (line_index < limit)
175 #if defined (HAVE_FNMATCH)
178 if (fnmatch (string, line + line_index, 0) == 0)
186 if (STREQN (string, line + line_index, string_len))
199 _hs_history_patsearch (const char *string, int direction, int flags)
203 int ret, unescaped_backslash;
205 #if defined (HAVE_FNMATCH)
206 /* Assume that the string passed does not have a leading `^' and any
207 anchored search request is captured in FLAGS */
208 len = strlen (string);
210 /* fnmatch is required to reject a pattern that ends with an unescaped
212 if (unescaped_backslash = (string[ret] == '\\'))
214 while (ret > 0 && string[--ret] == '\\')
215 unescaped_backslash = 1 - unescaped_backslash;
217 if (unescaped_backslash)
219 pat = (char *)xmalloc (len + 3);
220 /* If the search string is not anchored, we'll be calling fnmatch (assuming
221 we have it). Prefix a `*' to the front of the search string so we search
222 anywhere in the line. */
223 if ((flags & ANCHORED_SEARCH) == 0 && string[0] != '*')
234 /* Attempt to reduce the number of searches by tacking a `*' onto the end
235 of a pattern that doesn't have one. Assume a pattern that ends in a
236 backslash contains an even number of trailing backslashes; we check
238 strcpy (pat + start, string);
239 if (pat[len - 1] != '*')
241 pat[len] = '*'; /* XXX */
248 ret = history_search_internal (pat, direction, flags|PATTERN_SEARCH);
255 /* Do a non-anchored search for STRING through the history in DIRECTION. */
257 history_search (const char *string, int direction)
259 return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
262 /* Do an anchored search for string through the history in DIRECTION. */
264 history_search_prefix (const char *string, int direction)
266 return (history_search_internal (string, direction, ANCHORED_SEARCH));
269 /* Search for STRING in the history list. DIR is < 0 for searching
270 backwards. POS is an absolute index into the history list at
271 which point to begin searching. */
273 history_search_pos (const char *string, int dir, int pos)
277 old = where_history ();
278 history_set_pos (pos);
279 if (history_search (string, dir) == -1)
281 history_set_pos (old);
284 ret = where_history ();
285 history_set_pos (old);