]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - readline/isearch.c
7decf9595b0f5aed3a50c7d95ae4882b57dc9aef
[thirdparty/binutils-gdb.git] / readline / isearch.c
1 /* **************************************************************** */
2 /* */
3 /* I-Search and Searching */
4 /* */
5 /* **************************************************************** */
6
7 /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
8
9 This file contains the Readline Library (the Library), a set of
10 routines for providing Emacs style line input to programs that ask
11 for it.
12
13 The Library is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 1, or (at your option)
16 any later version.
17
18 The Library is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 The GNU General Public License is often shipped with GNU software, and
24 is generally kept in a file called COPYING or LICENSE. If you do not
25 have a copy of the license, write to the Free Software Foundation,
26 675 Mass Ave, Cambridge, MA 02139, USA. */
27 #define READLINE_LIBRARY
28
29 #if defined (HAVE_CONFIG_H)
30 # include <config.h>
31 #endif
32
33 #include <sys/types.h>
34
35 #include <stdio.h>
36
37 #if defined (HAVE_UNISTD_H)
38 # include <unistd.h>
39 #endif
40
41 #if defined (HAVE_STDLIB_H)
42 # include <stdlib.h>
43 #else
44 # include "ansi_stdlib.h"
45 #endif
46
47 #include "rldefs.h"
48 #include "readline.h"
49 #include "history.h"
50
51 /* Variables imported from other files in the readline library. */
52 extern Keymap _rl_keymap;
53 extern HIST_ENTRY *saved_line_for_history;
54 extern int rl_line_buffer_len;
55 extern int rl_point, rl_end;
56 extern char *rl_line_buffer;
57
58 extern void _rl_save_prompt ();
59 extern void _rl_restore_prompt ();
60
61 extern int rl_execute_next ();
62 extern void rl_extend_line_buffer ();
63
64 extern int _rl_input_available ();
65
66 extern char *xmalloc (), *xrealloc ();
67
68 static int rl_search_history ();
69
70 /* Last line found by the current incremental search, so we don't `find'
71 identical lines many times in a row. */
72 static char *prev_line_found;
73
74 /* Search backwards through the history looking for a string which is typed
75 interactively. Start with the current line. */
76 int
77 rl_reverse_search_history (sign, key)
78 int sign, key;
79 {
80 return (rl_search_history (-sign, key));
81 }
82
83 /* Search forwards through the history looking for a string which is typed
84 interactively. Start with the current line. */
85 int
86 rl_forward_search_history (sign, key)
87 int sign, key;
88 {
89 return (rl_search_history (sign, key));
90 }
91
92 /* Display the current state of the search in the echo-area.
93 SEARCH_STRING contains the string that is being searched for,
94 DIRECTION is zero for forward, or 1 for reverse,
95 WHERE is the history list number of the current line. If it is
96 -1, then this line is the starting one. */
97 static void
98 rl_display_search (search_string, reverse_p, where)
99 char *search_string;
100 int reverse_p, where;
101 {
102 char *message;
103 int msglen, searchlen;
104
105 searchlen = (search_string && *search_string) ? strlen (search_string) : 0;
106
107 message = xmalloc (searchlen + 33);
108 msglen = 0;
109
110 #if defined (NOTDEF)
111 if (where != -1)
112 {
113 sprintf (message, "[%d]", where + history_base);
114 msglen = strlen (message);
115 }
116 #endif /* NOTDEF */
117
118 message[msglen++] = '(';
119
120 if (reverse_p)
121 {
122 strcpy (message + msglen, "reverse-");
123 msglen += 8;
124 }
125
126 strcpy (message + msglen, "i-search)`");
127 msglen += 10;
128
129 if (search_string)
130 {
131 strcpy (message + msglen, search_string);
132 msglen += searchlen;
133 }
134
135 strcpy (message + msglen, "': ");
136
137 rl_message ("%s", message, 0);
138 free (message);
139 (*rl_redisplay_function) ();
140 }
141
142 /* Search through the history looking for an interactively typed string.
143 This is analogous to i-search. We start the search in the current line.
144 DIRECTION is which direction to search; >= 0 means forward, < 0 means
145 backwards. */
146 static int
147 rl_search_history (direction, invoking_key)
148 int direction, invoking_key;
149 {
150 /* The string that the user types in to search for. */
151 char *search_string;
152
153 /* The current length of SEARCH_STRING. */
154 int search_string_index;
155
156 /* The amount of space that SEARCH_STRING has allocated to it. */
157 int search_string_size;
158
159 /* The list of lines to search through. */
160 char **lines, *allocated_line;
161
162 /* The length of LINES. */
163 int hlen;
164
165 /* Where we get LINES from. */
166 HIST_ENTRY **hlist;
167
168 register int i;
169 int orig_point, orig_line, last_found_line;
170 int c, found, failed, sline_len;
171
172 /* The line currently being searched. */
173 char *sline;
174
175 /* Offset in that line. */
176 int line_index;
177
178 /* Non-zero if we are doing a reverse search. */
179 int reverse;
180
181 orig_point = rl_point;
182 last_found_line = orig_line = where_history ();
183 reverse = direction < 0;
184 hlist = history_list ();
185 allocated_line = (char *)NULL;
186
187 /* Create an arrary of pointers to the lines that we want to search. */
188 maybe_replace_line ();
189 i = 0;
190 if (hlist)
191 for (i = 0; hlist[i]; i++);
192
193 /* Allocate space for this many lines, +1 for the current input line,
194 and remember those lines. */
195 lines = (char **)xmalloc ((1 + (hlen = i)) * sizeof (char *));
196 for (i = 0; i < hlen; i++)
197 lines[i] = hlist[i]->line;
198
199 if (saved_line_for_history)
200 lines[i] = saved_line_for_history->line;
201 else
202 {
203 /* Keep track of this so we can free it. */
204 allocated_line = xmalloc (1 + strlen (rl_line_buffer));
205 strcpy (allocated_line, &rl_line_buffer[0]);
206 lines[i] = allocated_line;
207 }
208
209 hlen++;
210
211 /* The line where we start the search. */
212 i = orig_line;
213
214 _rl_save_prompt ();
215
216 /* Initialize search parameters. */
217 search_string = xmalloc (search_string_size = 128);
218 *search_string = '\0';
219 search_string_index = 0;
220 prev_line_found = (char *)0; /* XXX */
221
222 /* Normalize DIRECTION into 1 or -1. */
223 direction = (direction >= 0) ? 1 : -1;
224
225 rl_display_search (search_string, reverse, -1);
226
227 sline = rl_line_buffer;
228 sline_len = strlen (sline);
229 line_index = rl_point;
230
231 found = failed = 0;
232 for (;;)
233 {
234 Function *f = (Function *)NULL;
235
236 /* Read a key and decide how to proceed. */
237 c = rl_read_key ();
238
239 if (_rl_keymap[c].type == ISFUNC)
240 {
241 f = _rl_keymap[c].function;
242
243 if (f == rl_reverse_search_history)
244 c = reverse ? -1 : -2;
245 else if (f == rl_forward_search_history)
246 c = !reverse ? -1 : -2;
247 }
248
249 /* Let NEWLINE (^J) terminate the search for people who don't like
250 using ESC. ^M can still be used to terminate the search and
251 immediately execute the command. */
252 if (c == ESC || c == NEWLINE)
253 {
254 /* ESC still terminates the search, but if there is pending
255 input or if input arrives within 0.1 seconds (on systems
256 with select(2)) it is used as a prefix character
257 with rl_execute_next. WATCH OUT FOR THIS! This is intended
258 to allow the arrow keys to be used like ^F and ^B are used
259 to terminate the search and execute the movement command. */
260 if (c == ESC && _rl_input_available ()) /* XXX */
261 rl_execute_next (ESC);
262 break;
263 }
264
265 if (c >= 0 && (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT) && c != CTRL ('G'))
266 {
267 rl_execute_next (c);
268 break;
269 }
270
271 switch (c)
272 {
273 case -1:
274 if (search_string_index == 0)
275 continue;
276 else if (reverse)
277 --line_index;
278 else if (line_index != sline_len)
279 ++line_index;
280 else
281 ding ();
282 break;
283
284 /* switch directions */
285 case -2:
286 direction = -direction;
287 reverse = direction < 0;
288 break;
289
290 case CTRL ('G'):
291 strcpy (rl_line_buffer, lines[orig_line]);
292 rl_point = orig_point;
293 rl_end = strlen (rl_line_buffer);
294 _rl_restore_prompt();
295 rl_clear_message ();
296 if (allocated_line)
297 free (allocated_line);
298 free (lines);
299 return 0;
300
301 #if 0
302 /* delete character from search string. */
303 case -3:
304 if (search_string_index == 0)
305 ding ();
306 else
307 {
308 search_string[--search_string_index] = '\0';
309 /* This is tricky. To do this right, we need to keep a
310 stack of search positions for the current search, with
311 sentinels marking the beginning and end. */
312 }
313 break;
314 #endif
315
316 default:
317 /* Add character to search string and continue search. */
318 if (search_string_index + 2 >= search_string_size)
319 {
320 search_string_size += 128;
321 search_string = xrealloc (search_string, search_string_size);
322 }
323 search_string[search_string_index++] = c;
324 search_string[search_string_index] = '\0';
325 break;
326 }
327
328 for (found = failed = 0;;)
329 {
330 int limit = sline_len - search_string_index + 1;
331
332 /* Search the current line. */
333 while (reverse ? (line_index >= 0) : (line_index < limit))
334 {
335 if (STREQN (search_string, sline + line_index, search_string_index))
336 {
337 found++;
338 break;
339 }
340 else
341 line_index += direction;
342 }
343 if (found)
344 break;
345
346 /* Move to the next line, but skip new copies of the line
347 we just found and lines shorter than the string we're
348 searching for. */
349 do
350 {
351 /* Move to the next line. */
352 i += direction;
353
354 /* At limit for direction? */
355 if (reverse ? (i < 0) : (i == hlen))
356 {
357 failed++;
358 break;
359 }
360
361 /* We will need these later. */
362 sline = lines[i];
363 sline_len = strlen (sline);
364 }
365 while ((prev_line_found && STREQ (prev_line_found, lines[i])) ||
366 (search_string_index > sline_len));
367
368 if (failed)
369 break;
370
371 /* Now set up the line for searching... */
372 line_index = reverse ? sline_len - search_string_index : 0;
373 }
374
375 if (failed)
376 {
377 /* We cannot find the search string. Ding the bell. */
378 ding ();
379 i = last_found_line;
380 continue; /* XXX - was break */
381 }
382
383 /* We have found the search string. Just display it. But don't
384 actually move there in the history list until the user accepts
385 the location. */
386 if (found)
387 {
388 int line_len;
389
390 prev_line_found = lines[i];
391 line_len = strlen (lines[i]);
392
393 if (line_len >= rl_line_buffer_len)
394 rl_extend_line_buffer (line_len);
395
396 strcpy (rl_line_buffer, lines[i]);
397 rl_point = line_index;
398 rl_end = line_len;
399 last_found_line = i;
400 rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i);
401 }
402 }
403
404 /* The searching is over. The user may have found the string that she
405 was looking for, or else she may have exited a failing search. If
406 LINE_INDEX is -1, then that shows that the string searched for was
407 not found. We use this to determine where to place rl_point. */
408
409 /* First put back the original state. */
410 strcpy (rl_line_buffer, lines[orig_line]);
411
412 _rl_restore_prompt ();
413
414 /* Free the search string. */
415 free (search_string);
416
417 if (last_found_line < orig_line)
418 rl_get_previous_history (orig_line - last_found_line);
419 else
420 rl_get_next_history (last_found_line - orig_line);
421
422 /* If the string was not found, put point at the end of the line. */
423 if (line_index < 0)
424 line_index = strlen (rl_line_buffer);
425 rl_point = line_index;
426 rl_clear_message ();
427
428 if (allocated_line)
429 free (allocated_line);
430 free (lines);
431
432 return 0;
433 }