No specific user configuration
[platform/upstream/bash.git] / lib / readline / histsearch.c
1 /* histsearch.c -- searching the history list. */
2
3 /* Copyright (C) 1989, 1992-2009 Free Software Foundation, Inc.
4
5    This file contains the GNU History Library (History), a set of
6    routines for managing the text of previously typed lines.
7
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.
12
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.
17
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/>.
20 */
21
22 #define READLINE_LIBRARY
23
24 #if defined (HAVE_CONFIG_H)
25 #  include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #if defined (HAVE_STDLIB_H)
30 #  include <stdlib.h>
31 #else
32 #  include "ansi_stdlib.h"
33 #endif /* HAVE_STDLIB_H */
34
35 #if defined (HAVE_UNISTD_H)
36 #  ifdef _MINIX
37 #    include <sys/types.h>
38 #  endif
39 #  include <unistd.h>
40 #endif
41
42 #include "history.h"
43 #include "histlib.h"
44
45 /* The list of alternate characters that can delimit a history search
46    string. */
47 char *history_search_delimiter_chars = (char *)NULL;
48
49 static int history_search_internal PARAMS((const char *, int, int));
50
51 /* Search the history for STRING, starting at history_offset.
52    If DIRECTION < 0, then the search is through previous entries, else
53    through subsequent.  If ANCHORED is non-zero, the string must
54    appear at the beginning of a history line, otherwise, the string
55    may appear anywhere in the line.  If the string is found, then
56    current_history () is the history entry, and the value of this
57    function is the offset in the line of that history entry that the
58    string was found in.  Otherwise, nothing is changed, and a -1 is
59    returned. */
60
61 static int
62 history_search_internal (string, direction, anchored)
63      const char *string;
64      int direction, anchored;
65 {
66   register int i, reverse;
67   register char *line;
68   register int line_index;
69   int string_len;
70   HIST_ENTRY **the_history;     /* local */
71
72   i = history_offset;
73   reverse = (direction < 0);
74
75   /* Take care of trivial cases first. */
76   if (string == 0 || *string == '\0')
77     return (-1);
78
79   if (!history_length || ((i >= history_length) && !reverse))
80     return (-1);
81
82   if (reverse && (i >= history_length))
83     i = history_length - 1;
84
85 #define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
86
87   the_history = history_list ();
88   string_len = strlen (string);
89   while (1)
90     {
91       /* Search each line in the history list for STRING. */
92
93       /* At limit for direction? */
94       if ((reverse && i < 0) || (!reverse && i == history_length))
95         return (-1);
96
97       line = the_history[i]->line;
98       line_index = strlen (line);
99
100       /* If STRING is longer than line, no match. */
101       if (string_len > line_index)
102         {
103           NEXT_LINE ();
104           continue;
105         }
106
107       /* Handle anchored searches first. */
108       if (anchored == ANCHORED_SEARCH)
109         {
110           if (STREQN (string, line, string_len))
111             {
112               history_offset = i;
113               return (0);
114             }
115
116           NEXT_LINE ();
117           continue;
118         }
119
120       /* Do substring search. */
121       if (reverse)
122         {
123           line_index -= string_len;
124
125           while (line_index >= 0)
126             {
127               if (STREQN (string, line + line_index, string_len))
128                 {
129                   history_offset = i;
130                   return (line_index);
131                 }
132               line_index--;
133             }
134         }
135       else
136         {
137           register int limit;
138
139           limit = line_index - string_len + 1;
140           line_index = 0;
141
142           while (line_index < limit)
143             {
144               if (STREQN (string, line + line_index, string_len))
145                 {
146                   history_offset = i;
147                   return (line_index);
148                 }
149               line_index++;
150             }
151         }
152       NEXT_LINE ();
153     }
154 }
155
156 /* Do a non-anchored search for STRING through the history in DIRECTION. */
157 int
158 history_search (string, direction)
159      const char *string;
160      int direction;
161 {
162   return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
163 }
164
165 /* Do an anchored search for string through the history in DIRECTION. */
166 int
167 history_search_prefix (string, direction)
168      const char *string;
169      int direction;
170 {
171   return (history_search_internal (string, direction, ANCHORED_SEARCH));
172 }
173
174 /* Search for STRING in the history list.  DIR is < 0 for searching
175    backwards.  POS is an absolute index into the history list at
176    which point to begin searching. */
177 int
178 history_search_pos (string, dir, pos)
179      const char *string;
180      int dir, pos;
181 {
182   int ret, old;
183
184   old = where_history ();
185   history_set_pos (pos);
186   if (history_search (string, dir) == -1)
187     {
188       history_set_pos (old);
189       return (-1);
190     }
191   ret = where_history ();
192   history_set_pos (old);
193   return ret;
194 }