import gdb-1999-08-02 snapshot
[binutils-gdb.git] / readline / search.c
1 /* search.c - code for non-incremental searching in emacs and vi modes. */
2
3 /* Copyright (C) 1992 Free Software Foundation, Inc.
4
5 This file is part of the Readline Library (the Library), a set of
6 routines for providing Emacs style line input to programs that ask
7 for it.
8
9 The Library is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 1, or (at your option)
12 any later version.
13
14 The Library is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 The GNU General Public License is often shipped with GNU software, and
20 is generally kept in a file called COPYING or LICENSE. If you do not
21 have a copy of the license, write to the Free Software Foundation,
22 675 Mass Ave, Cambridge, MA 02139, USA. */
23 #define READLINE_LIBRARY
24
25 #if defined (HAVE_CONFIG_H)
26 # include <config.h>
27 #endif
28
29 #include <sys/types.h>
30 #include <stdio.h>
31
32 #if defined (HAVE_UNISTD_H)
33 # include <unistd.h>
34 #endif
35
36 #if defined (HAVE_STDLIB_H)
37 # include <stdlib.h>
38 #else
39 # include "ansi_stdlib.h"
40 #endif
41
42 #include "rldefs.h"
43 #include "readline.h"
44 #include "history.h"
45
46 #ifdef abs
47 # undef abs
48 #endif
49 #define abs(x) (((x) >= 0) ? (x) : -(x))
50
51 extern char *xmalloc (), *xrealloc ();
52
53 /* Variables imported from readline.c */
54 extern int rl_point, rl_end, rl_line_buffer_len;
55 extern int rl_editing_mode;
56 extern char *rl_prompt;
57 extern char *rl_line_buffer;
58 extern HIST_ENTRY *saved_line_for_history;
59 extern Function *rl_last_func;
60
61 /* Functions imported from the rest of the library. */
62 extern int _rl_free_history_entry ();
63 extern char *_rl_make_prompt_for_search ();
64 extern void rl_extend_line_buffer ();
65
66 static char *noninc_search_string = (char *) NULL;
67 static int noninc_history_pos;
68 static char *prev_line_found = (char *) NULL;
69
70 /* Search the history list for STRING starting at absolute history position
71 POS. If STRING begins with `^', the search must match STRING at the
72 beginning of a history line, otherwise a full substring match is performed
73 for STRING. DIR < 0 means to search backwards through the history list,
74 DIR >= 0 means to search forward. */
75 static int
76 noninc_search_from_pos (string, pos, dir)
77 char *string;
78 int pos, dir;
79 {
80 int ret, old;
81
82 old = where_history ();
83 history_set_pos (pos);
84
85 if (*string == '^')
86 ret = history_search_prefix (string + 1, dir);
87 else
88 ret = history_search (string, dir);
89
90 if (ret != -1)
91 ret = where_history ();
92
93 history_set_pos (old);
94 return (ret);
95 }
96
97 /* Search for a line in the history containing STRING. If DIR is < 0, the
98 search is backwards through previous entries, else through subsequent
99 entries. */
100 static void
101 noninc_dosearch (string, dir)
102 char *string;
103 int dir;
104 {
105 int oldpos, pos, line_len;
106 HIST_ENTRY *entry;
107
108 if (string == 0 || *string == '\0' || noninc_history_pos < 0)
109 {
110 ding ();
111 return;
112 }
113
114 pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
115 if (pos == -1)
116 {
117 /* Search failed, current history position unchanged. */
118 maybe_unsave_line ();
119 rl_clear_message ();
120 rl_point = 0;
121 ding ();
122 return;
123 }
124
125 noninc_history_pos = pos;
126
127 oldpos = where_history ();
128 history_set_pos (noninc_history_pos);
129 entry = current_history ();
130 #if defined (VI_MODE)
131 if (rl_editing_mode != vi_mode)
132 #endif
133 history_set_pos (oldpos);
134
135 line_len = strlen (entry->line);
136 if (line_len >= rl_line_buffer_len)
137 rl_extend_line_buffer (line_len);
138 strcpy (rl_line_buffer, entry->line);
139
140 rl_undo_list = (UNDO_LIST *)entry->data;
141 rl_end = strlen (rl_line_buffer);
142 rl_point = 0;
143 rl_clear_message ();
144
145 if (saved_line_for_history)
146 _rl_free_history_entry (saved_line_for_history);
147 saved_line_for_history = (HIST_ENTRY *)NULL;
148 }
149
150 /* Search non-interactively through the history list. DIR < 0 means to
151 search backwards through the history of previous commands; otherwise
152 the search is for commands subsequent to the current position in the
153 history list. PCHAR is the character to use for prompting when reading
154 the search string; if not specified (0), it defaults to `:'. */
155 static void
156 noninc_search (dir, pchar)
157 int dir;
158 int pchar;
159 {
160 int saved_point, c;
161 char *p;
162
163 maybe_save_line ();
164 saved_point = rl_point;
165
166 /* Use the line buffer to read the search string. */
167 rl_line_buffer[0] = 0;
168 rl_end = rl_point = 0;
169
170 p = _rl_make_prompt_for_search (pchar ? pchar : ':');
171 rl_message (p, 0, 0);
172 free (p);
173
174 #define SEARCH_RETURN rl_restore_prompt (); return
175
176 /* Read the search string. */
177 while (c = rl_read_key ())
178 {
179 switch (c)
180 {
181 case CTRL('H'):
182 case RUBOUT:
183 if (rl_point == 0)
184 {
185 maybe_unsave_line ();
186 rl_clear_message ();
187 rl_point = saved_point;
188 SEARCH_RETURN;
189 }
190 rl_rubout (1, c);
191 break;
192
193 case CTRL('W'):
194 rl_unix_word_rubout (1, c);
195 break;
196
197 case CTRL('U'):
198 rl_unix_line_discard (1, c);
199 break;
200
201 case RETURN:
202 case NEWLINE:
203 goto dosearch;
204 /* NOTREACHED */
205 break;
206
207 case CTRL('C'):
208 case CTRL('G'):
209 maybe_unsave_line ();
210 rl_clear_message ();
211 rl_point = saved_point;
212 ding ();
213 SEARCH_RETURN;
214
215 default:
216 rl_insert (1, c);
217 break;
218 }
219 (*rl_redisplay_function) ();
220 }
221
222 dosearch:
223 /* If rl_point == 0, we want to re-use the previous search string and
224 start from the saved history position. If there's no previous search
225 string, punt. */
226 if (rl_point == 0)
227 {
228 if (!noninc_search_string)
229 {
230 ding ();
231 SEARCH_RETURN;
232 }
233 }
234 else
235 {
236 /* We want to start the search from the current history position. */
237 noninc_history_pos = where_history ();
238 if (noninc_search_string)
239 free (noninc_search_string);
240 noninc_search_string = savestring (rl_line_buffer);
241 }
242
243 rl_restore_prompt ();
244 noninc_dosearch (noninc_search_string, dir);
245 }
246
247 /* Search forward through the history list for a string. If the vi-mode
248 code calls this, KEY will be `?'. */
249 int
250 rl_noninc_forward_search (count, key)
251 int count, key;
252 {
253 noninc_search (1, (key == '?') ? '?' : 0);
254 return 0;
255 }
256
257 /* Reverse search the history list for a string. If the vi-mode code
258 calls this, KEY will be `/'. */
259 int
260 rl_noninc_reverse_search (count, key)
261 int count, key;
262 {
263 noninc_search (-1, (key == '/') ? '/' : 0);
264 return 0;
265 }
266
267 /* Search forward through the history list for the last string searched
268 for. If there is no saved search string, abort. */
269 int
270 rl_noninc_forward_search_again (count, key)
271 int count, key;
272 {
273 if (!noninc_search_string)
274 {
275 ding ();
276 return (-1);
277 }
278 noninc_dosearch (noninc_search_string, 1);
279 return 0;
280 }
281
282 /* Reverse search in the history list for the last string searched
283 for. If there is no saved search string, abort. */
284 int
285 rl_noninc_reverse_search_again (count, key)
286 int count, key;
287 {
288 if (!noninc_search_string)
289 {
290 ding ();
291 return (-1);
292 }
293 noninc_dosearch (noninc_search_string, -1);
294 return 0;
295 }
296
297 static int
298 rl_history_search_internal (count, direction)
299 int count, direction;
300 {
301 HIST_ENTRY *temp, *old_temp;
302 int line_len;
303
304 maybe_save_line ();
305
306 temp = old_temp = (HIST_ENTRY *)NULL;
307 while (count)
308 {
309 temp = (direction < 0) ? previous_history () : next_history ();
310 if (temp == 0)
311 break;
312 /* On an empty prefix, make this the same as previous-history. */
313 if (rl_point == 0)
314 {
315 count--;
316 continue;
317 }
318 if (STREQN (rl_line_buffer, temp->line, rl_point))
319 {
320 /* Don't find multiple instances of the same line. */
321 if (prev_line_found && STREQ (prev_line_found, temp->line))
322 continue;
323 if (direction < 0)
324 old_temp = temp;
325 prev_line_found = temp->line;
326 count--;
327 }
328 }
329
330 if (temp == 0)
331 {
332 if (direction < 0 && old_temp)
333 temp = old_temp;
334 else
335 {
336 maybe_unsave_line ();
337 ding ();
338 return 1;
339 }
340 }
341
342 line_len = strlen (temp->line);
343 if (line_len >= rl_line_buffer_len)
344 rl_extend_line_buffer (line_len);
345 strcpy (rl_line_buffer, temp->line);
346 rl_undo_list = (UNDO_LIST *)temp->data;
347 rl_end = line_len;
348 return 0;
349 }
350
351 /* Search forward in the history for the string of characters
352 from the start of the line to rl_point. This is a non-incremental
353 search. */
354 int
355 rl_history_search_forward (count, ignore)
356 int count, ignore;
357 {
358 if (count == 0)
359 return (0);
360 if (rl_last_func != rl_history_search_forward)
361 prev_line_found = (char *)NULL;
362 return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
363 }
364
365 /* Search backward through the history for the string of characters
366 from the start of the line to rl_point. This is a non-incremental
367 search. */
368 int
369 rl_history_search_backward (count, ignore)
370 int count, ignore;
371 {
372 if (count == 0)
373 return (0);
374 if (rl_last_func != rl_history_search_backward)
375 prev_line_found = (char *)NULL;
376 return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
377 }