[readline] Fix compilation on MinGW
[deliverable/binutils-gdb.git] / readline / histsearch.c
1 /* histsearch.c -- searching the history list. */
2
3 /* Copyright (C) 1989, 1992-2009,2017 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 #if defined (HAVE_FNMATCH)
43 # include <fnmatch.h>
44 #endif
45
46 #include "history.h"
47 #include "histlib.h"
48 #include "xmalloc.h"
49
50 /* The list of alternate characters that can delimit a history search
51 string. */
52 char *history_search_delimiter_chars = (char *)NULL;
53
54 static int history_search_internal PARAMS((const char *, int, int));
55
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
64 returned. */
65
66 static int
67 history_search_internal (const char *string, int direction, int flags)
68 {
69 register int i, reverse;
70 register char *line;
71 register int line_index;
72 int string_len, anchored, patsearch;
73 HIST_ENTRY **the_history; /* local */
74
75 i = history_offset;
76 reverse = (direction < 0);
77 anchored = (flags & ANCHORED_SEARCH);
78 #if defined (HAVE_FNMATCH)
79 patsearch = (flags & PATTERN_SEARCH);
80 #else
81 patsearch = 0;
82 #endif
83
84 /* Take care of trivial cases first. */
85 if (string == 0 || *string == '\0')
86 return (-1);
87
88 if (!history_length || ((i >= history_length) && !reverse))
89 return (-1);
90
91 if (reverse && (i >= history_length))
92 i = history_length - 1;
93
94 #define NEXT_LINE() do { if (reverse) i--; else i++; } while (0)
95
96 the_history = history_list ();
97 string_len = strlen (string);
98 while (1)
99 {
100 /* Search each line in the history list for STRING. */
101
102 /* At limit for direction? */
103 if ((reverse && i < 0) || (!reverse && i == history_length))
104 return (-1);
105
106 line = the_history[i]->line;
107 line_index = strlen (line);
108
109 /* If STRING is longer than line, no match. */
110 if (patsearch == 0 && (string_len > line_index))
111 {
112 NEXT_LINE ();
113 continue;
114 }
115
116 /* Handle anchored searches first. */
117 if (anchored == ANCHORED_SEARCH)
118 {
119 #if defined (HAVE_FNMATCH)
120 if (patsearch)
121 {
122 if (fnmatch (string, line, 0) == 0)
123 {
124 history_offset = i;
125 return (0);
126 }
127 }
128 else
129 #endif
130 if (STREQN (string, line, string_len))
131 {
132 history_offset = i;
133 return (0);
134 }
135
136 NEXT_LINE ();
137 continue;
138 }
139
140 /* Do substring search. */
141 if (reverse)
142 {
143 line_index -= (patsearch == 0) ? string_len : 1;
144
145 while (line_index >= 0)
146 {
147 #if defined (HAVE_FNMATCH)
148 if (patsearch)
149 {
150 if (fnmatch (string, line + line_index, 0) == 0)
151 {
152 history_offset = i;
153 return (line_index);
154 }
155 }
156 else
157 #endif
158 if (STREQN (string, line + line_index, string_len))
159 {
160 history_offset = i;
161 return (line_index);
162 }
163 line_index--;
164 }
165 }
166 else
167 {
168 register int limit;
169
170 limit = line_index - string_len + 1;
171 line_index = 0;
172
173 while (line_index < limit)
174 {
175 #if defined (HAVE_FNMATCH)
176 if (patsearch)
177 {
178 if (fnmatch (string, line + line_index, 0) == 0)
179 {
180 history_offset = i;
181 return (line_index);
182 }
183 }
184 else
185 #endif
186 if (STREQN (string, line + line_index, string_len))
187 {
188 history_offset = i;
189 return (line_index);
190 }
191 line_index++;
192 }
193 }
194 NEXT_LINE ();
195 }
196 }
197
198 int
199 _hs_history_patsearch (const char *string, int direction, int flags)
200 {
201 char *pat;
202 size_t len, start;
203 int ret, unescaped_backslash;
204
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);
209 ret = len - 1;
210 /* fnmatch is required to reject a pattern that ends with an unescaped
211 backslash */
212 if (unescaped_backslash = (string[ret] == '\\'))
213 {
214 while (ret > 0 && string[--ret] == '\\')
215 unescaped_backslash = 1 - unescaped_backslash;
216 }
217 if (unescaped_backslash)
218 return -1;
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] != '*')
224 {
225 pat[0] = '*';
226 start = 1;
227 len++;
228 }
229 else
230 {
231 start = 0;
232 }
233
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
237 above */
238 strcpy (pat + start, string);
239 if (pat[len - 1] != '*')
240 {
241 pat[len] = '*'; /* XXX */
242 pat[len+1] = '\0';
243 }
244 #else
245 pat = string;
246 #endif
247
248 ret = history_search_internal (pat, direction, flags|PATTERN_SEARCH);
249
250 if (pat != string)
251 free (pat);
252 return ret;
253 }
254
255 /* Do a non-anchored search for STRING through the history in DIRECTION. */
256 int
257 history_search (const char *string, int direction)
258 {
259 return (history_search_internal (string, direction, NON_ANCHORED_SEARCH));
260 }
261
262 /* Do an anchored search for string through the history in DIRECTION. */
263 int
264 history_search_prefix (const char *string, int direction)
265 {
266 return (history_search_internal (string, direction, ANCHORED_SEARCH));
267 }
268
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. */
272 int
273 history_search_pos (const char *string, int dir, int pos)
274 {
275 int ret, old;
276
277 old = where_history ();
278 history_set_pos (pos);
279 if (history_search (string, dir) == -1)
280 {
281 history_set_pos (old);
282 return (-1);
283 }
284 ret = where_history ();
285 history_set_pos (old);
286 return ret;
287 }
This page took 0.056103 seconds and 4 git commands to generate.